matters
V2EX  ›  投资

如何判断一个策略只是过拟合?

  •  
  •   matters · 16h 36m ago · 305 views

    “回测收益高”是最容易骗人的指标。一个策略回测年化 50%,最大回撤 10%,Sharpe 2+,看起来非常漂亮。但如果把它拿到真实市场里跑,可能很快就发现完全不是那么回事。想分享一下我目前判断策略是否过拟合的一些方法。

    1. 先把训练集和测试集分开

    比如我有 2018 ~ 2025 年的历史数据,不能直接拿全部数据调参数,然后说这个策略在 2018 ~ 2025 年表现很好。因为策略参数本身就是根据这些数据调出来的。我一般会先分成:

    • 2018 - 2022:训练集
    • 2023 - 2024:验证集
    • 2025:测试集

    训练集用来开发策略和调参数。验证集用来检查策略是不是还能工作。测试集最好完全不碰,最后才拿出来做一次真正的 out-of-sample test 。 如果一个策略在训练集表现特别好,但到了验证集和测试集突然失效,我一般就会开始怀疑过拟合。

    2. 参数稍微变化,策略就完全失效?

    比如我做一个均线策略:

    • fast_ma = 20
    • slow_ma = 60

    回测结果很好。 然后我把参数稍微改一下:

    • fast_ma = 19, slow_ma = 60
    • fast_ma = 21, slow_ma = 60
    • fast_ma = 20, slow_ma = 59
    • fast_ma = 20, slow_ma = 61

    如果结果都差不多,我会觉得这个策略可能找到了某种比较稳定的市场规律。但如果:

    • 20 / 60 → 年化 45%
    • 19 / 60 → 年化 5%
    • 21 / 60 → 亏损
    • 20 / 59 → 亏损
    • 20 / 61 → 亏损

    这种情况我就会比较警惕。因为这很可能不是策略本身有效,而是参数刚好“撞上”了历史数据中的某个特殊模式。所以我现在倾向看参数附近的 performance surface 。一个真正有一定 robustness 的策略,通常不会只有一个孤立的最优点,而应该是一片相对稳定的区域。

    3. 换一个市场还能不能跑?

    比如我做的是一个美股策略。如果策略只在 SPY 上表现很好,我会尝试 SPY 、QQQ 、IWM 、DIA ,甚至换成其他市场。 当然,不是说一个策略必须在所有市场都赚钱。如果策略背后的逻辑是合理的,那么通常应该能够解释, 为什么它在这个市场有效。 如果只是“我在 SPY 上测试了 1000 组参数,最后发现这一组最好”,那我会觉得这个结果的可信度比较低。

    4. 用 Monte Carlo 看看是不是太依赖某几笔交易

    有些策略回测收益非常高,但仔细看发现,总收益的 70%来自 3 笔交易。这种策略我也会比较担心。我一般会尝试对交易顺序、收益序列做 Monte Carlo simulation 。例如原来的交易结果是:

    • +5%
    • -1%
    • +2%
    • -1%
    • +20%
    • -2%
    • +3%

    我可以随机打乱交易顺序,重复跑很多次。然后观察:

    • Median CAGR
    • 5% worst CAGR
    • 95% best CAGR
    • Max Drawdown distribution
    • Probability of ruin

    如果随机后的结果和原始结果差别非常大,说明策略可能比较依赖特定的交易顺序。这不一定意味着策略过拟合,但至少说明风险可能比回测结果看起来更高。

    5. 不要只看收益率

    除了看年化收益率、夏普比率、最大回撤,我还会看:

    • 交易次数
    • 胜率
    • 盈利因子
    • 单笔平均收益
    • 平均持仓时间
    • 换手率
    • 年度收益表现
    • 不同市场环境下的表现
    • 不同波动率环境下的表现

    尤其是交易次数。如果一个策略回测了 10 年,最后只有 20 笔交易,然后 CAGR 50%。我会觉得这个结果的统计意义可能不太够,因为样本太少了。反之,如果一个策略 10 年做了几万笔交易,虽然每笔平均收益只有 0.05%,但经过手续费和滑点之后还能赚钱,我反而会觉得这种结果可能更值得研究。

    6. 实盘数据和回测数据一定要尽量一致

    很多策略回测使用的是日 K ,但真正交易的时候却需要 Tick 级数据和订单簿。这时候很容易出现一个问题:回测里看起来你是在某个价格成交的,但真实市场里根本没有办法以那个价格成交。尤其是

    • 高频策略
    • 短周期策略
    • 突破策略
    • 新闻事件策略
    • 盘口策略

    这些策略对数据质量和时间精度都比较敏感。我自己在测试实时策略的时候,会用上实时行情,主要是想把策略回测和实时行情环境尽量连接起来:

    
    import json
    import websocket
    
    API_KEY = "YOUR_API_KEY"
    
    def on_message(ws, message):
        data = json.loads(message)
        print(data)
    
    def on_open(ws):
        print("WebSocket connected")
    
        # 根据 API 文档发送订阅请求
        subscribe_message = {
            "action": "subscribe",
            "symbols": ["AAPL"]
        }
    
        ws.send(json.dumps(subscribe_message))
    
    ws = websocket.WebSocketApp(
        f"wss://quote.alltick.co/quote-stock-b-ws-api?token={API_KEY}",
        on_open=on_open,
        on_message=on_message
    )
    
    ws.run_forever()
    

    实战过程中要确保 [回测数据 → 策略信号 → 实时行情 → 模拟成交 → 实际交易] 这几个环节的数据定义尽量一致。否则可能出现一种情况:回测策略赚钱的原因,是因为你在历史数据里拥有“未来信息”。

    7. Walk-forward Test

    这是我目前比较喜欢的一种回测方法。 假设我有 2018 ~ 2025 年数据。 可以这样滚动测试:

    Train: 2018-2020 Test : 2021

    Train: 2019-2021 Test : 2022

    Train: 2020-2022 Test : 2023

    Train: 2021-2023 Test : 2024

    Train: 2022-2024 Test : 2025

    每次只使用过去的数据训练和优化参数,然后拿未来的一段数据测试。这样可以模拟真实交易过程中:我只能看到过去的数据,然后决定未来怎么交易。如果一个策略在多个 walk-forward window 里都表现不错,我会认为它的 robustness 比单次回测更高。

    8. 我自己现在判断过拟合,大概会看这几个信号

    如果一个策略出现下面这些情况,我会提高警惕:

    1. 参数稍微变化,收益就断崖式下降

    2. 训练集很好,测试集明显失效

    3. 换一个相似市场就完全不能用

    4. 收益高度依赖少数几笔交易

    5. 回测交易次数太少

    6. 加入手续费和滑点后直接亏损

    7. 使用更高频的数据后表现明显恶化

    8. 策略逻辑很难解释为什么有效

    9. 参数是经过大量试错后“挑”出来的

    10. 不同时间窗口测试结果差异非常大

    尤其是第 9 个,我觉得很容易被忽略。如果我尝试了 500 个策略,最后只挑一个表现最好的出来,然后说:我的策略年化 100%。这个结果本身其实没有太大意义,因为我实际上是在做一种隐性的 multiple testing 。如果测试的策略足够多,总会有一些策略“碰巧”在历史数据里表现特别好。

    No Comments Yet
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   1111 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 23:03 · PVG 07:03 · LAX 16:03 · JFK 19:03
    ♥ Do have faith in what you're doing.