滚动前推验证:每年重新优化,不如一开始不动
12 折 walk-forward 实测——每年重选参数年化 -0.45%,固定 5/20 不动 0.13%,买入持有 3.84%
p5.4 只做了一次样本外检验。一次不够——一次切分只有一个结果,而你还是会忍不住调到它好看为止。
所以把它做成流水线:训练 3 年 → 选参 → 参数在测试窗内完全冻结 → 测试 1 年 → 整体前移 1 年 → 重复。
12 折,测试窗合计 3024 个交易日。把 12 段测试窗首尾相接:
A 滚动前推(每期选单点最优) 年化 -0.45% 最大回撤 -49.5% 夏普 0.026
B 滚动前推(每期选平原最优) 年化 -0.06% 最大回撤 -36.1% 夏普 0.056
C 固定参数 5/20,从头到尾不动 年化 0.13% 最大回撤 -41.7% 夏普 0.075
D 买入持有 年化 3.84% 最大回撤 -46.7% 夏普 0.283
每年勤勤恳恳重新优化参数的 A,跑输了从头到尾没动过的 C。
而 12 折里,每折选出来的参数有 11 个不同取值——它每年都在跳。
你每年根据去年的天气,重新决定今年种什么。
邻居十年不换,一直种同一种作物。
十年下来,他收成比你好。
不是因为他聪明,是因为 "去年的天气"里,能指导今年的信息本来就很少——而你每年都当它是全部信息。
一、切分方式
| 标的 | 沪深300 指数,4023 个交易日 |
| 训练窗 | 3 年(756 个交易日) |
| 测试窗 | 1 年(252 个交易日),参数在窗内完全冻结 |
| 前移步长 | 1 年 |
| 折数 | 12 |
| 覆盖 | 2013-02-19 ~ 2025-07-28 |
| 参数网格 | fast 2 |
两种选参方式对照跑:单点最优(训练窗内年化最高)与平原最优(p5.4 定义的平原分最高)。
测试窗回测时带上最长均线所需的历史做预热,但只统计测试窗内的收益——否则前 160 天信号是空的,等于白送一段空仓。
二、逐折结果
| 折 | 测试窗起 | 单点参数 | 训练内% | 测试外% | 平原参数 | 训练内% | 测试外% | 固定5/20% | 买入持有% |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 2013-02-19 | 6/80 | 7.20 | -18.43 | 14/100 | 4.95 | -19.58 | -12.51 | -19.13 |
| 2 | 2014-03-07 | 4/80 | -0.38 | 62.90 | 4/20 | -5.57 | 42.20 | 47.90 | 77.78 |
| 3 | 2015-03-19 | 2/80 | 17.01 | 1.98 | 4/140 | 16.27 | -10.69 | -8.18 | -17.51 |
| 4 | 2016-03-29 | 6/60 | 19.93 | -1.27 | 6/60 | 19.93 | -1.27 | 7.15 | 12.23 |
| 5 | 2017-04-12 | 20/40 | 25.77 | 2.37 | 12/160 | 19.53 | 5.75 | 6.75 | 7.19 |
| 6 | 2018-04-23 | 18/160 | 5.24 | 5.38 | 18/160 | 5.24 | 5.38 | -2.86 | -1.22 |
| 7 | 2019-05-08 | 14/80 | 8.35 | -15.31 | 10/80 | 7.79 | -11.12 | -11.84 | 7.91 |
| 8 | 2020-05-20 | 2/20 | 3.92 | 6.95 | 20/60 | 1.79 | 20.82 | 6.99 | 35.91 |
| 9 | 2021-06-02 | 16/160 | 8.76 | -10.50 | 6/100 | 7.66 | -10.55 | -8.82 | -19.73 |
| 10 | 2022-06-17 | 16/160 | 4.41 | -7.64 | 18/160 | 2.40 | -7.04 | -3.43 | -11.35 |
| 11 | 2023-06-30 | 16/40 | 4.17 | -5.07 | 10/20 | -0.71 | 1.00 | -9.93 | -9.67 |
| 12 | 2024-07-15 | 18/40 | -0.20 | -7.10 | 14/160 | -4.12 | -1.46 | 3.37 | 19.06 |
第 4 折和第 6 折,两种选参方式选出了同一组参数——这种巧合一年发生一次左右,不是常态。
三、三个数,一起读
① 训练内 → 测试外的衰减
| 选参方式 | 训练窗内平均 | 测试窗外平均 | 衰减 |
|---|---|---|---|
| 单点最优 | 8.68% | 1.19% | -7.50 pp |
| 平原最优 | 6.26% | 1.12% | -5.14 pp |
平原选参的衰减更小(-5.14 vs -7.50)——p5.4 那个启发式在 12 折上重复出来了,不是单次巧合。
② 但拼起来是负的
上面写"测试窗外平均 1.19%",而拼接后的年化是 -0.45%。这不矛盾:
前者是 12 个分年收益率的算术平均,后者是复利。 第 2 折那个 +62.90% 把算术平均拉高了,但复利不吃这一套——p3.1 讲过的算术均值与几何均值之差,在这里正面撞上来了。
凡是用"平均每年赚 X%"描述一段实际持有经历的,先问一句:是算术平均还是复利? 本例两者差了 1.64 个百分点,方向还是相反的。
③ 谁也没跑赢什么都不做
| 方案 | 年化% | 最大回撤% | 夏普 |
|---|---|---|---|
| A 滚动前推(单点最优) | -0.45 | -49.5 | 0.026 |
| B 滚动前推(平原最优) | -0.06 | -36.1 | 0.056 |
| C 固定参数 5/20 | 0.13 | -41.7 | 0.075 |
| D 买入持有 | 3.84 | -46.7 | 0.283 |
A 跑输 C:每年重新优化,不如一开始定死不动。
这句话值得停下来想一想,因为它推翻的是一个非常自然的直觉:"市场在变,参数当然要跟着调。"
实测说的是:你以为你在跟踪市场变化,实际上你在跟踪噪声。
证据在参数序列里:
单点最优每折选出的参数:
(6,80) (4,80) (2,80) (6,60) (20,40) (18,160) (14,80) (2,20) (16,160) (16,160) (16,40) (18,40)
→ 12 折里 11 个不同取值
如果训练窗真的在测量某种稳定的市场结构,参数不该每年都跳到完全不同的地方。
平原选参也是 11/12——它减小了衰减和回撤,但没有让参数变稳定。
🔧 动手做:诚实验证之后,策略还剩多少?(6 分钟)
滚动前推是这门课最接近"你当年真这么做"的验证:训练窗选参 → 测试窗冻结 → 前移 → 重复。跑 python walk_forward.py。
你会看到(实测):滚动前推(平原选参)拼起来的净值,年化 -0.06%;而同期买入持有 3.84%。平原参数训练内 6.26% → 测试外只剩 1.12%。
想明白:一旦不许偷看未来、参数一进测试窗就冻结,这条双均线策略输给了什么都不做。这不是策略没调好——是大多数看着能赚的策略,经不起这一关。这门课到这里没给你一个赚钱的策略,给的是这台照妖镜。
四、那滚动前推还有什么用?
它没能让策略变好。但它让你提前知道了这件事。
这就是它的全部价值:
| 一次样本外检验 | 滚动前推 | |
|---|---|---|
| 样本外结果个数 | 1 个 | 12 个 |
| 能否看出参数稳定性 | 不能 | 能(11/12 个不同取值) |
| 能否算样本外的回撤路径 | 只有一段 | 12 段拼接,-49.5% |
| 被"调到好看为止"的空间 | 大 | 小(每调一次要重跑全部 12 折) |
它是一个证伪工具,不是一个提升工具。
而它在本例里给出的答案是明确的:这个策略族在这段样本上,经不起这个检验。
需要说清楚的边界:本节只检验了双均线 + 网格选参这一种组合,在沪深300 指数这一个标的上。 "滚动前推之后仍然有效"的策略是存在的——但你必须真的跑一遍才知道自己手上这个是不是。
五、报告规范
一份合格的滚动前推报告至少包含:
- 切分参数:训练窗、测试窗、步长、折数(缺一项就无法复现)
- 逐折表,不只有汇总——汇总会藏住第 2 折那种一枝独秀
- 拼接净值的复利年化 + 最大回撤,而不是分年收益的算术平均
- 每折选出的参数列表——参数漂移是最诚实的过拟合指标
- 至少一个"什么都不做"的对照(固定参数 / 买入持有)
📌 免责:本课为技术教学,标的为沪深300 指数,所有回测为历史模拟,不构成投资建议。
三件事:
- 滚动前推 = 12 个样本外结果,不是 1 个。训练 3 年 → 选参 → 冻结 → 测试 1 年 → 前移;实测 12 折,测试窗合计 3024 个交易日
- 每年重新优化(-0.45%)跑输从头不动(0.13%),两者都跑输买入持有(3.84%)。参数序列 12 折里有 11 个不同取值——你以为在跟踪市场变化,实际在跟踪噪声
- 平原选参确实更稳:衰减 -5.14 pp vs -7.50 pp,最大回撤 -36.1% vs -49.5%。p5.4 的启发式在 12 折上重复出来了——但它没有让参数变稳定(同样 11/12)
一个必须记住的口径差:测试窗外算术平均 +1.19%,拼接复利 -0.45%,差 1.64 个百分点且方向相反(p3.1)。凡是用"平均每年赚 X%"描述实际持有经历的,先问是算术还是复利。
滚动前推是证伪工具,不是提升工具。它没让策略变好,但它让你提前知道了。
下一节继续这条线:即使拿到了一条样本外净值曲线,它也只是一次实现。蒙特卡洛与自助法回答的是——如果历史重演一次,结果的范围有多宽?
🔎 来源与核验· 4 条,点开核对
