金融时序交叉验证的核心矛盾,不是样本数量够不够,而是训练集和测试集之间有没有偷偷串门。价格、成交量、波动率、盘口因子都带有时间联系;更麻烦的是,很多标签本身覆盖一段时间。今天生成的样本,可能要等未来几天的价格路径走完,才能确定它究竟是上涨标签还是下跌标签。你表面上切开了数据,实际上却让两组样本共享了同一段未来。
这就是数据泄漏。它不会在回测报告里主动报警,只会把收益曲线抬高,把风险压低,最后等你真金白银开仓时再把账户击穿。
金融时序数据的本质陷阱:传统 K 折验证为何会失效
传统 K 折交叉验证建立在一个前提上:样本近似独立同分布。把数据切成若干份,轮流拿一份做测试,其余部分做训练,模型在不同切分上反复验证,最后汇总指标。
这套方法放在普通分类任务里很顺手。图片、文本、用户行为样本,只要样本之间没有明显的时间依赖,随机切分可以提供相对合理的评估。但金融市场不是一堆互不相干的彩色小球。价格序列有自相关,波动会成簇出现,成交量和盘口状态会持续一段时间,宏观事件还会让多个交易日共享同一套驱动因素。
你随机打乱金融样本,相当于把未来的市场状态拆成碎片,塞回过去的训练集中。模型不需要真正学会预测,只要认出与测试集相似的市场片段,就能拿到一份虚假的高分。
第一层泄漏:样本之间存在时间依赖
假设你用过去若干交易日的收益率、波动率和成交量构造特征,预测下一个交易日的方向。某个训练样本发生在一月十日,测试样本发生在一月十二日。只要特征窗口、标签区间或市场状态存在重叠,这两个样本就不是完全独立的。
如果你的历史窗口是六十三个交易日,那么一月十二日样本使用的历史信息,会与一月十日样本大范围重合。模型训练时看到的并不是陌生环境,而是与测试样本高度相似的市场结构。你以为模型在做样本外预测,实际是在相邻的时间片里反复认图。
这类泄漏不一定表现为直接使用未来收盘价。很多时候,特征计算本身没有越过预测时点,程序也没有明显错误,但训练样本与测试样本共享了太多历史路径,模型就会得到不该拥有的优势。
第二层泄漏:标签覆盖区间发生重叠
金融机器学习里,标签不是一个静止的点。你可能在时刻 \(t_0\) 建立样本,用未来一段区间 \([t_0,t_1]\) 的价格变化来定义标签。
例如:
- 在一月十日收盘后生成样本;
- 观察未来五个交易日;
- 如果期间收益达到目标,标签记为上涨;
- 如果先触发止损,标签记为下跌;
- 直到观察窗口结束,标签才最终确定。
此时,一月十日样本的标签区间可能覆盖一月十一日至一月十七日。另一个一月十五日生成的样本,标签区间可能覆盖一月十六日至一月二十二日。两个标签在一月十六日至一月十七日发生重叠。
如果前一个样本被放进训练集,后一个样本被放进测试集,训练数据实际上已经携带了测试区间的部分价格路径。模型并不是在未知未来上受检,而是在相互重叠的答案纸上重新作答。
这就是重叠标签带来的泄漏。只看样本生成日期,根本抓不住它。你必须同时记录每条观测的起始时间和结束时间,也就是标签真正覆盖的评估区间。
金融回测最危险的不是亏损,而是用泄漏制造出来的盈利。
第三层泄漏:特征窗口与测试区间相邻
很多交易策略使用滚动均值、历史波动率、成交量分位数、技术指标或订单流特征。它们通常需要一段回看窗口。窗口本身没有使用未来数据,并不等于切分之后没有泄漏。
假设某个特征使用六十三个交易日的历史窗口。测试集结束后,紧接着的训练样本会立刻使用测试集附近的市场状态。金融市场的微观结构并不会在测试集最后一天自动清零,报价节奏、流动性、波动状态、参与者行为都可能持续到后续日期。
如果训练集紧贴测试集,模型就可能从相邻样本中吸收测试阶段留下的市场结构噪声。对于高频期货、短周期股票策略和盘口策略,这种影响更加尖锐:几根连续的报价变化、同一轮主动买盘、同一个事件冲击,都可能让相邻观测高度相关。
传统 K 折验证不会替你处理这些关系。它只负责切分索引,不负责理解标签区间和市场时间结构。刀切得再整齐,切错位置还是会把训练集和测试集缝在一起。
净化机制:把重叠标签从训练集中清出去
净化,也就是净化交叉验证中的“净化”步骤,目的非常明确:测试集覆盖的评估时间区间,不能在训练集的标签区间里留下重叠观测。
它不是删除测试集,也不是把数据简单按日期一刀切成训练集和测试集。真正的净化,是针对每一条训练观测检查它的标签区间,只要与测试区间发生重叠,就从训练集中移除。
先把每条样本从一个时间点改成一个区间
很多回测框架只保存一列时间戳:
| 样本时间 | 特征 | 标签 |
|---|---|---|
| 一月十日 | 当日可获得的市场数据 | 未来五日收益方向 |
这张表对普通机器学习够用,对金融时序不够。你至少还需要记录:
| 字段 | 含义 |
|---|---|
| 样本起始时间 | 生成特征和发出预测的时间 |
| 标签结束时间 | 标签所覆盖的未来区间结束时间 |
| 评估区间 | 实际用于判断标签的时间范围 |
| 特征回看窗口 | 构造特征时向历史回看的长度 |
| 交易执行时间 | 信号生成后真正成交的时间 |
其中最关键的是标签起点和终点。没有标签区间,净化只能凭日期猜测,最终还是会漏掉重叠样本。
举个不依赖具体品种的例子。测试集评估区间是三月十日至三月十四日。训练集中有一条观测,样本生成时间是三月八日,但它的标签结束时间是三月十二日。虽然三月八日早于测试集,标签却穿进了测试区间。这条观测必须被清除。
另一条训练观测生成于三月十五日,标签覆盖三月十五日至三月十九日。它没有和测试区间直接重叠,但它紧贴测试集结束位置,仍可能受到测试阶段市场状态和微观结构噪声的影响。这部分不由净化处理,而要交给禁运。
净化的判断逻辑
实际处理时,可以把测试样本的评估区间记为 \([T_0,T_1]\),训练样本的标签区间记为 \([L_0,L_1]\)。
两者满足以下关系时,训练样本应当被移除:
- 训练标签在测试区间开始前进入,但在测试区间内结束;
- 训练标签在测试区间内开始,并在测试区间结束后结束;
- 训练标签完整覆盖测试区间;
- 训练标签完全落在测试区间内部。
换句话说,只要两个区间相交,就不能让这条训练观测继续留在训练集里。
这一步看起来朴素,实际最容易被工程细节绞杀。交易日历、节假日、夜盘、跨市场时区、合约换月都会影响区间判断。期货策略尤其不能只用自然日做索引。夜盘属于哪个交易日,标签结束落在哪个结算时点,信号是在收盘生成还是在下一根盘口成交,这些都必须先定义清楚。
否则,你会得到一种危险的假净化:代码运行正常,训练集也确实删掉了一些样本,但删掉的并不是实际发生信息重叠的样本。
净化不是简单的“训练集早于测试集”
不少人会采用最粗糙的时间切分:测试集从某天开始,测试日之前全部训练,测试日之后全部丢弃。这个方法在单次严格的时间外推里有一定价值,但它无法解决滚动标签的问题。
原因很简单:样本的生成时间早于测试集,不代表标签结束时间早于测试集。只要标签使用未来窗口,旧样本就可能把测试区间的价格信息带进训练集。
如果你用未来五天收益做标签,训练截止日期至少要考虑标签的实际结束边界;如果标签由止盈、止损和最大持有期共同决定,结束时间甚至不是固定的。净化必须读取每条样本真实的标签结束时间,而不是凭一个固定窗口粗暴估算。
净化之后,样本数量减少是正常现象
净化会让训练样本减少,尤其是在标签窗口较长、测试区间较宽、样本生成频率较高时。有人看到训练集少了,就急着把禁运天数调低、标签窗口缩短,甚至直接关闭净化。这不是优化,是向泄漏投降。
有效样本变少,说明你原来的样本并没有那么独立。模型需要在更干净的数据上训练,而不是靠重复观测堆出一个漂亮指标。
你真正应该检查的是:
- 每个测试折净化掉了多少训练样本;
- 被删除样本主要集中在哪些时间段;
- 不同品种、不同频率下净化比例是否异常;
- 净化后训练集是否仍覆盖完整的市场状态;
- 模型性能下降后,是否还具备可解释的交易逻辑。
如果净化之后收益曲线明显塌陷,不要立刻认为净化破坏了策略。先承认一个事实:原来的收益可能就是靠泄漏撑起来的。
禁运机制:给测试集后面留出真正的缓冲区
净化解决的是区间重叠,禁运解决的是相邻样本之间的隐性联系。
禁运,也叫禁运期或缓冲期,是在测试集结束之后,额外划出一段时间。在这段时间内生成的样本不参与训练。它们既不属于当前测试集,也不属于当前训练集,相当于在两者之间挖出一道隔离带。
为什么测试集结束后还要隔离?因为市场信息和微观结构不会随着测试标签的结束瞬间消失。
假设测试集覆盖三月十日至三月十四日。三月十五日刚生成的样本,可能仍然处于同一轮波动冲击中。它的特征可能包含测试阶段延续下来的成交量异常、报价跳动和波动率状态。对于短周期策略,这种相邻关系足以让模型从测试环境中获得不该获得的线索。
禁运就是把这段紧邻区域剥离出去,降低连续样本之间的关联。
净化与禁运各自处理什么问题
| 处理方式 | 主要针对的问题 | 删除或隔离的对象 | 判断依据 |
|---|---|---|---|
| 净化 | 标签区间与测试区间重叠 | 训练集中与测试区间相交的观测 | 标签起止时间 |
| 禁运 | 测试结束后的邻近相关和微观结构噪声 | 测试结束后缓冲期内的观测 | 测试结束时间与缓冲长度 |
| 时间顺序切分 | 防止直接使用未来时间段 | 测试开始之后的历史数据 | 样本生成时间 |
| 组合净化交叉验证 | 多折评估下的泄漏控制和损益路径分析 | 每个组合折中的重叠与邻近观测 | 各折测试区间、标签区间及禁运期 |
这三件事不能混为一谈。时间顺序切分是基本秩序,净化是区间层面的清理,禁运是相邻关系层面的隔离。只做其中一项,仍然可能漏出数据泄漏。
净化是拆掉交叉的电线,禁运是拉开两根还在冒火花的电线。少做一步,模型照样会触电。
禁运长度不能靠固定数字拍脑袋
部分实践会使用五个交易日作为禁运缓冲,但这不是所有市场、所有周期、所有策略的统一答案。把五天写死在配置文件里,然后对股票、期货、加密资产和高频盘口策略一视同仁,是典型的工程懒惰。
禁运长度至少要结合以下因素判断:
- 标签的最大持有期;
- 特征回看窗口;
- 样本生成频率;
- 市场波动和成交结构的持续时间;
- 策略的交易周期;
- 交易成本和滑点的变化速度;
- 标的之间的联动关系;
- 数据是否来自同一事件或同一批订单流。
对于日频、持有期较短的策略,五个交易日可以作为一种待验证的经验设置,但不能把它写成行业标准。对于高频期货,五天可能长得毫无意义,也可能短得不够用,关键要看你的样本定义和市场状态持续时间。
如果特征使用六十三个交易日回看窗口,禁运是否也必须设置成六十三天?不能机械推导。回看窗口描述特征需要多少历史信息,禁运描述测试集附近的样本需要隔离多久,两者有关联,但不是同一个参数。
正确做法是做敏感性分析:在逻辑一致的范围内改变禁运长度,观察模型的收益、回撤、换手、胜率和损益分布是否稳定。如果禁运从一个设置调整到另一个相邻设置,策略就从盈利变成爆仓,说明模型对时间边界极其敏感,不能把那条收益曲线当成可靠证据。
禁运会制造“空白区”,这不是数据浪费
禁运后的数据不被使用,很多人会觉得可惜。金融数据本来就少,再丢掉一段,模型怎么训练?
但回测不是数据收集比赛。你要评估的是未来交易能力,不是把每一条历史记录都压进训练集。为了多留几条样本而把相邻泄漏放进来,等于用几百条脏数据换一条假收益曲线。
真正需要担心的不是禁运造成的样本减少,而是禁运设置后,训练集是否仍然覆盖牛市、熊市、震荡、快速反转和流动性收缩等关键状态。如果数据量不足以支撑干净的验证,就降低模型复杂度、减少策略自由度,而不是取消隔离。
从一次切分到组合净化交叉验证
单次训练集和测试集切分,只能告诉你某一个时间段上发生了什么。它无法完整回答:这套策略换一个测试区间是否还能活?收益是否集中在一段特殊行情?回撤是否只是某一次切分恰好没有出现?
组合净化交叉验证,简称组合净化交叉验证,是在多个时间分组之间组合测试集,并对每一种组合执行净化和禁运。它的价值不在于把交叉验证包装得更复杂,而在于生成多条相对独立的损益路径,让你观察策略在不同测试组合下的表现。
先按时间分组,而不是随机打散
假设你把历史数据按时间顺序划分为若干组。每次选取其中若干组作为测试集,其余组作为候选训练集。然后,对候选训练集执行两道清理:
1. 删除标签区间与测试区间重叠的训练样本;
2. 删除测试结束后禁运期内的样本。
这里的关键是“按时间分组”。如果先随机打乱,再组合折叠,分组本身已经破坏了时间结构,后面的净化只是在漏水的船上擦地板。
测试组也不能只看数量是否均匀。某些市场阶段波动极端、交易日稀疏或流动性显著下降,强行把它们切成相同长度的组,可能导致某个测试折承载了完全不同的风险。分组需要服务于评估目标,而不是只服务于代码循环。
每个组合都要重新计算可用训练集
组合净化交叉验证不是先固定一张训练表,再反复套不同测试索引。因为每次测试组合不同,发生重叠的训练样本也不同,禁运区间也不同。
每个组合至少要重新执行:
- 确定当前测试组合的最早开始时间和最晚结束时间;
- 找出所有与测试标签区间相交的候选训练样本;
- 删除这些重叠样本;
- 在测试结束位置之后设置禁运期;
- 删除禁运窗口内的训练样本;
- 记录剩余训练样本数量和时间覆盖范围;
- 训练模型并保存该组合的预测结果与损益路径。
如果你只在第一次切分时清理一次,后面的组合就会重新把泄漏样本带回来。这个错误不会让程序报错,却会让评估失去意义。
CPCV真正要看的是损益路径,不是平均分
普通交叉验证常用准确率、均方误差或其他单一指标汇总。金融策略不能只盯着平均准确率。交易的最终结果由信号、仓位、成交、手续费、滑点和退出逻辑共同决定。
组合净化交叉验证需要把每个测试组合产生的预测转换为真实交易规则下的损益。至少应该保留:
- 每笔交易的进场时间和退出时间;
- 信号方向和仓位大小;
- 交易价格与执行延迟;
- 手续费和滑点假设;
- 单笔收益、连续亏损和最大回撤;
- 不同测试组合下的累计损益;
- 交易次数和换手变化;
- 盈利是否集中在少数时间段。
如果某个模型在大多数组合中只是小幅盈利,却在一个组合里靠极端行情拉出全部收益,这不是稳健,是收益集中风险。反过来,如果模型在不同组合中收益方向一致,但个别阶段因交易成本升高而回撤扩大,就需要继续检查成本模型和信号频率,而不是只看一个被平均过的指标。
一个真实可用的模型,必须经得起不同时间组合的轮番扫损。它可以亏,但不能只在某一段历史里活着。
损益评估还要避免重复计数
不同测试组合可能包含相同的时间组。这样做可以形成多条损益路径,但同一段历史在不同路径中出现,并不代表你获得了更多独立证据。
你需要区分两件事:
- 组合数量增加;
- 独立市场信息增加。
前者可以通过组合方式实现,后者取决于时间覆盖、市场状态和样本之间的真实相关性。不能因为跑出了许多组合,就把它们简单当成许多完全独立的实验,再据此夸大统计信心。
同时,模型调参次数也必须记录。你用同一批组合反复尝试标签窗口、特征、模型深度、止盈止损和禁运长度,最终挑出表现最好的版本,这些尝试本身就构成了多重假设检验。净化和禁运能减少数据泄漏,却不能替你修正策略开发过程中的反复试错。
一套可落地的实操流程
如果你正在重构量化回测框架,不要先去换模型。先把样本时间定义清楚,再把切分流程固定下来。
第一步:定义信号、执行和标签的时间点
先写清楚策略到底在什么时候知道信息,什么时候产生信号,什么时候成交,什么时候结束一笔交易。
例如,收盘价只有在收盘后才可用,那么使用收盘价构造的信号不能假定在同一个收盘价上无摩擦成交。若信号在下一根开盘执行,标签起点、执行时间和价格都要向后移动。
这一步不是形式主义。执行时间错一根柱子,回测就可能把无法成交的价格当成成交价。对于期货和股票,开盘跳空、涨跌停、盘口深度和夜盘切换都会让这种错误直接放大成收益幻觉。
第二步:为每条观测保存标签结束时间
不要只保存标签数值。标签是由未来区间计算出来的,就要把区间结束时间一起保存。
固定持有期标签可以直接记录结束日;以止盈、止损或事件触发为终点的标签,要记录实际结束时间;如果达到最大持有期仍未触发退出条件,则用最大持有期结束时间作为标签终点。
标签结束时间决定净化边界。没有它,程序无法知道某条训练样本是否穿过测试区间。
第三步:明确特征是否发生跨折计算
滚动特征、标准化、缺失值填补、降维和特征选择,都不能在全量数据上先做完,再进行交叉验证。
例如,你用全历史均值和标准差对波动率进行标准化,测试区间的信息已经进入了训练过程。即便没有直接使用未来价格,分布参数也发生了泄漏。
正确顺序是:每个训练折独立计算预处理参数,再把同一组参数应用到对应测试折。特征工程必须服从训练—测试边界,而不是先处理全表再假装切分。
第四步:对每个测试折执行净化
确定测试区间后,逐条检查候选训练样本:
- 训练标签区间与测试区间相交,删除;
- 训练样本的特征计算明确使用了测试区间之后的信息,删除或重新计算;
- 样本生成时间虽然早于测试集,但标签结束时间越过测试起点,删除;
- 多资产数据共享同一事件窗口时,不能只按单一标的日期判断,要统一事件边界。
这一步的结果应该可以审计。你要能回答某条样本为什么被删除,而不是只看到一个最终的样本数量。
第五步:在测试结束后施加禁运
在测试区间结束后设置缓冲窗口,窗口内的样本不进入训练集。禁运长度按策略周期、标签持有期和市场相关性设定,再做敏感性分析。
五个交易日可以作为某些实践中的测试起点,但不能直接复制到所有策略。对于不同品种和频率,要记录不同设置下的结果变化。
第六步:保存每个组合的完整损益
不要只保存一个平均收益率。把每个组合的交易明细和净值路径存下来,最后再做汇总。
至少要看:
- 收益是否依赖某一个市场阶段;
- 回撤是否在不同组合中重复出现;
- 交易成本变化后是否仍能覆盖摩擦;
- 策略是否因训练样本减少而改变交易频率;
- 模型输出是否在不同折之间发生剧烈漂移。
如果训练集清理后,交易次数骤降,不能简单认为模型更稳健。可能是信号被削弱,也可能是原来存在大量重复样本。你必须结合交易逻辑判断,而不是只看净值曲线。
参数调优的边界:不要把禁运期调成收益开关
净化和禁运的参数本身也会被过拟合。
你不断试验不同的禁运长度,最后挑出收益最高的那一个;反复改变标签持有期,最后保留夏普比率最高的版本;再换一套模型深度和特征组合,把最漂亮的曲线提交到报告里。这套流程看起来严谨,实质上只是把过拟合从模型层面搬到了验证框架层面。
禁运长度应该由市场结构解释
禁运期的调整,必须能回答一个问题:你为什么认为这段时间内的样本仍然与测试阶段存在关联?
可以从以下角度建立解释:
- 标签最长持续多久;
- 信号生成频率是否导致样本高度密集;
- 事件冲击后波动率通常持续到什么范围;
- 盘口策略的订单流记忆持续多长时间;
- 跨市场传导是否让相关品种共享同一段信息;
- 交易成本和流动性是否在测试结束后继续异常。
如果只是因为某个长度让回测收益更高,就把它定为最终参数,你不是在控制泄漏,而是在给收益曲线挑衣服。
关注参数变化下的结果稳定性
可以建立一张简单的敏感性表,记录不同禁运长度下的结果:
| 禁运设置 | 净化后训练样本量 | 测试组合收益表现 | 最大回撤 | 交易次数 |
|---|---|---|---|---|
| 较短缓冲 | 记录实际数量 | 记录各组合分布 | 记录实际结果 | 记录实际结果 |
| 中等缓冲 | 记录实际数量 | 记录各组合分布 | 记录实际结果 | 记录实际结果 |
| 较长缓冲 | 记录实际数量 | 记录各组合分布 | 记录实际结果 | 记录实际结果 |
这张表不是为了找一行最高收益,而是看结果有没有结构性崩塌。如果禁运稍微变化,收益就从正变负,说明模型依赖边界附近的样本。此时应回到特征、标签和交易周期,而不是继续寻找一个能把曲线拉回去的数字。
看损益分布,别被均值收买
平均收益会掩盖路径差异。你需要把每个测试组合看成一次独立战斗,检查:
1. 盈利组合和亏损组合的数量是否失衡;
2. 最大盈利是否集中在少数组合;
3. 最大回撤是否集中在某一种市场状态;
4. 单笔大赚是否掩盖了大量小亏;
5. 交易成本增加后,损益方向是否改变;
6. 训练样本减少后,策略是否依旧符合原始逻辑。
如果策略只在某个趋势猛烈的阶段吃货,进入震荡后连续扫损,就不能用全样本平均收益给它盖章。模型不是因为平均值漂亮就获得了未来通行证。
这些错误最容易把回测结果抬上去
只按样本生成日期切分
这是最常见的错误。样本生成日期早于测试集,并不代表标签区间没有进入测试集。只看一列时间戳,净化无从谈起。
先全量计算标准化和特征选择
全量计算滚动统计、标准化参数、主成分或特征重要性,再做交叉验证,会让测试集参与训练流程。程序不会报错,指标还可能更好看,但那只是泄漏在替你赚钱。
把测试集之后的数据立刻塞回训练
测试集结束后的相邻样本,可能仍与测试阶段共享市场状态。没有禁运,短周期策略尤其容易被微观结构噪声反向喂养。
把五天禁运写成永恒规则
五天是部分实践中的设置,不是金融市场的物理常数。不同品种、不同频率、不同标签窗口必须重新判断。固定数字能让代码更简单,却不能让市场变得相同。
只报告一个总收益和一个夏普比率
总收益不告诉你利润来自哪里,夏普比率也不能替你检查标签重叠。没有逐折损益和交易明细,所谓稳健只是报告排版上的稳健。
把净化当成反过拟合的万能药
净化和禁运主要用于控制数据泄漏。它们不能替代策略多重假设检验校正,不能消除无限次调参带来的选择偏差,也不能解决交易成本估计错误、执行价格虚高和模型结构不合理。
如果你同时尝试了几十种标签、上百个特征和多套退出规则,最后只展示其中最好的一个结果,即便使用组合净化交叉验证,也仍然可能是过拟合。战场换了,贪婪没有换。
如何判断回测是否终于接近真实
没有一种验证方法能把未来完全搬到桌面上。你能做的,是让评估过程尽量不占未来的便宜。
一套更可信的金融时序验证,至少应满足以下条件:
- 样本按时间组织,而不是随机打散;
- 每条观测都具备明确的标签起止时间;
- 标签区间与测试区间重叠的训练样本被净化;
- 测试集结束后设置有依据的禁运期;
- 滚动特征和预处理参数只由训练集计算;
- 每个测试组合都独立完成清理和训练;
- 交易价格、延迟、手续费和滑点被纳入损益;
- 结果按测试组合保存,而不是只留一个总分;
- 调参次数和候选方案被记录;
- 最终模型还要接受严格的时间外推或走步验证。
最后一项尤其重要。组合净化交叉验证能让样本外评估更接近现实,但它不是交易系统的终点。你仍然需要用未参与开发的新时间段验证模型,检查它能否在完全陌生的市场状态下工作。
如果模型只能在交叉验证折里活着,离开那张历史表就爆仓,那么它不是策略,只是一份被精心打磨过的历史解释。
结语:先清理时间边界,再谈模型聪明
金融时序交叉验证的净化与去重,真正解决的不是某个代码接口,而是交易者对“样本独立”的错误幻想。
传统 K 折验证把金融数据当成可以随手洗牌的普通样本;净化承认标签具有时间区间,训练和测试可能在未来路径上重叠;禁运进一步承认市场状态不会在测试结束的那一秒消失。组合净化交叉验证,则把单条漂亮曲线拆成多条损益路径,让你看到策略究竟靠什么赚钱,又在哪里被绞杀。
你不需要先把模型换成更深的神经网络,也不需要先堆更多因子。先把每条样本的时间边界钉死,把泄漏的训练观测清出去,把测试后的缓冲期留出来,再去讨论预测算法、深度学习或智能投顾。
账户不会因为你的回测报告写得漂亮而手下留情。时间切分错了,模型再聪明也只是提前偷看答案;净化和禁运没做好,下一次被扫损的不是曲线,是你的本金。
Related reading: 金融时间序列的交叉验证:如何用清洗与禁运防止量化模型过拟合 and 数据清洗中的前瞻偏差:明日策略回测前必须排查的三个数据陷阱.
