4. 数据准备与窗口切分工程
滚动窗口回测的可信度,首先取决于进入窗口之前的数据是否干净、对齐、无偏。策略逻辑再精巧,如果行情序列存在重复时间戳、停牌缺口未处理、或股票池里混入了“未来才知道会退市”的标的,回测结果就只是数据缺陷的投影。本节围绕真实行情数据,完成从原始数据到可复用窗口切分方案的完整管道设计。
一、数据清洗:先定义“什么算脏数据”
以日频A股行情为例,原始数据通常包含日期、代码、开高低收、成交量、成交额、复权因子等字段。清洗的第一步不是写代码,而是明确校验规则。常见问题包括:同一代码同一日期重复记录、价格为零或负、最高价低于最低价、成交量非整数、复权因子缺失。建议在管道入口设置硬性校验,任何一条不满足即拒绝该批次数据并记录日志,而不是静默丢弃。
校验规则示例(日频行情):
1. (date, code) 唯一
2. low <= open, close <= high
3. low > 0 且 volume >= 0
4. 复权因子 > 0 且非空
5. 单日涨跌幅绝对值 <= 涨跌停限制 + 容差
复权处理需要统一口径。回测中若使用前复权价格,历史价格会随新除权事件变化,导致同一窗口在不同运行时间得到不同数值。工程上更稳妥的做法是:存储后复权价格用于计算收益,同时保留原始价格与复权因子,确保任意时点可重建。这样窗口切分方案不会因数据更新而漂移。
二、对齐与缺失处理:交易日历是基准
多标的回测中,各股票停牌、上市时间不同,直接按各自日期序列拼接会造成错位。正确做法是以交易所交易日历为主轴,将所有标的对齐到统一日期索引,缺失位置显式标记为NaN,而不是前向填充。前向填充会制造“停牌期间仍有价格变动”的假象,严重扭曲波动率和换手率计算。
缺失值的处理策略应分场景:对于收益计算,停牌日收益记为零、复牌日使用复牌价对停牌前收盘价计算累计收益;对于因子计算,若某标的在窗口内缺失比例超过阈值(例如20%),则该标的在该窗口内不参与选股,而不是用均值填补。阈值本身应作为参数写入配置,便于后续敏感性分析。
三、幸存者偏差检查:股票池必须“时点化”
幸存者偏差是回测中最隐蔽的偏差来源。若用当前仍在交易的股票列表回溯历史,等于提前剔除了退市、暂停上市和重大重组失败的标的,收益会被系统性高估。检查方法是:为每个标的维护上市日期、退市日期、暂停上市区间,构建“时点股票池”——在任意历史日期t,只允许使用当时已上市且未退市的标的。
工程实现上,可将股票池表示为区间表:代码、起始日期、结束日期、状态。窗口切分时,对训练段和测试段的每个交易日分别求交集,得到该日可用标的集合。若某标的在测试段中途退市,其退市前数据仍应保留在池中,退市后自动移出。这样回测的每一笔交易都只使用当时真实可交易的对象。
四、窗口切分规则:训练段与测试段的边界设计
窗口切分的核心参数有三个:训练段长度、测试段长度、滚动步长。以日频数据为例,一种常见配置是训练段500个交易日、测试段60个交易日、步长60个交易日,即训练段与测试段不重叠、窗口之间首尾相接。若希望训练样本更充分,可让训练段重叠,例如步长设为20个交易日,但必须保证测试段之间不重叠,否则同一段行情会被重复评估,夸大策略稳定性。
切分时必须遵守“训练段结束日 < 测试段开始日”的严格时序约束,且两者之间建议留出隔离带(embargo),长度至少覆盖策略持仓周期或标签计算窗口。例如策略使用未来5日收益作为标签,则训练段与测试段之间应空出5个交易日,防止标签泄漏。隔离带内的数据不参与训练也不参与测试,仅作为缓冲。
| 参数 | 示例取值 | 作用与约束 |
|---|---|---|
| 训练段长度 | 500个交易日 | 需覆盖至少一个完整市场周期片段 |
| 测试段长度 | 60个交易日 | 不宜过短,否则评估方差过大 |
| 滚动步长 | 60个交易日 | 等于测试段长度时测试段不重叠 |
| 隔离带 | 5个交易日 | 不小于标签计算窗口,防泄漏 |
| 缺失比例阈值 | 20% | 窗口内标的缺失超此值则剔除 |
五、可复用窗口切分方案与数据管道
将上述规则固化为一份窗口清单表,是管道可复用的关键。清单表每行对应一个窗口,字段包括:窗口ID、训练开始日、训练结束日、测试开始日、测试结束日、隔离带起止、数据快照版本号。回测引擎只读取该表,不自行推算日期,从而保证不同策略、不同运行批次使用完全一致的切分口径。
窗口清单表示例(片段):
window_id | train_start | train_end | test_start | test_end | embargo_days | snapshot_ver
W001 | 2018-01-02 | 2019-12-31 | 2020-01-08 | 2020-04-01 | 5 | v2024.03
W002 | 2018-04-02 | 2020-03-31 | 2020-04-08 | 2020-07-01 | 5 | v2024.03
W003 | 2018-07-02 | 2020-06-30 | 2020-07-08 | 2020-09-30 | 5 | v2024.03
数据管道则按“抽取—校验—对齐—掩码—时点池—切分—快照”的顺序组织,每个环节输出带版本号的中间产物。快照版本号与窗口清单绑定,确保任何时候重跑都能复现同一份数据状态。当原始数据发生除权调整或补充退市记录时,生成新版本快照,旧窗口清单仍指向旧版本,避免历史回测结果被无声改写。
完成以上步骤后,进入回测的每一段行情都具备明确的时间边界、干净的数值、真实的标的范围和可追溯的数据版本。窗口切分方案不再是散落在脚本里的日期硬编码,而是一份可审计、可复用、可版本化的工程资产,为后续参数稳定性评估提供一致的数据底座。