AI 生成的策略过度拟合吗?看 AI 如何解决过度拟合

✍️ 听雨量化 ·

AI 生成的策略过度拟合吗?看 AI 如何解决过度拟合

上一篇文章发出去之后,大家肯定有这样的疑问:

策略跑了 110 轮进化,试了 420 次参数组合,最后选出夏普 1.33 的那一版。这难道不是过度拟合吗?100 多轮挑出来的最优解,不就是在历史数据上凑答案?

做策略,就是在过度拟合以及欠拟合之间来寻找一个平衡。

110 轮迭代,每轮都在调整参数、加机制、删机制,最后留下来的肯定是历史表现最好的那一组——这正是过度拟合的定义。一个在历史上表现完美的策略,到了未来很可能直接崩盘。

所以这一天我没有继续让 AI 跑进化。我让它做了一件相反的事:如何解决自己策略的过度拟合呢?


1. 什么是过度拟合,为什么 R110-R112 可疑

先说清楚过度拟合长什么样。

最典型的信号是:策略在样本内(in-sample,IS)表现极好,但在样本外(out-of-sample,OOS)断崖式下跌。好比一个学生背过真题集,模拟考满分,但真考换了题就懵了。

量化里,这种”只对历史有效”的策略有几个具体特征:

  • 夏普的尖峰:参数稍微动一下,夏普就暴跌(说明最优值是个针尖,不是平台)
  • 依赖少数年份:总收益靠某一两年的时间窗口撑着,其他时间平平甚至亏损
  • 只适配一种行情:趋势行情赚得盆满钵满,震荡行情全还回去
  • IS/OOS 严重分裂:2018 年之前的训练数据上跑得飞起,2018 年之后实战就拉胯

我最担心的是 R110、R111、R112 这三轮。当时 AI 在 R102(即上一篇文章最终选出的那版 baseline)的基础上试了好几个加料版本:

  • R110 加了 Donchian 突破入场,夏普从 1.33 掉到 0.11
  • R111 加了 breakeven 移动止损,夏普掉到 1.02
  • R112 加了金字塔加仓,收益涨了但夏普掉到 1.10

这些是失败实验,看起来没问题——但反过来想:如果这版策略是一个坚实的最优解,为什么周围这么多变种都崩了?是不是它本身就站在悬崖边上?

这个问题必须用数据回答,不能凭感觉。


2. 解决思路:不是加更多机制,而是交叉验证

很多人一听到”过度拟合”,第一反应是”加更多 ML”、“加正则化”、“换更复杂的模型”。

这恰恰是错的方向。

过度拟合的本质,是你在一组数据上反复试错,最后挑出最适配这组数据的参数。解决方法不是让模型更复杂,而是从多个独立维度去验证:这个”最优”是不是只在特定条件下成立。

具体到我这次做的事情,是让 AI 跑了一套 4 维度的交叉验证:

维度问的问题通过标准
Walk-Forward用前半段训练、后半段测试,性能保留多少?OOS/IS ≥ 0.6
逐年一致性是不是只靠少数年份拉均值?≥ 6 个 OOS 年正收益
参数微扰参数稍微偏一点,策略会不会崩?相邻 Sharpe 差 < 10%
Regime 分解是不是只适配某一种行情?≥ 3 个 regime 都盈利

关键设计:这 4 个维度相互独立,任何一个维度的”作弊”都逃不过另一个维度。

  • 你可以在 Walk-Forward 上作弊(比如故意选了一个 OOS 表现好的参数),但你逃不过参数微扰——参数稍微动一下就会暴露
  • 你可以靠少数年份拉高平均值,但你逃不过逐年一致性检查
  • 你可以只适配一种行情,但你逃不过 Regime 分解

这叫defense in depth——多层防御,单层失守不至于全军覆没。


3. 维度一:Walk-Forward——OOS 保留 IS 的 78%

这是最经典也是最严苛的检查。

把数据切成两段:

  • IS(训练集):2010-2017,8 年
  • OOS(测试集):2018-2025,8 年

当前这版的参数是在 2010-2025 全量数据上跑出来的,所以”前半段 vs 后半段”是一个公平的分割——它没机会单独适配某一段。

结果:

段Sharpe
IS 2010-20171.5014
OOS 2018-20251.1732
比值 OOS/IS0.781

Walk-Forward IS vs OOS

0.781 意味着什么?

OOS 完整保留了 IS 78% 的性能。业内一般这么分档:

  • ≥ 0.6:PASS,没有明显过度拟合
  • 0.4 - 0.6:WARN,轻度可疑
  • < 0.4:FAIL,明显过度拟合

0.781 远超 PASS 阈值。这说明它学到的不是”2010-2017 的特例”,而是真实的市场规律——因为同样的规律在它没见过的 2018-2025 上依然成立。

作为对照,一个真正过度拟合的策略,这个比值通常在 0.2-0.4 之间,OOS 会直接腰斩甚至变负。


4. 维度二:逐年 Sharpe——8/9 年正收益

Walk-Forward 只把数据切成两段。但 OOS 的 8 年里,会不会其实是靠某一两个超级好年撑起来的?

所以我让 AI 把 OOS 拆成 9 个年份(2018-2026),单独算每年的 Sharpe:

YearSharpe备注
2018+0.959中性
2019+1.445好
2020-0.682唯一亏损年(COVID 冲击)
2021+1.565好
2022+2.615非常好
2023+1.017中性
2024+0.569弱正
2025+1.618好
2026+0.350弱正(半年)

OOS 逐年 Sharpe

8/9 年正收益。

通过标准是 ≥ 6 年正收益,9 年里 8 年都过关,这是非常强的证据。

但更重要的是 2020 年的亏损。

2020 年 3 月,COVID 引发全球资产恐慌,螺纹钢一周内波动率翻倍。趋势策略在这种波动率冲击下被打止损是正常的——任何趋势策略都会在 2020 年吃瘪。

这里有个非常重要的判断:我看到 2020 年 -0.682 的第一反应是”能不能加个规则把它修掉”。但 AI 给出了相反的结论:

不要修。如果你为了”修复 2020”加一条特殊规则,那才是真正的过度拟合——你在用一个特定年份的事件去雕刻参数。一个能在所有极端行情中都盈利的策略,几乎肯定是过拟合的。

健康的策略有亏损年,是 feature 不是 bug。


5. 维度三:参数微扰——11.1% 的平缓下降

这是最能直接检测”针尖最优”的方法。

固定其他所有参数,只动两个核心参数:

  • st_mult(SuperTrend 倍数):{4.5, 5.0, 5.5}
  • ema_period(趋势 EMA 周期):{155, 162, 170}

跑一个 3×3 的网格,看 Sharpe 在中心点(即当前参数)周围变化有多剧烈:

st_mult \ ema155162170
4.51.1701.1841.100
5.01.325★ 1.3321.246
5.51.2881.2681.200

3x3 参数微扰网格

当前参数在网格中心(★),相邻 8 个点的 Sharpe 全部在 1.10 - 1.33 之间。

通过标准:

  • < 10%:PASS,平缓高原
  • 10-25%:WARN,轻度敏感
  • > 25%:FAIL,悬崖式下降(针尖最优)

中心点的最大相邻差是 11.1%(st_mult 从 5.0 调到 4.5 时 Sharpe 从 1.33 掉到 1.18),落在 WARN 区间。

为什么 WARN 可以接受?

关键看下降形态。如果是悬崖——比如 5.0 时 Sharpe 1.33,4.9 时暴跌到 0.5——那是典型过度拟合。但中心点周围的下降是平缓的:

  • st=5.0 → 4.5:Sharpe 1.33 → 1.18,下降 11%
  • st=5.0 → 5.5:Sharpe 1.33 → 1.27,下降 5%

这意味着当前参数不是站在针尖上,而是站在一个宽阔的高原上——参数往任何方向偏一点,策略都依然有效。这正是反过度拟合最强的证据之一。

11.1% 的 WARN 提醒我们 st_mult 下限稍敏感(下降不对称),如果未来要做敏感性补强可以关注这一点。但这是一个改进方向,不是回退理由。


6. 维度四:Regime 分解——3/3 全盈利

这是我最喜欢的一个维度。

前面三个维度都是在时间维度上切——切 IS/OOS、切年份、切参数。但市场还有另一个独立的切法:按行情类型切。

先说清楚 Regime 在这里扮演什么角色:它不是一个新的策略,也没有改任何参数。它只是一种新的观察视角——把已经跑完的交易,按开仓那一刻市场所处的状态重新分组,看策略在不同类型的行情下是否都赚钱。

具体做法是用 K-Means 聚类,按 ADX 均值、ATR 百分比均值、自相关、波动率四个特征,把 16 年的 60min K 线聚成 3 类:

Regime特征占比标签
0ADX 23.6 / Vol 26.6%50.2%中等趋势
1ADX 34.3 / Vol 27.7% / 自相关 -0.0827.9%高波动震荡
2ADX 27.7 / Vol 58.7%21.9%高波动趋势

然后看当前策略在这 3 个 regime 里的 PnL 贡献:

RegimeTradesTotal PnL
0 中等趋势225+164,990
1 高波动震荡69+40,237
2 高波动趋势71+39,360

Regime 分解

3/3 全部盈利。

通过标准是 ≥ 3 个 regime 盈利,结果 3 个都过关。

这意味着什么?

它不是只适配某一种行情的策略。 当前策略在主导趋势行情(regime 0)赚得最多,在高波动震荡(regime 1)也赚,在高波动趋势(regime 2)也赚。这是一种真正的”普适”特征——它捕捉的是跨行情的某种底层规律,而不是某一段特定历史的巧合。

为了更直观,再看几张 regime 维度的图:

Regime 时间线分布

上图是 16 年里 regime 标签随时间的分布。可以看到,3 个 regime 是交替出现的——没有任何一个 regime 占据绝对主导,也没有任何一个 regime 集中在某一段特定时间。这进一步排除了”策略只适配特定时间段”的可能。

Regime 散点

散点图把每个 trade 按”所在 regime 的波动率”和”实际 PnL”画出来。3 个 regime 的颜色分布在零线以上都明显厚于零线以下——盈利端在所有 regime 中都 extending 到更高的 PnL。


7. 总评:3 PASS + 1 WARN + 0 FAIL

把 4 个维度汇总:

检查结果判定
Walk-Forward OOSOOS/IS = 0.781PASS
逐年 Sharpe8/9 年正收益PASS
参数微扰最大差 11.1%WARN
Regime 分解3/3 regime 盈利PASS

3 PASS + 1 WARN + 0 FAIL → 未过度优化。

这版策略可以作为 production baseline,不必回退或继续调参。

这个结论让我松了一口气,但更让我感兴趣的是过程中的一个反讽发现。


8. 反讽:Meta-Labeling 的失败

在跑这套交叉验证之前,我曾经尝试过另一种”解决过度拟合”的思路——加一层 ML。

思路来自 López de Prado 的《Advances in Financial Machine Learning》。原书的建议是:第一层用简单规则生成信号,第二层用 ML 分类器(通常是 LogReg 或 RF)做”二级过滤”——只在 ML 也认为这是一个好信号的时候才下单。这叫 Meta-Labeling。

理论上这个方法很优雅:

  • 一级信号负责召回(少漏机会)
  • 二级 ML 负责精确(少犯错)
  • 合起来既能抓住机会又能过滤假信号

我用当前策略的 607 笔交易做训练集,提取了 18 个特征(regime id、ADX、ATR%、MACD histogram、EMA 偏离度、连亏次数、距离上次交易的天数、小时、星期、月份……),训练了一个 LogReg + StandardScaler 的 pipeline。

离线 cross-validation 看起来很美:

  • Precision 0.73,Recall 0.68
  • 阈值 0.40 时”看起来”能保留 72.8% 的 PnL,过滤掉大部分亏损交易

然后我把它叠到原策略上做 walk-forward 实测。结果直接打脸:

变体SharpeMaxDD
R102 baseline1.33219.10%
R102 + Meta (thr=0.30)1.29598.67%
R102 + Meta (thr=0.40)0.8512.5%

Meta-Labeling 失败

thr=0.30:Sharpe 略降(1.33→1.30),MaxDD 略改善(9.10%→8.67%)。算是平局,但没有明显提升。

thr=0.40(离线 sweep 的”最优”):Sharpe 暴跌到 0.85,MaxDD 反而恶化到 12.5%。离线训练时的”最优阈值”在实战中直接崩了。

为什么会这样?复盘之后发现了几个问题:

1. 离线 sweep 高估了 72.8% 的 PnL 保留率,实际只保留了 83%

离线评估时,我们假设”如果 ML 拒绝了信号,那笔交易就真的不会发生”。但实战中,ML 拒绝信号 → 仓位为 0 → 下一根 bar SuperTrend 还在那个位置 → 同样的信号再次触发 → ML 再判断一次。

结果就是:filter 实际被调用了 1.67 倍(607 笔交易,但 ML 被触发了 1013 次)。原本该过滤掉的”坏信号”,有相当一部分在下一根 bar 重新进入并被放行了。

2. 训练集和测试集的 label 分布漂移

训练集(2010-2017)里”赢的交易”占 64%,但 OOS(2018-2025)由于 2020 年的 COVID 冲击,赢的交易占比下降到 58%。LogReg 学到的”先验概率”在 OOS 上是有偏的。

3. 阈值越严越过度自信

离线 sweep 说 thr=0.40 最好。但 0.40 在 OOS 上意味着——ML 必须非常确信才放行,而 ML 在 OOS 上本来就不够确信(分布漂移),所以大量本该抓住的机会被错杀。

这个反讽让我对”解决过度拟合”这件事有了新的理解:

加复杂度不等于减少过度拟合。 有时候,加一层 ML 反而引入了新的过度拟合源——你在训练集上挑了一个”最优阈值”,但这个阈值本身就是对训练集的 curve-fit。

简单胜过复杂。 这版策略不用 ML,规则透明(SuperTrend + EMA + ADX + MACD + Partial TP),每一行都有经济学解释。它的”反过度拟合”证据来自 4 个独立维度的交叉验证,而不是又一个 ML 模型的 metrics。


9. 那么现在的最终策略是什么样

经过这一轮验证,这版策略的所有参数都没有改动。最终交付的还是上一篇文章里那个策略:

参数值
atr_period14
st_mult5.0
ema_period162
adx_threshold25.0
macd_filter14 / 30 / 6
partial_tp4.5×ATR / 90%
trail_mult6.0
risk_percent0.3%
max_hold_bars210
cooldown_bars75

16 年实测指标:

指标值
Sharpe1.3321
Sortino1.9093
Total Return+244.80%
Max Drawdown9.10%
Win Rate64.4%
Profit Factor2.26
年正收益16/17
最差年份-3.2% (2020)

净值曲线和回撤与上一篇一致,这里不再重复贴图。唯一不同的是:这次我们有 4 维度交叉验证的证据,证明这组数字不是过度拟合的产物。


10. 这次实验真正说明的事

这次做的事情,本质上是让 AI 证明自己的工作不是 curve-fit。

我没有给它新的优化目标,没有让它继续进化。我给它的是 4 个独立的检验维度,每个维度都有明确的 PASS/WARN/FAIL 标准,没有任何调整空间。

它做出来的不是又一个”看起来更好”的策略,而是一份证据链:

  • 用 Walk-Forward 证明:策略在没见过的数据上依然有效
  • 用逐年 Sharpe 证明:不是靠少数年份拉均值
  • 用参数微扰证明:策略站在宽阔高原上,不是针尖
  • 用 Regime 分解证明:不依赖单一行情类型

更重要的是,这套验证本身是可以复现的——任何人拿到策略代码和这 4 个检查脚本,都能跑出同样的结论。这不是观点,是数据。


11. 我从这次实验中学到的事

1. 验证比优化更难,但也更重要

让 AI 跑 110 轮进化很容易,写一个指令就行。但要设计一套严谨的、能排除作弊的交叉验证体系,需要真正想清楚”过度拟合有几种可能的伪装形式”。

这个过程让我意识到:优化是体力活,验证是脑力活。 AI 可以承担前者,但后者目前还是人的核心价值。

2. 加复杂度 ≠ 减少过度拟合

这是 Meta-Labeling 失败给我的最大教训。直觉上”加 ML 应该更鲁棒”,但实际上 ML 模型本身就会引入新的过度拟合源(训练集偏差、阈值选择、分布漂移)。

简单透明的规则 + 严谨的交叉验证 > 复杂黑盒模型 + 自我吹捧的 metrics。

3. WARN 不是失败,是改进方向

策略在参数微扰维度上是 WARN(11.1%),但这不意味着策略不可信。它意味着 st_mult 下限稍敏感——这是一个可操作的改进方向,而不是一个回退理由。

完美的 plateau 是过拟合的另一种伪装。 一个真实有效的策略,总会在某个维度上有”敏感点”——因为真实市场的规律不会完美适配任何参数。

4. 健康的策略有亏损年

2020 年的 -3.2% 是这版策略健康的标志。如果有人给你看一个 16 年零亏损的策略,你应该扭头就走——那 100% 是过度拟合。


12. 下一步

这版策略现在是一个经过验证的 production baseline。我不打算继续动它的参数——动得越多,过度拟合的风险越大。

接下来的工作不在策略本身,而在它没回答的问题:

  • 多品种验证:当前策略在 RB88(螺纹钢)上有效。在铁矿石、焦炭、沪铜等其他趋势品种上呢?这是必须做的下一步——一个只在单一品种上有效的策略依然有过度拟合嫌疑。
  • 交易成本敏感性:现在的回测用的是合约默认手续费 + 滑点。如果把滑点放大 2 倍、3 倍,策略还赚钱吗?
  • 参数稳定性时间维度:现有参数是在 16 年全量数据上挑出来的。如果只用 2010-2015 训练,参数会落在哪?跟现在这版接近吗?

这些问题的答案,决定了它是一个”经过验证的趋势策略”,还是一个”经过深度验证的趋势策略”。

但我现在可以说的是:至少它不是 R110、R112 那种站在悬崖边上的”最优”。它站在一个宽阔的高原上。

这就是这次实验想要证明的事。


参考资料

  • 第一篇:一行代码不写,AI 自己进化出夏普 1.33 的策略
  • 回测引擎:PowerQuant Backtest(Rust 实现,已开源)
  • 验证维度:Walk-Forward / 逐年 Sharpe / 参数微扰 / Regime 分解(K-Means)
  • Meta-Labeling 参考:López de Prado, Advances in Financial Machine Learning(实测在本策略上失败)
  • 数据:RB88 螺纹钢连续主力,60min K 线,2010-2026
  • 结论:3 PASS + 1 WARN + 0 FAIL,当前策略未过度优化,可作为 production baseline