什么是回测——以及什么是验证
回测是一次计算,验证是对这次计算做的假设检验。这篇讲清楚两者的区别、五步验证流水线各自在证明什么,以及每一步给出的数字到底能支撑多强的结论。
没有验证的回测,就是在噪声里拟合一条曲线。验证这一步,才告诉你这个回测是真东西还是幻觉。
在”漂亮”的回测上亏过钱的交易员,都跳过了验证这一步。净值曲线上的 Sharpe 看起来很美,样本外表现跟扔硬币差不多。模型本身通常没什么大毛病——它只是在自己拟合过的数据之外没有任何优势。
这篇文章的主线是一句反复出现的追问:你手上这个数字,能支撑多强的结论? 五步验证流水线的每一步,本质上都是在给同一个招牌数字打折扣,而知道每一步在扣什么、扣的理由是什么,比记住门槛值有用得多。
回测 ≠ 验证
这两个词经常被混着用,但完全不是一回事。
回测是机械操作。你拿着一个策略——入场规则、出场规则、仓位管理——把它套到历史价格数据上,模拟当时会发生哪些交易,算出一条收益曲线。输出是一个数字:Sharpe 比率、总收益、最大回撤。给定数据和规则,这个计算是确定的,重跑一遍结果一模一样。
验证是统计层面的事。回测告诉你”过去会发生什么”,验证告诉你”这个结果对未来有没有指导意义”。它是在检验”检验”本身。
换个说法:回测是一次计算,验证是对这次计算做假设检验——“我刚算出来的 2.1 的 Sharpe,是真有 edge 的证据,还是我把这堆特定数据拟合出来的?”
之所以要分这么清,是因为一个扎心的事实:在足够多的历史数据上测试足够多的策略,你总能挖出惊艳的 Sharpe,而它纯粹就是噪声。Harvey、Liu 和 Zhu(2016)估计过,金融学里发表出来的所谓”因子”,绝大多数大概率是假阳性。交易策略这里是完全同样的故事。你挖得够深,总会找到一个在历史样本上”有效”的策略——哪怕底层过程压根没有任何 edge。
回测回答”发生了什么?“,验证回答”我是不是有理由期待它再次发生?”。没有后者,前者就是娱乐。
五步验证流水线
Marcos López de Prado 的 Advances in Financial Machine Learning(AFML)给出了一套层层递进、把回测”管教”住的方法。顺序是有意义的:每一步都假设前一步已经过了,只处理前一步管不到的那一类偏差。
第一步:样本内拟合
这就是回测本身。你圈定一个训练窗口——比如 2010 到 2019——把策略的超参数都拟合到这段数据上。你可能试了 50 种动量阈值、RSI 截断点、均值回归的 z-score,最后挑一个训练集上看起来最漂亮的。
这一步是必要的,你总得有个法子把策略搭起来。但只要你开始从一堆变体里挑”最好的”那个,样本外信息就已经泄漏到你的选择里了。样本内 Sharpe 几乎永远是你实盘表现的上界。把它记成一个基线数字,别拿它当预测。
在 Arithmion 里,一次不带 walk-forward 配置的 run_backtest 给的就是这个东西:样本内表现统计。用它,但别信它——而且平台也不打算让你信它,下面第二步会讲原因。
第二步:Walk-Forward 样本外
这是最起码的诚实测试。在 上训练,在 上测试,然后向前滚动 重复。你得到的是一串样本外 Sharpe 估计,而不是单个数字。
它同时检验两件事。一是泛化能力:策略的 edge 能不能延续到未来,还是只拟合了你调参的那个特定窗口?二是自适应能力:实盘里你会随着新数据到来而重新训练,walk-forward 模拟的就是这个,包括滚动窗口带来的 regime 切换。
样本内 Sharpe 2.5 对应 walk-forward 0.9,这就要警惕了;样本内 2.0 对应 walk-forward 1.8,那策略多半是真的。这个比值——样本外除以样本内——本文统称保留率(有些资料把同一个比值叫”衰减比”,于是”衰减比 47%“和”衰减了 47%“变成两个相反的意思,读别人的报告时先确认口径)。它是你能算出的最有信息量的单个诊断量。
这一步在 Arithmion 上不是可选项。平台的统计验证器默认 require_oos: True,而且这个开关被钳制住了:你传进来的验证配置会逐项跟默认值比,数值项取更严的那个,require_oos 只要默认为真就关不掉。拿一个没跑过 walk-forward 的 run 去要判定,回答是固定的——No out-of-sample result present (required)。注意这句话说的是证据缺失,不是策略糟糕。
第三步:多重检验调整——Deflated Sharpe
就算过了 walk-forward,你那个招牌 Sharpe 还可能虚高,因为你试了很多策略、只看了表现最好的那个。Deflated Sharpe Ratio(DSR)修的就是这个:它把观测到的 Sharpe 跟”在所有被测策略真实 edge 均为零的原假设下,期望的最大 Sharpe”做比较,然后把结果报成一个概率。
走一遍数。假设你试了 50 个互相独立的策略,最好的那个在 5 年日频数据上年化 Sharpe 是 2.0。AFML 的期望最大值近似给出的年化基准大约是 SR* = 1.25(不是 0.7–0.9)。为了把计算统一在一个频率上,用日频 Sharpe:SR = 2.0/√252,SR* = 1.25/√252,T ≈ 1,260。在正态收益(偏度 0、峰度 3)下,DSR 统计量约为 z = 1.68,DSR = Φ(z) ≈ 0.953。
这里有一个最常见的误读值得单独点出来:DSR 是概率值,不是调整后的 Sharpe,也不是 edge 的估计。看到”DSR = 0.3”不要理解成”真实 Sharpe 大概 0.3”,它的意思是”这个 Sharpe 超过折减基准的概率只有三成”。两者是完全不同的量纲。
这一步之所以关键,是因为每个量化人都不止测过一个策略。不调整,就是在自己骗自己关于 edge 的大小。Arithmion 的统计验证器算的正是这个数,默认门槛 min_dsr: 0.95,而 n_trials 要你诚实上报——对验证器少报试验次数不是道德问题,是让这个数字失去意义。
第四步:回测过拟合概率(PBO)
换个问题。PBO 估计的是模型选择过程在组合对称交叉验证(CSCV)下过拟合的频率。做法是:对每个等半 CSCV 切分,选出样本内赢家,算该赢家在样本外的相对排名 ω,再数一数那些 ω < 0.5 的切分——也就是选出的赢家落在样本外中位数之下。
如果 PBO = 0.65,意思是 65% 的 CSCV 切分选出了一个样本外相对排名低于中位数的样本内赢家。这是”选择过程容易过拟合”的证据,不是”这个具体策略有 65% 概率是过拟合的”那种字面概率。顺带澄清一个常见混淆:CPCV 是一种相关的 purged 验证方法,但它不是用来定义 PBO 的那个流程。
低 PBO(比如低于 0.30)说明选出的赢家在跨切分时通常能排在样本外中位数之上;高 PBO(比如高于 0.50)说明选择过程经常失败。这是流水线里对研究流程本身要求最高的一关——它测的不是你的策略,是你挑策略的方式。
也正因为它测的是流程而不是产物,平台不替你跑它。Arithmion 的验证闸门覆盖第二步和第三步(样本外证据 + DSR);PBO 和 purged 交叉验证属于”你应该自己跑”的范畴。别把一份通过的验证判定误当成这两项也过了。
第五步:实盘模拟(Paper Trading)
最后一步,枯燥无趣。把策略挂到实盘数据上跑,不下真金白银:真实的成交、真实的滑点、真实的市场冲击,只是钱是假的。
它抓的是前四步在结构上抓不到的东西——那些只在”回测数据”和”实盘数据”之间的缝隙里出现的问题。信号来得够不够快、快到你来得及下单(延迟);实盘 feed 跟回测 feed 表现一致吗(数据漂移);你拿到的成交是不是符合预期(运营风险);策略的 edge 在资金规模变大时会不会衰减(容量漂移)。这四类问题的共同点是:它们在历史数据上根本不存在,所以再严谨的历史验证也检不出来。
如果六个月的 paper Sharpe 落在 walk-forward Sharpe 的 ±30% 之内,你可以开始上真钱了。如果 paper Sharpe 只有 walk-forward 的一半,那从回测到实盘中间一定有东西断了——策略本身可能没问题,但你还没把它度量对。
一个具体的例子:陷阱
看一个走完整套流水线的策略。假设有个标普 500 股票池上的动量策略:买去年赢家、卖去年输家,每月再平衡。
| 步骤 | 结果 | 判定 |
|---|---|---|
| 样本内拟合(2010–2019) | SR = 2.5 | 看起来有戏 |
| Walk-forward OOS(2015–2024) | SR = 0.9 | 保留率 = 36% |
| Deflated Sharpe(50 次试验) | DSR = 0.30 | 没过 0.95 的概率门槛 |
| CSCV 算出的 PBO | PBO = 0.65 | 选择过程大概率过拟合 |
| 实盘模拟(3 个月) | SR = 0.4 | 与偏弱的样本外证据一致 |
我们能下什么结论?Walk-forward 给了 0.9。DSR 是 0.30,低于 0.95 的门槛——这说明证据不足以打败”期望最大值”基准,它不是对真实 edge 大小的估计。PBO 0.65 意味着 65% 的 CSCV 切分选出的样本内赢家在样本外排名低于中位数。3 个月的 paper 得到 0.4,时间太短不足以下结论,但方向上跟偏弱的样本外证据是一致的。
诚实的解读是:现有证据支撑不了那个 2.5。手上能拿到的样本外点估计是 0.9,短期 paper 是 0.4,而 DSR 和 PBO 本身并不给出真实 edge 的量级。最后这 0.4 扣完手续费还赚不赚钱,取决于分配的资本和容量,这是另一道题。
这就是流水线在诚实地工作。幼稚的读法是”回测 Sharpe 2.5!上!”——这种读法会亏钱。
跳过验证的五个陷阱
这五个陷阱有一条共同的形状:它们都是在证据链的某一环停下,然后把停下的地方当成终点。
最经典的是只看样本内 Sharpe。你在训练数据上调出一个策略,看一眼图表,看到一条平滑的净值曲线,然后就停了。没有 walk-forward,你没有任何样本外证据;没有 DSR,你也完全没为那 30 个你没选上的变体做修正。
稍微进阶一点的是只跑了一次 walk-forward 就下结论。即便走了 walk-forward,如果你跑了很多次、只报告最好的那次 fold,照样会过拟合。至少要在 12 个滚动窗口上取平均,才能得到可信的样本外估计;而不同 fold 之间样本外 Sharpe 的标准差本身就是个诊断量——方差高就说明不稳定。
忘掉交易成本是第三个,而且它比看起来更常见。扣费前的 walk-forward Sharpe 1.5,扣完 20 bp 双边成本之后就不是 1.5 了。正确做法是重新算净收益流——例如 r_net,t = r_gross,t - 0.002 × turnover_t——再用 r_net 算 Sharpe;结果取决于换手率、波动率、以及成本的时序。同理,扣完 30 bp 双边成本的 walk-forward Sharpe 1.5,不重做这个净收益计算就没法读懂。一定要按现实的价差模拟成交,一定要建模市场冲击,一定要看看扣完成本之后策略还有没有 edge。
用了未来的数据最隐蔽。你用昨天的价格比算一个依赖今天收盘价的信号,而信号在收盘后才触发——你是在用你下单时并没有的数据做决策。这种偏差杀伤力极大,而一个不做检查的 backtester 完全看不出来。
幸存者偏差是最后一个:你的股票池里漏掉了已经退市的名字,回测于是把所有失败案例都忽略了。只用今天还存在的股票搭出来的回测带着一个正向偏差,而这个偏差有可能就是它全部 alpha 的来源。
一个回测由什么组成
一个回测有四个要素,它们不是同样容易做对的,任何一处错了整个结果就塌了。
数据是你要交易的资产的价格和成交量历史,最好做过拆股和分红调整,最好包含已退市的股票。关键要求是:它必须跟你实盘时拿到的数据对得上。如果回测用收盘价、而你会在中午下单,那成交假设就是错的;如果回测用 point-in-time 的基本面、而你的数据供应商悄悄把它们 backfill 了,你算出来的每一个基本面信号都是未来函数。
策略是入场规则、出场规则、仓位规则、资金分配规则。这里的每一个自由度都是一个可能过拟合的地方。如果你的策略有 12 个自由参数、而且你在同一份样本内数据上调了每一个,那这个回测在结构上就是过拟合的——不需要看结果就能下这个判断。
成交模型决定交易怎么成交、假设多少滑点、假设多少市场冲击。回测里自欺欺人的地方主要就在这里。现实中的日内策略在流动性好的 ETF 上假设 1–5 bp 滑点、在小票上假设 10–50 bp,而大多数 backtester 假设 0 bp。你报出来的那个 Sharpe,量的就是”现实”和”理想化”之间的距离。
成本模型管佣金、交易所费用、融资、融券成本。成本就是”策略有没有 edge”和”扣完费之后还有没有 edge”之间的差别。除了建模,还要做敏感性测试:策略在成本上亏多少 bp,edge 才会消失?
Arithmion 把这四件事拆在配置的不同段落里,成本那一段的默认值是刻意保守的——每边 0.1% 佣金加 5 bp 滑点,对不少市场偏贵。这是特性不是 bug:回测成本宁可偏高,让”扣完成本还活着”的策略更可信。你做的市场跟这个口径差得远时,改成你自己的数,别用默认值糊弄过去——大多数看起来还行的回测结果,过不了的正是成本敏感性这一关,因为策略当初就是在 0 bp 假设下调出来的。
“样本外”到底是什么意思
“样本外”这个词被用得很随便。它其实有四个层级,信息量差得很远。
最弱的一层是 held-out 窗口:数据 50/50(或 70/30)切分,一半训练一半测试。它只能抓一种过拟合,抓不到 regime 变化、多重检验、以及数据 pipeline 里的未来函数。
往上一层是 walk-forward:在 上训练、 上测试、滚动前进。它比 held-out 强在有多个样本外估计,而且测了自适应性,但依然抓不到参数选择偏差——因为选参数这件事发生在整条 walk 之外。
第三层是 purged + embargo 的交叉验证。CPCV(Combinatorial Purged Cross-Validation,AFML §12.4)在多组 train/test 切分上测试,并且正确地 purge 掉标签重叠的训练观测。它能抓 walk-forward 漏掉的过拟合,原因是它的回测数量多得多、而且切分之间的重叠方式各不相同。
最强的一层是 out-of-time, out-of-platform:一份你从没碰过的独立数据集,可能来自不同供应商或不同市场。这是唯一一种能抓某些模型构建偏差的测试。如果你的策略在美股上过了第三层、而你想上新兴市场,你需要在新兴市场做一次第四层测试——策略必须对 regime 差异有韧性,而这件事只有换个市场才能证明。
一个”经过验证的”回测至少要到第二层。一个严肃策略要宣称自己有 edge,得有第三层或更高的支持。而大部分已发表的回测声明,停在第一层。
流水线说”不”的时候
大多数走到你面前的策略都会在流水线某处翻车,而翻车的模式都很有特征,基本能直接反推出病因。
Walk-forward Sharpe 塌到 0,通常意味着样本内拟合用到了未来的数据,或者你的训练窗口没跨够多个 regime。DSR 低于 0.95,意味着试验次数太多、挑出来的是被美化过的候选,你的证据低于一个常见的 5% 显著水平门槛。PBO 高于 0.5,意味着你的选择流程比不过拟合更可能过拟合,实盘会让人失望。而 paper Sharpe 偏离 walk-forward Sharpe,通常指向运营层面的问题(延迟、成交、成本),或者回测数据里有未来函数而实盘数据里没有。
任何单独一步给出”不”,就足够让你停下来。忽略那个”不”,等于选择跳过验证。亏钱的量化人大多数都这么干——他们听到了”不”,但因为样本内 Sharpe 看起来太好了,所以强行覆盖掉。
纪律就是把流水线当裁判。裁判不在乎你有多激动,裁判只看证据。
走完五步之后你有什么
流水线是保守的,这正是它的意义。在一个 Sharpe 2.5 的回测之后立刻想开始交易,是人之常情;流水线强制你走完五道过滤,每一步都可能把招牌数字往下压。
代价是你会发现大多数策略在这里就挂了,而这是设计如此:流水线筛的是”真有效”,不是”看起来好”。回报是,走完之后你手上不再是一个数字,而是四条互不重叠的证据——一个样本外 Sharpe 估计、一个针对多重检验的 DSR 概率、一个关于选择流程过拟合倾向的估计、以及一段实盘模拟给出的区间。四条都说”edge 存在”,你可以上资本;任何一条是坏的,你收手。
回测本身是必要的:你没法验证一个还没搭出来的策略,而不做回测也搭不出策略。但回测不是答案,验证才让回测表现变得可信。每个在漂亮回测上亏过钱的量化人,教的都是同一课——他们相信了第一步,然后跳过了第二到第五步。
参考文献
- López de Prado, M., Advances in Financial Machine Learning, Chs. 11–12,§11.6 用于 PBO,§12.4 用于 CPCV,§14.7.3 用于 DSR。Wiley, 2018. ISBN: 978-1-119-48208-6.
- Chan, E., Quantitative Trading: How to Build Your Own Algorithmic Trading Business, Ch. 3. Wiley, 2009. ISBN: 978-0-470-28488-9.
- Bailey, D., López de Prado, M., “The Deflated Sharpe Ratio,” Journal of Portfolio Management, 2014.
- Harvey, C., Liu, Y., Zhu, H., ”… and the Cross-Section of Expected Returns,” Review of Financial Studies, 2016.
- Aronson, D., Evidence-Based Technical Analysis, Ch. 8. Wiley, 2007. ISBN: 978-0-470-00874-4.