Appearance
第 14 讲:滚动样本外——walk-forward
本讲要点
一次切分只是入门;专业最低配至少要会滚动检验。
1. 为何单次切分不够
第 7 讲用「另一段历史」揭穿过拟合。若只做一次训练 / 测试:
- 恰好切在某种行情边界上,结论可能运气很好或很差;
- 无法看到样本外表现的分布(有多少折为正、离散有多大)。
Walk-forward(滚动前进)
步骤如下:
- 取一段训练窗,在窗内扫描参数,选出冠军;
- 冻结参数,在紧随其后的测试窗跑一遍;
- 窗口整体向前滚,重复多次;
- 报告各折测试收益,并可拼接样本外净值。
更严格的组合交叉验证(如 CPCV)存在;本课要求理解:为何需要滚动,以及如何读各折结果。
2. 本讲设定
| 项目 | 取值 |
|---|---|
| 训练窗 | 24 个月 |
| 测试窗 | 6 个月 |
| 滚动步长 | 6 个月(与测试窗同长) |
| 扫描网格 | 动量回看月数 = 1 / 2 / 3;Top-N = 1 / 2 / 3 |
| 训练选优 | 训练窗内 Sharpe 最高 |
| 成本 | 0 bps(专注参数迁移;摩擦见第 15 讲) |
共 3×3 = 9 组参数;每折只在训练窗内选优,测试窗禁止再调参。
3. 完整代码思路
python
TRAIN_MONTHS, TEST_MONTHS = 24, 6
MOM_GRID = (1, 2, 3)
TOP_GRID = (1, 2, 3)
oos_parts = []
i = 0
while i + TRAIN_MONTHS + TEST_MONTHS <= len(dates):
train_idx = dates[i : i + TRAIN_MONTHS]
test_idx = dates[i + TRAIN_MONTHS : i + TRAIN_MONTHS + TEST_MONTHS]
best_sharpe, best = float("-inf"), None
for mom in MOM_GRID:
for top in TOP_GRID:
ret = run_params(train_me, mom, top).loc[train_idx[0] : train_idx[-1]]
s = sharpe(ret)
if s > best_sharpe:
best_sharpe, best = s, (mom, top)
mom_b, top_b = best
test_ret = run_params(me, mom_b, top_b).reindex(test_idx).dropna()
oos_parts.append(test_ret)
i += TEST_MONTHS
oos = pd.concat(oos_parts) # 拼接样本外完整可运行脚本:easy-quant/code/14_walk_forward.py
bash
python easy-quant/code/14_walk_forward.py4. 运行结果
text
折1: 训练选 mom=1, top=1 训练收益 17.17% 测试收益 -4.04%
折2: 训练选 mom=1, top=1 训练收益 4.15% 测试收益 0.66%
折3: 训练选 mom=1, top=3 训练收益 1.07% 测试收益 7.17%
折4: 训练选 mom=3, top=1 训练收益 31.69% 测试收益 24.84%
折5: 训练选 mom=3, top=1 训练收益 42.79% 测试收益 35.36%
折6: 训练选 mom=3, top=1 训练收益 94.67% 测试收益 10.03%
滚动折数: 6
拼接样本外累计收益: 92.50%
拼接样本外 Sharpe: 1.03
全样本固定 mom=1, top=2 累计: 63.56% (非样本外,仅对照)
测试窗收益为正的折数: 5/6| 折 | 训练冠军 | 训练收益 | 测试收益 |
|---|---|---|---|
| 1 | mom=1, top=1 | 17.17% | −4.04% |
| 2 | mom=1, top=1 | 4.15% | 0.66% |
| 3 | mom=1, top=3 | 1.07% | 7.17% |
| 4 | mom=3, top=1 | 31.69% | 24.84% |
| 5 | mom=3, top=1 | 42.79% | 35.36% |
| 6 | mom=3, top=1 | 94.67% | 10.03% |

读法:
- 第 1 折测试为负:即使整体拼接好看,仍有失效窗口——要看分布,不看单一幸运数字。
- 冠军参数在折间会变(top 与 mom 都会换),全样本死守
mom=1, top=2只是其中一种选择。 - 拼接样本外累计与「全样本固定参数」不可直接比谁更神:路径、参数序列都不同;前者回答的是「按规则滚动选参后,样本外还在不在」。
- 仅 6 折、单一资产池,统计力度有限;课程达标线是会做、会读,不是宣称策略可上线。
5. 本讲小结
- Walk-forward = 反复「训练选参 → 测试冻结 → 向前滚」
- 关注各折测试收益的符号与离散,而非只报拼接总值
- 下一讲:把理想成交换成含佣金与滑点的净值