第四节:回测框架搭建陷阱——过拟合、多重假设检验、样本外测试不足、交易成本忽略

做量化交易这些年,我见过太多人栽在回测框架上。说实话,回测本身并不难,难的是你搭建的框架能不能真实反映未来表现。今天咱们就聊聊四个最常见的陷阱,每一个我都踩过坑。

4.1 过拟合:你拟合的是历史,不是未来

过拟合是什么?说白了,就是你让模型把历史数据里的噪音也学进去了。我有个朋友,花了三个月优化一个均线策略,参数调了上百组,回测曲线漂亮得像教科书。结果实盘第一周就亏了8%。

为什么会这样?因为他把参数调到了刚好匹配过去五年的每一个波动。你想想看,市场不会重复历史,它只会重复人性。

过拟合的典型症状:

  • 回测夏普比率 > 3.0(实盘能到1.5就烧高香了)
  • 参数稍微变一点,收益就大幅波动
  • 策略在特定时间段表现异常好

我个人习惯的做法是:参数稳定性测试。把参数在合理范围内随机扰动,看策略表现是否稳健。如果稍微动一下参数就崩了,那这个策略大概率是废的。

# 参数稳定性测试示例
import numpy as np

def parameter_stability_test(strategy, param_ranges, n_tests=100):
    results = []
    for _ in range(n_tests):
        # 在参数范围内随机采样
        params = {k: np.random.uniform(v[0], v[1]) 
                  for k, v in param_ranges.items()}
        sharpe = strategy.backtest(**params)
        results.append(sharpe)
    
    # 检查夏普比率的稳定性
    std_sharpe = np.std(results)
    mean_sharpe = np.mean(results)
    
    if std_sharpe / mean_sharpe > 0.3:
        print("警告:参数敏感度过高,可能存在过拟合")
    return results

4.2 多重假设检验:你测试了100个策略,总有一个看起来不错

这个陷阱特别隐蔽。你同时测试了50个不同的策略参数组合,其中总会有几个表现不错的——哪怕它们完全是随机生成的。

我记得有一次帮一个团队做策略评审,他们兴奋地展示了一个年化收益40%的策略。我问他们测试了多少个变体,回答是200多个。嗯,这就有问题了。

多重假设检验的校正方法:

  • Bonferroni校正:将显著性水平除以测试次数。比如你测了100个策略,原本p值要小于0.05,现在要小于0.0005
  • FDR控制:允许一定比例的假阳性,比Bonferroni更宽松一些
  • 交叉验证:把数据分成K份,轮流用K-1份训练、1份验证

我曾经犯过一个错误:在开发一个因子模型时,测试了300多个候选因子,最后选了20个表现最好的。结果实盘一塌糊涂。后来我才意识到,这20个因子里可能有一半都是噪音。

4.3 样本外测试不足:你的策略只会在历史数据上赚钱

样本内测试做得好,不代表样本外也能赚钱。这个道理大家都懂,但执行起来往往打折扣。

我建议的划分方式是这样的:

数据用途 占比 说明
训练集 60% 用于策略开发和参数优化
验证集 20% 用于参数调优和模型选择
测试集 20% 最终评估,只能使用一次

这里有个关键点:测试集只能使用一次。如果你在测试集上表现不好,回去调整参数再测一次,那测试集就变成了验证集,你的样本外测试就失效了。

避坑指南:我曾经在测试集上反复测试同一个策略,每次调整一点点参数,直到测试集表现完美。结果实盘亏得很惨。后来我学乖了:测试集就是用来做最终判决的,测完就封存,绝不再碰。

4.4 交易成本忽略:你以为赚了,其实亏了

这是新手最容易忽略的问题。回测里年化收益20%,加上交易成本可能只剩5%,甚至变成负的。

交易成本包括哪些?

  • 佣金:每笔交易的手续费
  • 滑点:实际成交价和预期价格之间的差异
  • 冲击成本:大单交易时对市场价格的冲击
  • 印花税:某些市场特有的税费

我个人习惯的做法是:在回测中至少加上双边千分之二的交易成本。如果是高频策略,这个数字还要更高。

# 交易成本模拟
def simulate_trading_cost(trade_size, price, cost_rate=0.002):
    """
    trade_size: 交易数量
    price: 成交价格
    cost_rate: 交易成本率(默认千分之二)
    """
    cost = trade_size * price * cost_rate
    # 考虑滑点:假设滑点为0.1%
    slippage = trade_size * price * 0.001
    total_cost = cost + slippage
    return total_cost

你想想看,如果一个策略每天交易10次,每次成本千分之二,一年250个交易日,光交易成本就吃掉100%的收益。所以,交易频率越高,对交易成本越敏感

知识体系总览

下面这张图总结了回测框架搭建的四个核心陷阱及其应对方法:

回测框架搭建四大陷阱 回测框架 过拟合 参数调优过度 多重假设检验 统计显著性失真 样本外测试不足 数据划分不合理 交易成本忽略 成本估算不足 应对方案 参数稳定性测试 随机扰动参数 检查夏普比率波动 统计校正 Bonferroni校正 FDR控制 严格数据划分 60/20/20划分 测试集仅用一次 成本模拟 双边千分之二 考虑滑点冲击 核心原则:回测是工具,不是预言 永远假设你的策略在实盘中会表现更差

这四个陷阱,每一个都能让你的回测结果和实盘表现天差地别。我见过太多人在这上面栽跟头,包括我自己。记住一句话:回测是工具,不是预言。永远假设你的策略在实盘中会表现更差,然后留足安全边际。

本章核心要点:

  1. 过拟合:用参数稳定性测试来检验
  2. 多重假设检验:用统计校正方法控制假阳性
  3. 样本外测试不足:严格划分数据,测试集只用一次
  4. 交易成本忽略:至少加双边千分之二的成本

公众号:蓝海资料掘金营,微信deep3321