跳到正文

Walk-Forward 分析

Walk-forward 是回测时间序列策略最起码的诚实做法:在过去数据上训练,在下一段上测试,然后向前滚动。它给你的不是一个数字,是一个分布——这才是它值钱的地方。

第 7 篇 · 共 8 篇 约 12 分钟

Walk-forward 不是什么花哨的技术。它是对实盘交易最起码的诚实模拟:在过去数据上训练,预测下一段,向前滚动。它也是量化流程里最容易被跳过的一步——因为它简单到不像一道关卡,而且它经常给出你不想听的答案。

不走 walk-forward 的回测就是曲线拟合。诚实走完一遍的 walk-forward,是除了掏真金白银之外你最接近实盘的东西。如果你在上真钱之前只肯做一步验证,就做这一步。

三个参数和一条流程

Walk-forward 由三个参数定义。训练窗口 TT 是你用来拟合的历史数据量,常见是 3、5 或 10 年。测试窗口 τ\tau 是你往前预测多远,常见是 1 个月、3 个月或 1 年。步长是每次迭代前进多少,通常等于 τ\tau(滚动,测试段不重叠),或者取它的一个分数(重叠)。

流程本身机械得可以直接写成代码:

  1. 在 [t0−T,t0][t_0 - T, t_0] 上的数据拟合你的策略。
  2. 在 [t0,t0+τ][t_0, t_0 + \tau] 上生成样本外收益。
  3. 记录那个窗口的样本外表现统计。
  4. 前进 τ\tau(或步长),重新训练,重新测试。
  5. 重复,直到数据用完。
  6. 把各段样本外收益串成一条时间序列。
  7. 在串起来的序列上算表现统计。

输出是一条由很多小 fold 拼起来的样本外净值曲线。在任何一个 fold 里,策略都没接触过它被测试的那段数据。

它到底证明了什么

Walk-forward 的机制跟实盘部署是同构的,这是它的第一层价值。实盘里,你在历史数据上拟合、下单、然后等结果;在任何一个时间点上,你的模型最后一次拟合用的都是那个时刻之前已有的数据,而你做决策时还没有的那部分数据,正好就是测试 fold 里的数据。Walk-forward 流程逐字复刻了这件事——每一次预测用的模型,都是没看过那段预测数据的。

第二层价值是它测自适应性。在 2015–2020 上训练的模型,交易方式跟 2020–2025 上训练的不一样。这种漂移在一次性的 80/20 切分里根本看不见,而 walk-forward 每滚动一步就重训一次,漂移被逼着显形。它回答的是:当下一个 regime 来临、你不得不重新训练时,这个策略还站得住吗?

第三层价值最容易被低估,也是我认为最重要的:它给你的不是一个数字,是一个分布。一次切分只给一个样本外表现数字;walk-forward 给几十个,于是你手里有一个经验分布 SR^1,SR^2,...,SR^N\widehat{SR}_1, \widehat{SR}_2, ..., \widehat{SR}_N,可以算均值、标准差、命中率和置信区间。单个样本外估计的标准误就是这些 walk-forward Sharpe 的标准差除以 N\sqrt{N}。

这个区别决定了你能说什么话。OOS Sharpe 1.0、跨 60 个月度 fold 标准差 0.4,这是一个可信的估计;同样是 1.0、标准差 0.1,是一个非常可信的估计;而 1.0 但只有 1 个 fold,你有的只是一个数字,连它稳不稳定都不知道。本文后面所有的判断标准,都是从这个”有多少个 fold”的问题上长出来的。

三种切法

同样叫 walk-forward,窗口怎么滚动决定了它在测什么。

滚动窗口是标准做法:在 [t−T,t][t - T, t] 上训练,在 [t,t+τ][t, t + \tau] 上测试,训练窗口长度固定为 TT,前进时丢掉最老的数据、加上最新的。这让策略偏向近期数据,短期信号通常没问题,但如果你的参数估计器需要长历史才稳,它就吃亏。

一个典型配置是 T=2520T = 2520 天(10 年)、τ=21\tau = 21 天(1 个月)、步长 21。这里有一处新手常算错的账:fold 数不是 Ttotal/21T_{total}/21,而是 (Ttotal−T)/21(T_{total} - T)/21——第一个测试段要等训练窗口填满才开始。所以 20 年数据配 10 年训练窗口,给的是约 120 个月度样本外估计,不是 240 个。做分布推断这已经够了,但别把它记成两倍。

锚定(扩张窗口)换了个思路:起点 t0t_0 固定,窗口随时间往右扩张,你始终保留全部可用历史。这更保守,策略每一步都能用上所有信息;代价是时间序列开头计算很贵(训练集大、产出的数据点少),而且对最近的 regime 变化反应慢。因子投资和 regime 识别这类受益于长历史上下文的策略适合它,短周期信号则不适合。配置形如 t0=2000t_0 = 2000-0101-0101、τ=21\tau = 21、步长 21。

锚定有个弱点:起点选得不好,样本外估计跟着差。多锚定就是冲这个来的——在几个不同起点(比如 2005、2010、2015)各跑一遍完整的 walk-forward,再对样本外表现估计取平均,把结论对起点日期的敏感性摊掉。它比单次锚定稳健,但计算量成倍上去,所以它的定位是稳健性检查,不是主跑。

大多数策略默认用滚动。锚定留给”参数估计器在短训练窗口下不稳”的情形。多锚定在你怀疑结论被某个特定起点带偏时再跑。

一个具体的例子

假设你在美股上测试一个 12 个月动量策略。数据从 2004-01-01 到 2023-12-31 共 20 年,用 5 年(1260 天)训练、3 个月(63 天)测试、每 3 个月前进一步。这给你大致 ⌊(20−5)/0.25⌋=60\lfloor (20 - 5)/0.25 \rfloor = 60 步——同样地,第一个测试 fold 要等五年训练窗口用完之后才开始。每个 fold 是 63 个交易日的样本外,60 个 fold 串起来约 3,780 个交易日,也就是初始训练期之后的 15 年样本外数据。

一组示意结果:平均 OOS Sharpe 0.7,跨 fold 的标准差 0.45,命中率 65%(即 65% 的 fold Sharpe 为正),最差的一个 fold Sharpe −1.2(某年行情不好),最好的一个 2.1,15 年样本外期间的累计收益 +128%。

诚实的解读是这样的。0.7 的均值配 0.45 的跨 fold 标准差,在 60 个 fold 上算合理——标准误约 0.45/60≈0.0580.45/\sqrt{60} \approx 0.058,意味着这个 0.7 离零足够远。65% 的命中率说明有正向 edge,但谈不上压倒性:三分之一的季度是亏的,你得有心理准备。最差 fold 的 −1.2 说明尾部风险是实打实的,不是理论担忧。

拿它跟样本内比更有意思。同一个策略的样本内 Sharpe 可能是 1.5,样本外 0.7,保留率 47%(样本外除以样本内)。这个数对动量策略来说很典型,也很诚实。反过来,如果样本外是 1.4、保留率 93%,那不是好消息,是该去查未来函数的信号——样本外表现几乎不掉,通常意味着”样本外”根本没有真的隔离开。

顺带把术语钉死,因为这里的中文译法经常互相打架:本文说的保留率指 OOS/IS 这个比值,值越高越好;有些资料把同一个比值叫”衰减比”,于是”衰减比 47%“和”衰减了 47%“变成两个相反的意思。下文一律用保留率。

Walk-Forward 抓不到什么

Walk-forward 抓的是时间维度上的过拟合,它对另外三类问题完全免疫。

如果你是靠试 T∈{3,5,10}T \in \{3, 5, 10\} 然后报最好的那个来选训练窗口长度的,你已经对 TT 过拟合了,而 walk-forward 一点都看不出来——它只会忠实地把你选中的那个 TT 跑得很好看。唯一的解法是纪律:看数据之前先定好 TT。

如果底层信号里有未来函数,walk-forward 会原样继承这种偏差。每个 fold 的样本外预测都被同等地夸大,曲线依然漂亮,而你会在 paper trading 阶段第一次看到真相。

还有一层更微妙:N=60N = 60 个 fold 本身就是 60 次隐式的假设检验。这种条件下的期望最大 Sharpe 会把招牌数字吹起来,而这个偏差要用 Deflated Sharpe 单独调整,walk-forward 自己修不了。

所以 walk-forward 必要但不充分。参数选择要靠 purged 交叉验证(AFML 里的 CPCV),多重检验要靠 Deflated Sharpe,跟随机的经验对比要靠 Reality Check 或 SPA 检验,最后一道是实盘 paper trading。

实现时最常见的五种自欺

在样本外上调超参。 正确的顺序只有两步:先凭判断(不是凭数据)选定训练、测试、步长,然后直接跑。错误的顺序是试几组 TT 和 τ\tau、挑样本外 Sharpe 最高的那组、然后报告——它长得像 walk-forward,给出的结果比单纯的样本内拟合还糟,因为你把样本外也变成了拟合目标。你可以在一份 holdout 上做预备测试,但一旦定下 TT、τ\tau、步长,生产跑就别再动它们。

用样本外挑策略。 上一条的加强版:在同一批 walk-forward 样本外数据上测很多策略,报最好的那个。这又是数据挖掘。Walk-forward 的样本外表现只是总体里的一个样本,一旦你基于它挑策略,选择偏差就进来了。补救办法是接受 walk-forward 只是策略选择的一部分,对挑出来的候选再上 Deflated Sharpe 和 PBO。

碰了测试窗口。 你每看一眼 test fold 然后想”这儿我该调一下”,信息就泄漏了一次;一旦真调了,这个 fold 就不再是样本外的。如果必须调,从更早的 train fold 重新开始整条 walk,把调整应用到重训后的模型上,而不是把调整塞回 test fold。这件事在研究流程里很难靠自觉管住,所以最好用一份研究日志:每碰一次 test fold 就记一笔,同一个 fold 碰过两次以上,那次 walk 作废重跑。

忘了交易成本。 双边 20 bp 成本下的 walk-forward Sharpe 1.5 是一个数,双边 30 bp 下的 1.5 是另一个数——前提是你真把成本建进模型了。大多数 walk-forward 实现要么忽略成本,要么套一个固定 bp 假设,然后在成本敏感性上翻车。

只报均值,不报标准误。 你有 60 个样本外 Sharpe 估计,均值 0.7,均值的标准误是 σ/60\sigma/\sqrt{60}。σ=0.45\sigma = 0.45 时标准误约 0.45/60≈0.0580.45/\sqrt{60} \approx 0.058,于是平均样本外 Sharpe 是 0.70±0.1160.70 \pm 0.116(95% 置信区间)。大多数报告到”均值 0.7”就停了,而这一步恰恰是判断能不能下结论的关键:95% CI 是 [0.6,0.8][0.6, 0.8],你能确定策略跑赢了零;95% CI 是 [−0.2,1.6][-0.2, 1.6],你什么都判断不了。同样的均值,两个完全不同的结论,差别只在标准误。

数字怎么读

上面那几个诊断量各有一个大致的读法,值得说清楚为什么是那个门槛,而不是背下来。

保留率(样本外除以样本内)在 50%–70% 之间,是诚实策略的典型区间——参数有点不稳定,但 edge 是真的。到 70%–90%,说明策略在样本外几乎没掉多少,这是有力证据。超过 90% 反而要查未来函数或挑窗口,理由前面说过了:真正隔离干净的样本外,不太可能几乎不掉。低于 30% 就别上了,那基本是样本内过拟合的形状。

命中率是样本外 Sharpe 为正的 fold 占比。高于 55% 大概率有正向 edge;45%–55% 是边缘地带,跟随机区分不开;低于 45% 说明是负 edge 或者没有 edge。这个指标的好处是它对单个大赢 fold 不敏感——一次暴利拉不高命中率,只能拉高均值,两个指标一起看能识别出”靠一次行情撑起来的策略”。

跨 fold 的 Sharpe 标准差量的是稳定性。σ<0.4\sigma < 0.4 说明表现一致;σ>1.0\sigma > 1.0 说明策略被 regime 切换来回抽,即便均值好看,你也很难在实盘上扛过它最差的那几段。而最差 fold 的 Sharpe 直接对应”你得咽下的最难受的一段”:高于 −0.5 通常扛得住,−0.5 到 −1.0 需要复查(很多时候能对上一次已知危机),低于 −1.0 就是在没有更强风控之前别上实盘的信号。

这些都是经验法则,不是判据。真正的部署决策还要看你的风险偏好、资本配置和容量。

为什么大家还是跳过它

部署前没做过 walk-forward 验证的量化策略数量大得吓人,理由有三个,没有一个光彩。

时间压力最常见:新 idea 冒出来,你想赶紧测,而 walk-forward 好好跑一遍要几小时到几天,于是捷径就成了做一次回测然后说”够了”。计算成本是第二个:20 年数据上跑一个日内策略的 100-fold walk-forward,把现实成本建模进去之后可能要好几个小时,基础设施有限时你能对日频策略跑、跑不了 tick 级策略——这种情况下诚实的做法是在子样本上估同样的流程,再对小样本做统计修正,而不是干脆不跑。

第三个理由最难承认:确认偏差。一旦你相信自己的策略有效,任何额外测试都是不受欢迎的,因为 walk-forward 可能会告诉你它不工作。跳过它就能保住你的信念——这也是它代价最大的地方,大多数失败的实盘部署源头都在这儿。

修法只能是结构性的:把 walk-forward 嵌进部署流水线,而不是留成一个可选检查。Arithmion 就是照这个思路做的。平台的统计验证器默认带 require_oos: True,而且这个开关被钳制住了——调用方传进来的验证配置会逐项跟默认值比,数值项取更严的那个,require_oos 只要默认为真就关不掉。你拿一个没跑过 walk-forward 的 run 去要判定,得到的回答是固定的:

No out-of-sample result present (required)

注意这句话说的是证据缺失,不是策略糟糕。补证据的入口也是明确的——回测时带上 walk-forward 配置:

walk_forward = {
    "enabled": True,
    "is_months": 12,     # 样本内窗口
    "oos_months": 3,     # 样本外窗口
    "step_months": 3,    # 每次前进
    "mode": "true_oos",
}

提示词

给出 Arithmion run_backtest 的 walk-forward 配置:12 个月训练、3 个月样本外、每 3 个月滚动一次。

窗口怎么切在契约层里是可读代码,不是黑箱。apexquant.core.training.rolling.rolling_windows(n, train_size=..., test_size=..., step=..., expanding=...) 返回一串 Window,每个是 train_start/train_end/test_start/test_end 四个半开区间下标,且 test_start == train_end。expanding=False 就是上面说的滚动窗口,expanding=True 把每个窗口的 train_start 锚在 0——本文的变体一和变体二,在这里就是一个布尔量的差别。

最后提醒一句流程纪律:别搞”我跑过一遍 walk-forward、结果不好、所以这次跳过”这种工作流。跑,看结果,做决策。

它在整条验证链里的位置

生产环境的研究里,walk-forward 是链条中的一环,不是全部。标准顺序是:

  1. 样本内 backtest 做初始开发。
  2. Walk-forward 测自适应能力和样本外可信度。
  3. Purged combinatorial CV(CPCV) 测参数稳健性。
  4. Deflated Sharpe Ratio 做多重检验修正。
  5. White Reality Check 或 SPA 跟随机做经验对比。
  6. PBO 测模型选择过程的过拟合倾向。
  7. 实盘 paper trading 做最后确认。

过了 1–3、部分过了 4–6 的策略是”有意思、未证实”。全过的是”可以谨慎部署”。全过之后又 paper trading 跑了六个月表现稳定的,才是”可以扩规模”。

这个链条在平台上不是全自动的。Arithmion 的验证闸门管的是第 2 和第 4 步:walk-forward 产生样本外证据,统计验证器算 deflated / probabilistic Sharpe 并给判定(默认 min_dsr: 0.95)。第 3 和第 6 步——purged 交叉验证和 PBO——属于”你应该自己跑”的范畴,引擎不替你跑,别把”验证通过”误当成这两项也过了。

流程也不必是线性的。研究期间在 walk-forward 和调参之间来回循环是正常的;策略准备上线时就不行了。那时候停掉循环、冻结策略、跑完整条链。

如果你手上的策略没有一份 walk-forward 报告,你没有验证过它,你只是回测过它。而即便有了这份报告,它能告诉你的也只是参数稳健性合不合理——它不告诉你策略是不是在更宽的假设空间里被过拟合了,不告诉你收益里有没有未来函数,也不告诉你策略有没有容量。同时扛过 walk-forward、DSR、PBO 和 SPA 四关的策略很稀有,而稀有正是它值得部署的原因。

参考文献

  • Pardo, R., Design, Testing, and Optimization of Trading Systems, Ch. 7. Wiley, 2008. ISBN: 978-0-470-12229-2.
  • López de Prado, M., Advances in Financial Machine Learning, §12.4 (Combinatorial Purged Cross-Validation). 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., Borwein, J., López de Prado, M., Zhu, Q., “The Probability of Backtest Overfitting,” Journal of Computational Finance, 2017.
  • Aronson, D., Evidence-Based Technical Analysis, Ch. 6 (Data-Mining Bias: The Fool’s Gold). Wiley, 2007. ISBN: 978-0-470-00874-4.
  • Hyndman, R., Athanasopoulos, G., Forecasting: Principles and Practice, Ch. 3 (cross-validation for time series). OTexts, 2018.