2. 参数调优概述:为什么参数调优如此重要?过拟合与欠拟合的平衡
做量化交易这几年,我见过太多人把策略写出来就跑,参数随便设几个,然后就开始幻想躺赚。嗯,现实往往很打脸。参数调优这件事,说白了就是给你的策略「找感觉」——找到那个既能赚钱又不会翻车的平衡点。
我个人习惯把参数调优比作「调琴」。弦太紧,一弹就断;弦太松,声音发闷。你想想看,量化策略的参数不也是这个道理吗?
为什么参数调优如此重要?
先讲个我自己的经历。几年前我做了一个简单的双均线策略,参数设的是5日和20日。回测结果漂亮得吓人,年化收益40%,最大回撤不到5%。我当时差点就准备实盘了。还好多留了个心眼,换了个时间段重新跑了一遍——结果收益直接变成负的。
为什么会这样?因为那组参数恰好「拟合」了历史数据中的噪声,而不是真正的市场规律。这就是参数调优要解决的核心问题。
参数调优的重要性,我总结为三点:
- 提升策略的鲁棒性:好的参数能让策略在不同市场环境下都表现稳定,而不是只在某一段行情里有效
- 避免「运气成分」:你看到的漂亮回测曲线,可能只是参数恰好踩中了历史数据的某个巧合
- 找到真正的信号:参数调优的本质,是从噪声中分离出有统计意义的交易信号
核心观点:参数调优不是让回测曲线更好看,而是让策略在实盘中更可靠。这两者有时候是矛盾的。
过拟合与欠拟合:一对冤家
这两个概念其实不复杂。我试着用大白话讲清楚。
过拟合,就是策略太「聪明」了,把历史数据里的每一个小波动都当成了规律。结果一到实盘,市场稍微变个花样,策略就懵了。
欠拟合,就是策略太「笨」了,连明显的规律都没抓住。回测表现平平,实盘也好不到哪去。
我曾经犯过一个典型的过拟合错误。当时为了追求高夏普比率,我把一个趋势跟踪策略的参数从3个增加到了8个,还加了一堆过滤条件。回测曲线确实漂亮,但实盘第一天就亏了2%。后来复盘发现,那8个参数里有5个都是在「解释」某一段特定行情的噪声。
避坑指南:我曾经见过有人用20个参数去拟合3年的日线数据,结果夏普比率做到了5.0。这种策略,说白了就是「看图说话」——把历史数据背下来了,但根本没学会交易。
如何找到那个平衡点?
这里我分享几个实战中总结的方法:
- 参数数量控制:我个人建议,一个策略的参数不要超过5个。每增加一个参数,过拟合的风险就翻一倍。
- 样本外测试:把数据分成训练集和测试集。在训练集上调参数,在测试集上验证。如果测试集表现明显差于训练集,那就是过拟合的信号。
- 参数稳定性分析:画一张参数热力图,看看收益对参数变化的敏感度。如果参数稍微变一点,收益就剧烈波动,那这个策略大概率是过拟合的。
小技巧:我习惯在调参时故意把参数设得「丑」一点——比如均线周期用17和43,而不是20和50。如果策略在「丑」参数下还能赚钱,那说明它抓住了真正的规律。
一张图看懂参数调优的核心逻辑
下面这张图是我自己总结的,把参数调优的整个流程串起来了:
从这张图可以看得很清楚:参数调优就是在过拟合和欠拟合之间找平衡。左边是过拟合,右边是欠拟合,中间那个绿色的「平衡点」才是我们想要的。
实战中的判断标准
说了这么多理论,到底怎么判断自己的参数调优有没有做好?我列几个实际可用的标准:
| 判断维度 | 过拟合信号 | 欠拟合信号 | 健康状态 |
|---|---|---|---|
| 样本外表现 | 明显差于样本内 | 样本内外都差 | 两者接近 |
| 参数敏感度 | 微小变化导致收益剧烈波动 | 参数变化几乎不影响结果 | 参数在一定范围内表现稳定 |
| 策略复杂度 | 参数多、规则复杂 | 参数太少、规则过于简单 | 参数数量适中(3-5个) |
| 不同时间段 | 只在某一段行情有效 | 所有时间段都平庸 | 多数时间段表现一致 |
我的经验:如果你发现策略在2018年熊市和2020年牛市都表现不错,那大概率是找到了真正的规律。如果只在2020年3月那波暴跌中赚钱,嗯...那可能就是运气。
一个简单的代码示例
最后,我写一段简单的代码,演示一下参数调优的基本思路。这里用的是双均线策略,参数是短周期和长周期:
# 一个简单的参数调优示例
import numpy as np
import pandas as pd
def backtest_strategy(data, short_window, long_window):
"""
双均线策略回测
short_window: 短周期
long_window: 长周期
"""
signals = pd.DataFrame(index=data.index)
signals['signal'] = 0.0
# 计算均线
signals['short_ma'] = data['close'].rolling(window=short_window).mean()
signals['long_ma'] = data['close'].rolling(window=long_window).mean()
# 生成信号
signals['signal'][short_window:] = np.where(
signals['short_ma'][short_window:] > signals['long_ma'][short_window:], 1.0, 0.0
)
# 计算收益
signals['returns'] = data['close'].pct_change()
signals['strategy_returns'] = signals['signal'].shift(1) * signals['returns']
return signals['strategy_returns'].sum()
# 参数网格搜索
short_params = range(5, 30, 5)
long_params = range(20, 100, 10)
best_sharpe = -np.inf
best_params = None
for short in short_params:
for long in long_params:
if short >= long:
continue
ret = backtest_strategy(data, short, long)
if ret > best_sharpe:
best_sharpe = ret
best_params = (short, long)
print(f"最优参数: 短周期={best_params[0]}, 长周期={best_params[1]}")
print(f"最优收益: {best_sharpe:.4f}")
注意:这段代码只是演示思路。实际调优时,你还需要考虑交易成本、滑点、样本外验证等因素。我习惯在网格搜索之后,再用随机参数跑一遍,看看最优参数附近的表现是否稳定。
好了,参数调优的重要性就讲到这里。说白了,这就是一个「过犹不及」的哲学问题——参数太少抓不住机会,参数太多又容易掉进噪声的陷阱。找到那个平衡点,你的策略才算真正「活」了。
公众号:蓝海资料掘金营,微信deep3321