第28章 模型评估与回测:联动模型的回测框架、夏普比率、最大回撤等评估指标
模型做完了,参数调好了,接下来呢?
说实话,很多人在这一步就急着上线实盘了。我见过太多这样的案例——回测没跑明白,直接扔进实盘,结果一个月亏掉半年的利润。嗯,咱们今天就把回测这件事聊透。
回测框架:你得有个靠谱的“时光机”
回测说白了,就是用历史数据模拟交易。但这里有个坑:你模拟的越真实,结果越可信。我个人习惯把回测框架分成三层:
- 数据层:处理原始行情、宏观数据、波动率曲面数据
- 策略层:执行交易逻辑,生成信号
- 评估层:计算绩效指标,生成报告
我曾经犯过一个低级错误——回测时用了未来数据。当时波动率曲面数据里混入了第二天的隐含波动率,结果回测夏普高达3.5,实盘直接翻车。从那以后,我每次回测前都会做一次数据泄露检查。
核心原则:回测框架必须保证数据的时间顺序严格正确。任何“穿越”行为都会让你的回测变成笑话。
下面是一个简单的回测框架伪代码,我习惯用Python实现:
class BacktestEngine:
def __init__(self, data, strategy, initial_capital=1_000_000):
self.data = data # 包含波动率曲面、宏观指标
self.strategy = strategy
self.capital = initial_capital
self.positions = []
self.trades = []
def run(self):
for i in range(len(self.data)):
# 获取当前时刻的数据
current_data = self.data.iloc[:i+1]
# 生成交易信号
signal = self.strategy.generate_signal(current_data)
# 执行交易
self.execute_trade(signal, current_data.iloc[-1])
# 计算绩效
return self.evaluate_performance()
你想想看,这个框架最核心的是什么?是current_data = self.data.iloc[:i+1]这一行。它保证了每次决策时,只能看到截止到当前时刻的数据。很多新手会写成self.data.iloc[:i+2],多取了一行,结果就变成了“预知未来”。
夏普比率:最熟悉的陌生人
夏普比率,量化圈没人不知道。但你真的理解它吗?
公式很简单:Sharpe = (Rp - Rf) / σp
其中Rp是策略收益率,Rf是无风险利率,σp是收益率标准差。
我个人习惯用年化夏普,这样不同策略之间才好比较。但这里有个细节:计算标准差时,用日收益率还是周收益率?
我在项目中遇到过这样的情况:一个高频策略,日收益率夏普2.0,但换成周收益率夏普只有0.8。为什么?因为高频策略的日收益率波动大,但周收益率波动更大——持仓周期和计算周期不匹配。
我的建议:计算夏普时,收益率频率要和策略持仓周期匹配。日内策略用分钟级,日频策略用日级,周频策略用周级。别偷懒直接用日收益率算所有策略。
还有一个坑:夏普比率对异常值极其敏感。我记得有一次回测,某天因为数据错误产生了+50%的收益,夏普直接飙到5.0。后来修复数据后,夏普掉到1.2。所以,回测前一定要做数据清洗。
| 夏普比率范围 | 评价 | 我的经验 |
|---|---|---|
| < 0.5 | 较差 | 基本不值得实盘 |
| 0.5 - 1.0 | 一般 | 需要结合其他指标看 |
| 1.0 - 2.0 | 良好 | 可以考虑实盘 |
| 2.0 - 3.0 | 优秀 | 但小心过拟合 |
| > 3.0 | 可疑 | 大概率是数据泄露或过拟合 |
最大回撤:你的心脏能承受多少?
最大回撤,就是策略从最高点到最低点的最大跌幅。说白了,就是最惨的时候亏了多少。
公式:Max Drawdown = max(1 - 当前净值 / 历史最高净值)
嗯,这里要注意:最大回撤只看绝对值,不看时间跨度。一个策略可能回撤20%用了3个月,另一个策略回撤20%用了3天。虽然最大回撤一样,但体验天差地别。
避坑指南:我曾经设计过一个波动率套利策略,回测最大回撤只有5%,但实盘时连续回撤了6个月。为什么?因为回测期间市场环境单一,没有覆盖到极端行情。所以,回测时要刻意加入压力测试场景,比如2020年3月的流动性危机。
我个人习惯用回撤恢复时间作为辅助指标。如果一个策略回撤后需要2年以上才能恢复,那它的实际风险远大于最大回撤本身。
其他关键指标:别只看夏普和回撤
光看夏普和最大回撤,就像只看一个人的身高和体重——太片面了。我一般还会看这几个:
- 卡玛比率:年化收益率 / 最大回撤。我个人觉得这个比夏普更直观,直接告诉你每承担1%的回撤能换来多少收益。
- 胜率:盈利交易次数 / 总交易次数。但别迷信高胜率,我见过胜率70%但亏钱的策略——因为亏一次就把前面赚的全吐回去了。
- 盈亏比:平均盈利 / 平均亏损。这个和胜率要一起看。胜率30%但盈亏比5:1的策略,长期来看比胜率70%但盈亏比1:1的策略更赚钱。
- 索提诺比率:和夏普类似,但只考虑下行波动。对于波动率曲面策略来说,这个指标更合理——因为我们只关心亏损的波动,不关心盈利的波动。
联动模型的特殊评估:宏观数据的影响
咱们做的是波动率曲面与宏观数据的联动模型,所以评估时还要多考虑一层:宏观因子对策略表现的解释力。
我习惯做这样一个分析:把回测期间的宏观数据(比如利率、通胀、PMI)作为自变量,策略每日收益作为因变量,跑一个回归。如果R²很高,说明策略收益很大程度上被宏观因素驱动。这本身不是坏事,但你要问自己:如果宏观环境变了,策略还能赚钱吗?
举个例子,我记得2022年美联储加息期间,很多依赖低利率环境的波动率策略都崩了。回测时这些策略表现很好,但实盘时宏观环境一变,直接失效。
我的做法:在回测框架中加入“宏观情景分析”。把历史数据按宏观状态分成几类(加息周期、降息周期、震荡期),分别计算每个状态下的夏普和回撤。如果某个状态下的表现明显差于其他状态,那就要警惕了。
回测的终极问题:过拟合
说实话,回测最大的敌人不是数据质量,不是计算效率,而是过拟合。
你想想看,一个策略有10个参数,每个参数试5个值,那就是5¹⁰ ≈ 976万种组合。总有一种组合在回测里表现完美。但实盘呢?大概率翻车。
我常用的防过拟合方法:
- 交叉验证:把数据分成多段,轮流做训练集和测试集。别只用一段数据来回测。
- 参数稳定性测试:最优参数附近微调,看策略表现是否剧烈变化。如果参数稍微一变就崩,那说明过拟合了。
- 样本外测试:留出最后20%的数据完全不参与调参,只在最后做一次验证。如果样本外表现和样本内差距很大,那就要重新审视策略了。
一个小技巧:我习惯在回测报告中加入“随机策略对比”。生成1000个随机交易信号,计算它们的夏普分布。如果你的策略夏普在分布中排在前5%,那才说明真的有alpha。否则,可能只是运气好。
回测报告:让结果说话
最后,所有指标都要汇总成一份报告。我一般会包含以下内容:
- 策略基本信息(名称、时间范围、交易频率)
- 绩效指标表(夏普、最大回撤、卡玛、胜率、盈亏比等)
- 净值曲线图(标注最大回撤区间)
- 月度收益率热力图
- 宏观情景分析结果
- 参数敏感性分析
- 样本外测试结果
嗯,到这里,回测框架和评估指标就讲完了。记住一句话:回测的目的是发现策略的弱点,而不是证明策略的完美。如果你回测结果完美无瑕,那大概率是哪里出了问题。