主观判断最大的问题,是选择性记忆——亏了觉得无关紧要,赚了牢牢记住。回测的价值不是"证明你很牛",而是在数据面前撕掉你的过度自信。但 90% 的散户量化尝试都死在了同样的六个坑里:未来函数、幸存者偏差、过度拟合、忽略交易成本、数据窥探、复权方式错误。
回测不是"策略赚钱能力的证明",而是"策略是否经得起数据拷问的压力测试"。一条健康的回测曲线要同时满足:参数 ≤ 5 个、跨周期验证、扣除全部交易成本、最大回撤 < 20%、夏普比率 > 1.5。做不到这五条的策略,无论看着多么漂亮,都只是未来函数 + 幸存者偏差 + 过度拟合合谋制造的虚假幻觉。
你有没有这样的体验:账户上个月明明赚了 8000 块,你却觉得"好像没赚多少";可上上个月亏了 2000 块,你却记得清清楚楚,连哪只票、哪一天买的都能复述。这不是记忆力问题,是人类大脑天然的选择性记忆偏差。
这种偏差在投资里的表现非常一致:
量化回测的价值,就是让冷冰冰的数据替代你的记忆。它能在几秒钟之内回答三个核心问题:
回测解决的不是"选哪个策略"的问题,而是"在你以为有效的策略里,先把不靠谱的快速剔除掉"的问题。一个无法在历史数据里站住脚的策略,到了实盘一定死得更难看——因为实盘还有滑点、情绪、黑天鹅三个回测里都没出现的额外打击。
但要小心:回测同时也是一个最容易自欺欺人的工具。用得不对,它会让你比主观判断更危险——因为你会在虚假的安全感里加大注码。我们接着看那 6 大致命陷阱。
这 6 个坑,90% 的初学者都会全部踩一遍。它们不是技术 bug,而是认知陷阱——你越聪明,越容易踩得深。下面一个一个拆。
这是回测里最常见、也最隐蔽的错误:在决策时偷看了还没发生的数据。
| 错误做法 | 为什么错 | 正确做法 |
|---|---|---|
| 用当日收盘价算信号 | 收盘价 15:00 才确定,你不可能在当天买入 | 次日开盘买入 |
| 用当日最高/最低价决定买卖 | 日内的高低点是事后才知道的 | 次日开盘价成交 |
| 回看 20 天后才公告的财报 | 公告日之后你才能看到 | 按公告日 T+1 决策 |
未来函数会让你的回测曲线看起来无比漂亮——但每漂亮一分,实盘就会难看十分。原因很简单:实盘里你永远拿不到还没发生的数据,而回测里你偷看了,结果差距就是几十个百分点。
用今天还活着的成分股,去回测过去 10 年——这等于自动忽略了所有已经退市的股票。而退市的票里恰恰藏着最多的暴跌、停牌、归零。
当你用 50 个参数 + 1000 只股票 + 10 年日线 去"找规律",你几乎一定能在历史数据里"挖"出一个年化 80% 的"圣杯"。但这个圣杯只对过去有效,对未来完全无效。
正确做法只有两条:参数尽量少(< 5 个),样本外验证(Out-of-Sample Testing)。比如用 2010—2018 训练,用 2019—2024 验证,这是最朴素但最有效的方法。
这是新手回测里最普遍、最容易让人自我感觉良好的陷阱。一组直观数字:
听起来不多?算给你看:
高频策略忽略交易成本 = 稳亏不赚的死亡螺旋。任何回测都必须扣除:印花税 0.05%(卖出单边)+ 佣金万 2.5(双边)+ 滑点至少 0.1%。
在同一份历史数据上反复测试、反复调参、反复"找规律"——哪怕一开始没有规律,你测试 1000 次也能凑巧出 50 个"看似有效"的策略。这就是数据窥探。
A 股有除权除息,需要对历史价格做调整。但复权方式选错,会直接污染你的回测:
| 复权方式 | 特点 | 使用场景 |
|---|---|---|
| 不复权 | 原始价格,含跳空缺口 | 仅用于查看真实历史成交 |
| 前复权 | 以最新价为基准回溯调整 | 实盘看盘(推荐) |
| 后复权 | 保持早期数据连续性 | 回测专用(推荐) |
如果用前复权做回测,早期数据会随着每次分红送股被重新调整,长期看价格曲线会出现不真实的"塌陷"。回测用后复权,实盘用前复权,这是不可违反的铁律。
一个完整的回测框架,本质上由四层组成:数据层 → 信号层 → 持仓层 → 业绩评估。下面分别拆解每一层的关键设计要点。
回测结果的可信度,80% 取决于数据质量。数据层要解决三件事:
缺失复权因子的回测都是耍流氓。不复权 ≠ 真实价格,会导致分红送股后的跳空被误判为"暴跌信号"。这一点几乎是 90% 散户回测犯的第一个错。
信号层负责把"我觉得要涨"翻译成机器能执行的规则。常见三类信号:
| 类型 | 典型例子 | 说明 |
|---|---|---|
| 阈值型 | MA5 > MA20 买入 | 规则最简单、最容易验证 |
| 形态型 | 早晨之星、MACD 金叉 | 多条件组合,过拟合高发区 |
| 组合型 | 量价共振 + 趋势 + 估值 | 多因子打分,参数容易失控 |
无论哪种信号,生成时机必须是"当日收盘 + 第二日开盘"或者更晚。这条规则再强调一次,因为它直接对应"未来函数"陷阱 1。
信号告诉你买什么,持仓层决定买多少。健康的资金分配规则:
回测结束不代表结束——评估才是策略能否上实盘的最后一关。下面是 7 个核心指标的"健康值"参考:
| 指标 | 含义 | 健康值 |
|---|---|---|
| 年化收益 | 复合年化收益率 | > 15% |
| 最大回撤 | 从峰值到谷底的最大跌幅 | < 20% |
| 夏普比率 | (收益 − 无风险)/ 波动率 | > 1.5 |
| 卡玛比率 | 年化收益 / 最大回撤 | > 1.0 |
| 胜率 | 盈利交易占比 | > 50% |
| 盈亏比 | 平均盈利 / 平均亏损 | > 1.5 |
| 换手率 | 资金周转速度 | 越低越好 |
注意:年化 15% 听起来不高,但叠加最大回撤 < 20%、夏普 > 1.5这两个约束条件,能同时满足的策略在 A 股长期看已经是 TOP 5% 的水平。任何看着年化 50%+ 的策略,几乎都可以判定为存在陷阱 1—3 中的某一个。
Python 是量化回测的事实标准。下面按"数据获取 → 回测框架"两个维度推荐工具,并给出一段可直接运行的双均线示例。
| 工具 | 费用 | 数据范围 | 适合人群 |
|---|---|---|---|
| akshare | 完全免费 | A 股 / 港股 / 美股 / 基金 / 期货 | 新手首选,无注册门槛 |
| baostock | 完全免费 | A 股证券数据齐全 | 需要完整复权因子的用户 |
| tushare pro | 积分制(基础免费) | A 股全量数据 | 需要稳定高频数据的进阶用户 |
| wind / iFinD | 机构付费 | 全市场 + 宏观 + 衍生数据 | 专业机构 / 量化团队 |
| 框架 | 特点 | 适合场景 |
|---|---|---|
| backtrader | 经典回测框架,社区庞大 | 事件驱动策略、多标的组合 |
| vectorbt | 向量化回测,性能极强 | 参数扫描 / 大规模回测 |
| qstock | 小而美,开箱即用 | 轻量级个人策略验证 |
| zipline / quantstats | 专业量化平台级 | 研究型 / 机构级回测 |
下面是一段可直接复制运行的最小回测示例,用 akshare 拉数据、用 pandas 做双均线策略、用 shift(1) 避免未来函数:
import pandas as pd import akshare as ak # 1. 获取数据(后复权,避免陷阱 6) df = ak.stock_zh_a_hist(symbol="000001", period="daily", adjust="hfq") # 2. 计算均线 df['MA5'] = df['收盘'].rolling(5).mean() df['MA20'] = df['收盘'].rolling(20).mean() # 3. 生成信号(金叉买入 / 死叉卖出) df['signal'] = 0 df.loc[df['MA5'] > df['MA20'], 'signal'] = 1 df.loc[df['MA5'] < df['MA20'], 'signal'] = -1 # 4. 计算收益(shift(1) 避免未来函数,对应陷阱 1) df['ret'] = df['收盘'].pct_change() df['strategy_ret'] = df['signal'].shift(1) * df['ret'] # 5. 评估业绩(参考 7 个健康指标) annual_ret = df['strategy_ret'].mean() * 252 # 注:上面算的是简单平均年化(单利近似),复合年化要用 (1+ret).prod()**(252/n) - 1 nav = (1 + df['strategy_ret']).cumprod() peak = nav.cummax() max_dd = ((nav - peak) / peak).min() # 注:原代码用 cumsum() 的减法算的是"日收益累加曲线"与峰值之差,量纲错误 print(f"年化收益: {annual_ret:.2%}, 最大回撤: {max_dd:.2%}")
这段代码 30 行不到,但已经内置了所有"防陷阱机制":后复权数据、shift(1) 防止未来函数、滚动计算、收益序列、最大回撤。这是你能写出的最干净的最小回测原型。先在这个基础上跑通,再去套 backtrader 或 vectorbt 才有意义。
一份诚实的回测报告,比一份漂亮的回测报告有价值 100 倍。下面先看回测报告的 5 大禁忌——任何一份报告犯了其中之一,请直接判定为不可信。
① 只展示胜率(隐藏回撤) · ② 只展示最好年份(隐藏最差年份) · ③ 只展示最优参数(隐藏参数敏感性) · ④ 没有交易次数(10 次和 1000 次完全是两回事) · ⑤ 没有跨周期验证(只在牛市中跑过不算数)。
| 误区 | 真相 |
|---|---|
| 回测赚钱 = 实盘赚钱 | 滑点 + 心理因素 + 流动性,通常会让收益缩水 30%—60% |
| 策略越复杂越好 | 5 个参数 > 50 个参数,简单即正义 |
| 胜率高 = 策略好 | 盈亏比同样关键,胜率 40% + 盈亏比 3 的策略远胜胜率 80% + 盈亏比 0.5 |