第十五章:稳健性检验
参数调优做到这一步,你可能会觉得:嗯,回测曲线挺漂亮,夏普比率也不错。但我要泼一盆冷水——这很可能只是过拟合的假象。
我见过太多交易员,拿着回测漂亮的参数直接上实盘,结果亏得怀疑人生。为什么?因为市场环境一变,那些参数就失效了。所以,稳健性检验不是可选项,是必选项。
参数敏感性分析
说白了,就是看看你的参数稍微动一动,策略表现会不会崩。
我个人习惯的做法是:把每个参数在最优值附近±10%、±20%的范围里跑一遍,观察收益曲线的变化。如果稍微调一点就大幅亏损,那这个参数就是「脆弱的」。
核心指标:参数敏感度系数 = (策略收益变化率) / (参数变化率)
系数越小,说明参数越鲁棒。
举个例子,我做过一个基差交易策略,参数是「开仓阈值=2.5倍标准差」。当我把它调到2.3和2.7时,年化收益从18%掉到了5%。这说明这个参数太敏感了,实盘中很容易出问题。
我的经验:对于敏感参数,可以考虑用参数区间替代固定值。比如不设死板的2.5,而是设一个2.3~2.7的动态区间,根据市场波动自动调整。
蒙特卡洛模拟
这个方法听起来高大上,其实原理很简单:用随机抽样来模拟未来可能出现的各种行情路径。
具体做法是:
- 从历史数据中随机抽取交易样本(有放回)
- 用这些样本重新跑策略
- 重复1000次以上
- 看收益分布是否稳定
import numpy as np
def monte_carlo_simulation(strategy_returns, n_simulations=1000):
"""
蒙特卡洛模拟策略收益分布
"""
results = []
n_samples = len(strategy_returns)
for i in range(n_simulations):
# 有放回抽样
sample = np.random.choice(strategy_returns, size=n_samples, replace=True)
# 计算累计收益
cum_return = np.prod(1 + sample) - 1
results.append(cum_return)
# 计算95%置信区间
lower = np.percentile(results, 2.5)
upper = np.percentile(results, 97.5)
return lower, upper, results
我曾经用这个方法检验过一个参数组合,发现虽然平均收益不错,但最差的5%情景下亏损超过40%。这个风险我承受不了,果断放弃了那组参数。
注意:蒙特卡洛模拟假设历史会重演,但极端行情(比如2020年原油负价格)可能从未出现过。所以它不能替代压力测试。
压力测试
压力测试就是故意挑最恶劣的市场环境来考验策略。我一般会选几个典型场景:
- 2008年金融危机:流动性枯竭,基差剧烈波动
- 2015年股灾:连续跌停,无法平仓
- 2020年疫情:开盘即跌停,基差瞬间拉大
- 2022年俄乌冲突:地缘政治风险,商品价格暴涨暴跌
把这些极端行情的数据单独拎出来,看看策略在其中的表现。如果最大回撤超过你能承受的范围,那就得重新考虑参数了。
我的标准:压力测试下的最大回撤不能超过正常回撤的3倍。超过这个数,说明策略在极端行情下会失控。
不同市场环境下的表现
市场环境不是一成不变的。牛市、熊市、震荡市、趋势市,策略表现可能天差地别。
我习惯把历史数据分成几个阶段:
| 市场环境 | 特征 | 策略表现要求 |
|---|---|---|
| 趋势市 | 单边上涨或下跌 | 年化收益>15% |
| 震荡市 | 价格在区间内波动 | 夏普比率>1.5 |
| 高波动市 | 波动率>30% | 最大回撤<10% |
| 低波动市 | 波动率<15% | 胜率>60% |
如果一个策略只在牛市里赚钱,熊市里就亏成狗,那它就不是好策略。真正稳健的策略,应该能在各种环境下都活得下去。
避坑指南:我曾经有一个策略,在2017-2019年表现极好,但2020年3月那波暴跌中直接爆仓。后来复盘发现,那三年是低波动环境,策略参数完全没考虑高波动情况。从那以后,我每个策略都必须通过至少3种市场环境的检验。
参数鲁棒性评估
最后,把所有检验结果综合起来,给参数打个分。我自己的评分体系是这样的:
- 参数敏感性:±10%范围内收益波动<20% → 10分
- 蒙特卡洛模拟:95%置信区间不包含负收益 → 10分
- 压力测试:所有极端行情下最大回撤<20% → 10分
- 多环境表现:至少3种环境下收益为正 → 10分
总分40分,低于30分的参数组合直接淘汰。别心疼,淘汰掉一个脆弱的参数,可能救你一命。
记住:回测是历史,实盘是未来。稳健性检验就是给策略买一份「保险」。虽然不能保证100%不出问题,但至少能让你在暴风雨来临时,不至于裸奔。