事件驱动回测 vs 向量化回测,选哪个?

做量化回测,第一个绕不开的问题就是:到底用事件驱动,还是向量化?

我刚开始做套利策略那会儿,也纠结过这个问题。当时觉得向量化多快啊,一行代码跑完整个历史。后来真上了实盘,才发现事情没那么简单。今天咱们就把这两个方案掰开揉碎了聊。

先说说向量化回测

向量化回测,说白了就是拿整个历史数据做矩阵运算。你写个公式,比如 (close - ma20) / ma20,然后整个序列一起算。速度快得飞起。

核心特点:

  • 一次性处理所有数据
  • 依赖 NumPy、Pandas 的向量运算
  • 代码简洁,几行就能跑

举个例子,一个简单的双均线策略:

import pandas as pd
import numpy as np

# 假设 df 是历史数据
df['ma5'] = df['close'].rolling(5).mean()
df['ma20'] = df['close'].rolling(20).mean()
df['signal'] = np.where(df['ma5'] > df['ma20'], 1, -1)
df['return'] = df['signal'].shift(1) * df['close'].pct_change()
total_return = df['return'].sum()

你看,三行搞定。但这里有个坑——shift(1) 是事后诸葛亮。它假设你收盘后立刻能下单,实际交易中根本做不到。

我曾经踩过的坑:用向量化回测跑了一个统计套利策略,年化收益看着有 35%。结果实盘第一周就亏了 8%。后来发现,向量化没考虑订单簿深度和滑点,信号出来时价格早变了。

再聊聊事件驱动回测

事件驱动回测,模拟的是真实交易流程。每一根 K 线来了,你判断要不要下单,然后模拟撮合、记录持仓、更新风控。

它更像一个循环:

for each bar in history:
    # 1. 更新市场数据
    update_market(bar)
    
    # 2. 检查信号
    signal = check_signal()
    
    # 3. 执行交易
    if signal:
        execute_order(signal)
    
    # 4. 更新风控
    update_risk_control()
    
    # 5. 记录结果
    record_pnl()

每一步都能加逻辑。比如滑点、手续费、最小交易单位、涨跌停限制。你甚至可以模拟订单簿的逐笔成交。

我个人习惯:做套利策略时,一定用事件驱动。因为套利对执行时机极其敏感,差 0.1 秒可能利润就没了。向量化根本抓不住这种细节。

两个方案的对比

维度 向量化回测 事件驱动回测
速度 极快(秒级) 较慢(分钟级)
代码量 少(几十行) 多(几百行)
模拟精度 低(忽略细节) 高(贴近实盘)
适合场景 因子研究、初步筛选 策略验证、实盘前测试
调试难度 低(容易定位) 高(逻辑复杂)

我的选择策略

你想想看,这两个方案其实不是二选一,而是分阶段用。

  1. 第一阶段:因子挖掘——用向量化。快速跑几百个因子组合,看哪个有苗头。
  2. 第二阶段:策略验证——转事件驱动。把筛选出来的策略,加上真实交易约束再跑一遍。
  3. 第三阶段:参数优化——回到向量化。因为要跑大量参数组合,事件驱动太慢了。
  4. 第四阶段:实盘前测试——必须事件驱动。模拟完整的交易流程,包括网络延迟、交易所限频。

核心原则:向量化做广度,事件驱动做深度。两者互补,缺一不可。

一个真实的教训

我记得有一次做跨期套利回测。用向量化跑,年化夏普 2.8,看着完美。结果实盘时发现,每次信号出现后,要等 3-5 秒才能成交。这 3 秒里价差已经变了。

后来改成事件驱动,把滑点设成 2 个 tick,夏普直接掉到 1.2。嗯,这才是真实水平。

避坑指南:如果你用向量化回测,一定要手动加上滑点和延迟。别信那些「理想状态」下的收益曲线。我曾经见过一个策略,向量化回测年化 50%,加上 0.1% 滑点后变成 -5%。

框架选择流程图

下面这张图,是我自己总结的决策流程。每次做新策略,我都会走一遍:

开始回测 是因子筛选还是策略验证? 因子筛选 用向量化回测 策略验证 用事件驱动回测 参数优化 回到向量化 实盘前测试 必须事件驱动 输出回测报告

最后说几句

其实没有完美的回测框架。向量化快但不准,事件驱动准但慢。关键是你得知道当前阶段要什么。

我个人建议:新手从向量化入手,先理解策略逻辑。等跑通了,再升级到事件驱动。别一上来就搞复杂框架,容易把自己绕晕。

嗯,今天就聊到这儿。记住一句话:回测是帮你发现问题的,不是帮你证明策略赚钱的。

一个小技巧:写回测框架时,把滑点和手续费做成可配置参数。这样你可以在向量化和事件驱动之间快速切换,对比结果差异。我自己的框架就是这么设计的,省了不少事。

专注资料整理