Skip to content

9.8 Walk-forward 滚动训练测试入门

课前导读

本节目标

学完能解决什么困惑:为什么一次完整回测不够,还要把历史切成多轮“先训练、再考试”。

适合谁学:已经理解回测指标、成本、参数扫描,并希望降低过拟合风险的读者。

难度:中级。

用时:约 45 分钟。

上一节我们知道,参数不能只看一个最高点。

但即使找到了看起来稳定的参数平台,也还不能马上放心。

因为整段历史回测可能仍然把未来的信息混进了过去的选择。

Walk-forward,就是把历史拆成一段段时间。

每一轮都先用过去资料练习,再用随后一段资料考试。

它的核心纪律是:不能用未来调过去。


知识正文

1. 类比:先练习再考试,多轮滚动

想象一个学生准备考试。

他不能先看完整套期末答案,再回头说自己“平时训练很有效”。

合理做法是:先用前几章内容练习,然后做一套没见过的小测。

做完后,再把新学到的内容加入训练范围,继续准备下一次小测。

Walk-forward 的思路就是这样。

每一轮都有明确的训练期和测试期。

训练期用来选择参数、检查规则和确定策略版本。

测试期用来模拟“策略发布后”的真实表现。

如果策略在多轮测试期都没有完全失控,我们才更有理由相信它不是只会背历史答案。

关键直觉

回测不是让策略参加一场已经知道答案的大考,而是让它经历多轮没见过的小考。

2. 术语:训练期、测试期、滚动窗口

训练期,就是允许你研究、调参、筛选规则的历史区间。

在训练期里,你可以做参数扫描,可以比较指标,也可以决定某个策略版本是否保留。

测试期,就是训练完成后,不再改规则,直接把策略放到下一段历史上检查。

测试期越像未来,越能暴露策略离开训练样本后的真实压力。

Walk-forward,常翻译为滚动前推验证。

它不是一次切分,而是多次重复“训练、测试、向前移动”的流程。

滚动窗口,指每次训练只使用最近一段固定长度的历史。

例如用过去 2 年训练,用接下来 6 个月测试,然后整体向前滚动 6 个月。

扩展窗口,指训练期从早期开始,随着时间不断变长。

例如先用 2018 到 2019 年训练,测试 2020 年上半年。

下一轮用 2018 到 2020 年上半年训练,测试 2020 年下半年。

两种方法没有绝对高低。

滚动窗口更强调近期市场状态。

扩展窗口更强调积累更多样本。

新手先理解纪律:测试期不能参与训练期的选择。

3. 为什么普通回测还不够

一段 2018 到 2024 年的完整回测,看起来很完整。

但如果你用这整段历史选出了参数,再说策略在 2018 到 2024 年表现很好,就存在问题。

因为 2024 年的信息也参与了你对 2018 年规则的选择。

这在现实中不可能发生。

站在 2018 年,你不知道 2024 年会发生什么。

站在 2020 年,你也不知道后面几年某个风格会不会突然失效。

Walk-forward 把这件事强制写进流程。

每一轮都要求你只用当时以前的数据做决定。

然后用当时之后的一小段数据检验。

4. A 股案例:均线参数的滚动验证

假设我们研究一个简单的 A 股趋势过滤策略。

股票池是流动性较好的沪深主板样本。

规则是:收盘价站上 N 日均线后观察买入,跌破 N 日均线后卖出。

交易成本包含佣金、印花税、过户费和滑点。

我们准备在训练期里从 15、20、25、30 四个均线参数里选择一个。

然后在测试期里固定使用这个参数。

轮次训练期测试期训练期选出的参数测试期表现简评
12018-20192020 上半年20收益可接受,回撤较大
22018-2020 上半年2020 下半年25收益较好,交易次数适中
32018-20202021 上半年20收益一般,但未严重失控
42019-2021 上半年2021 下半年30回撤扩大,需要记录原因
52020-20212022 上半年25测试期表现偏弱

这张表比单次回测更有教学价值。

它告诉你策略不是每一轮都赚钱。

它也告诉你参数会随着训练期变化。

更重要的是,它把“当时能知道什么”和“后来发生什么”分开了。

如果测试期多轮都很差,说明策略可能只在训练数据里漂亮。

如果测试期有赚有亏,但回撤、交易次数和失效原因都能解释,策略才有继续研究的价值。

5. Walk-forward 的标准流程

先选定总样本区间。

再决定训练期长度和测试期长度。

接着在每一轮训练期里做参数扫描。

然后把选出的参数锁定,放进下一段测试期。

最后把所有测试期结果拼接起来,形成一条“样本外资金曲线”。

mermaid
graph TD
    A["准备历史数据"] --> B["划分训练期与测试期"]
    B --> C["训练期内选择参数"]
    C --> D["锁定规则"]
    D --> E["测试期检验"]
    E --> F["窗口向前滚动"]
    F --> C
    E --> G["汇总所有测试期结果"]

这里有两个词很重要。

第一个是“锁定”。

进入测试期后,不能看到结果不好就回头改参数。

第二个是“汇总”。

不要只挑一轮最漂亮的测试期展示。

要把所有测试期结果放在同一张表里。

6. 训练期和测试期该多长

没有万能长度。

长度要和策略节奏匹配。

如果策略一周就交易很多次,训练期可以相对短一些,但要注意成本和噪声。

如果策略基于月线或季度财务数据,训练期太短就可能没有足够样本。

对日线 A 股新手策略,可以先尝试:

策略节奏训练期示例测试期示例直觉解释
较短线1 年3 个月快速检查近期适应性
波段2 年6 个月兼顾样本和市场变化
中期趋势3 年1 年更重视跨环境表现

这些只是学习起点。

真正写报告时,要说明为什么这样切。

不能因为某种切法结果好,就事后宣布它最合理。

7. 不能用未来调过去

这是 Walk-forward 的红线。

假设你用 2022 年的测试结果发现 25 日均线不好。

你不能回头把 2021 年训练期的选择改成 20 日。

因为站在 2021 年末,你还不知道 2022 年会怎样。

同样,你不能用完整样本里表现最好的股票池,回头用于早期测试。

也不能用后来才披露的财务数据,提前放进训练期。

在 A 股里,公告、财报、停复牌、成份股调整,都有明确可见时间。

回测流程必须尊重这些时间。

风险提醒

只要测试期结果参与了规则修改,这一轮测试就不再是真正的测试,而变成了新的训练。

8. 一个短小的伪代码示例

下面代码不追求完整运行,只展示 Walk-forward 的思路。

python
windows = [
    ("2018-01-01", "2019-12-31", "2020-01-01", "2020-06-30"),
    ("2018-07-01", "2020-06-30", "2020-07-01", "2020-12-31"),
    ("2019-01-01", "2020-12-31", "2021-01-01", "2021-06-30"),
]

test_results = []

for train_start, train_end, test_start, test_end in windows:
    train_data = data.loc[train_start:train_end]
    test_data = data.loc[test_start:test_end]

    best_param = choose_param_on_train(train_data, candidates=[15, 20, 25, 30])
    result = run_backtest(test_data, ma_days=best_param, cost_model=cost_model)
    test_results.append(result)

读这段代码时,请抓住三点。

第一,训练数据和测试数据按时间切开。

第二,参数只在训练数据里选择。

第三,测试数据只负责检验,不负责反向修改本轮规则。

9. 专业老师视角:Walk-forward 检查的是学习流程

Walk-forward 不是神秘算法。

它检查的是你的研究流程是否诚实。

如果你每一轮都能清楚说明训练期做了什么,测试期发生了什么,策略为什么通过或失败,说明你的研究开始可复查。

如果你只展示最终拼起来的漂亮曲线,却不展示每轮选择过程,就少了最关键的证据。

老师看 Walk-forward 报告,最关心三件事。

第一,切分是否提前规定。

第二,测试期是否独立。

第三,失败轮次是否被诚实记录。

10. 投资者视角:测试期亏损不是自动否定

很多新手看到某一轮测试期亏损,就立刻认为策略没用。

这也太急。

任何策略都有不适合的市场。

关键是亏损是否在可承受范围内。

最大回撤是否突破规则边界。

交易次数是否异常增加。

亏损是否集中在涨跌停、停牌或流动性不足的环境。

如果亏损符合策略已知风险,说明它只是经历了逆风。

如果亏损来自规则没有覆盖的漏洞,才需要暂停研究或重写规则。

11. 量化开发视角:每一轮都要可追踪

Walk-forward 很容易因为文件混乱而失真。

建议每轮记录一个表。

字段需要记录的内容
轮次编号例如 WF-01、WF-02
训练期起止日期
测试期起止日期
候选参数本轮允许选择哪些参数
选中参数训练期最终锁定的参数
成本假设佣金、印花税、滑点
测试期指标收益、回撤、交易次数
备注异常行情、停牌、涨跌停等

不要把每轮文件随手命名为 finalfinal2final_new

量化研究最怕的不是结果不好,而是结果好却没人能复现。

12. 常见失败信号

第一,训练期很好,测试期连续很差。

这通常说明训练期参数把历史细节学得太死。

第二,参数每一轮跳来跳去,且没有投资解释。

这说明策略可能没有稳定结构。

第三,测试期交易次数突然暴增。

这可能是行情噪声、成本估计不足或规则过于敏感。

第四,只有某一轮测试期特别好,整体靠它撑起结果。

这说明收益可能高度依赖单一市场环境。

这些信号都不是“立刻放弃”的命令。

它们是要求你回到规则和数据,重新检查原因。


交互实验室

本节的互动练习,是亲手设计一个 Walk-forward 切分表。

不用真实外部数据。

只要把时间逻辑写清楚,就已经完成了关键训练。

练习 A:设计滚动窗口

假设你有 2018 年到 2024 年的日线数据。

策略节奏是中期趋势。

请先采用“2 年训练 + 6 个月测试”的方案。

轮次训练期测试期本轮是否能看见测试期数据
12018-20192020 上半年不能
22018 下半年-2020 上半年2020 下半年不能
32019-20202021 上半年不能
42019 下半年-2021 上半年2021 下半年不能

请继续补完后续轮次。

补完后检查:每一轮测试期是否都在训练期之后?

练习 B:判断是否偷看未来

请判断下面做法是否合格。

做法是否合格原因
用 2018-2019 训练,测试 2020 上半年合格时间顺序正确
看完 2020 测试结果后,回头重选 2018-2019 参数不合格测试期参与了训练
用 2021 年才披露的财务数据判断 2020 年买点不合格数据当时不可见
每轮都记录选中参数和失败原因合格便于复查

练习 C:写一段 Walk-forward 结论

请套用下面模板。

本策略共完成 ______ 轮 Walk-forward。训练期长度为 ______,测试期长度为 ______。测试期中有 ______ 轮收益为正,最大回撤最深的一轮出现在 ______。当前结论是 ______,下一步需要检查 ______。

示例答案:

本策略共完成 8 轮 Walk-forward。训练期长度为 2 年,测试期长度为 6 个月。测试期中有 5 轮收益为正,最大回撤最深的一轮出现在 2022 上半年。当前结论是策略具备一定趋势环境适应性,但在震荡下跌阶段压力较大,下一步需要检查参数平台和成本敏感性。


核心复盘

知识清单

  • [ ] 我知道 Walk-forward 是多轮“训练期选择、测试期检验”的流程。

  • [ ] 我能区分训练期、测试期、滚动窗口和扩展窗口。

  • [ ] 我知道测试期不能反向参与本轮参数选择。

  • [ ] 我会把每轮选中的参数、成本假设和测试期指标记录下来。

  • [ ] 我理解测试期亏损不一定否定策略,但必须解释风险来源。

  • [ ] 我知道所有测试期结果都要展示,不能只挑好看的轮次。

金句总结

Walk-forward 的价值,不是让曲线更漂亮,而是逼策略在没见过的时间里接受考试。

本文档仅供学习交流用途,不构成任何投资建议。股市有风险,入市需谨慎。