跳到主要内容

向量化回测 vs 事件驱动回测

直觉

实现回测有两种范式:

  • 向量化(vectorized):用矩阵运算一次算完整段,、代码短,适合信号→持仓→收益的线性逻辑(我们的 quant.vector_backtest 就是);
  • 事件驱动(event-driven):逐根 K 线(事件)推进,模拟订单簿、撮合、资金,更真实但慢、代码复杂。
维度向量化事件驱动
速度极快
真实度简化(即时成交、线性成本)高(限价单、滑点、资金)
适用研究、快速试想法实盘前仿真、执行细节
「人话」解释:研究阶段该用哪个?

研究阶段几乎都用向量化——它让你在几秒内扫完成千上万组参数,快速淘汰烂想法。 等策略定型、要贴近实盘时,再用事件驱动精修成交细节。本书的 quant 引擎是向量化教学版, 模块 8 后续都在它上面讲成本、防偏差、Walk-Forward。

可运行案例:两种范式结果一致

用同一个双均线信号,分别跑向量化引擎手写事件驱动循环,验证两者资金曲线吻合——这既验证引擎正确,也展示事件驱动的写法。

import quant
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

df = pd.read_csv('/data/spy_daily.csv', parse_dates=['date']).set_index('date')
close = df['adj_close']
cost = 2.0

raw = (close.rolling(20).mean() > close.rolling(60).mean()).astype(float)
signal = raw.replace(0, np.nan).ffill().fillna(0)
asset_ret = close.pct_change().fillna(0.0)

# —— 1) 向量化引擎 ——
res = quant.vector_backtest(close, signal, cost_bps=cost, freq=252)

# —— 2) 事件驱动循环(逐 bar) ——
pos, eq, nav = 0.0, 1.0, [1.0]
for t in range(1, len(close)):
  target = signal.iloc[t-1]                 # 昨日信号决定今日持仓(防前视)
  turnover = abs(target - pos)
  eq *= (1 + target * asset_ret.iloc[t] - turnover * cost/1e4)
  pos = target
  nav.append(eq)
nav = pd.Series(nav, index=close.index)

a, b = res['equity'].iloc[-1], nav.iloc[-1]
print(f"向量化末值 = {a:.4f}")
print(f"事件驱动末值 = {b:.4f}")
print(f"差异 = {abs(a-b):.2e}  → 两者一致 ✓")

plt.figure(figsize=(8, 3.4))
plt.plot(res['equity'], label='向量化', lw=1.5)
plt.plot(nav, label='事件驱动', ls='--', lw=1.2)
plt.legend(); plt.title('向量化 vs 事件驱动:同一信号、同一结果')
plt.tight_layout(); plt.show()

小结

  • 向量化快但简化,事件驱动慢但真实;
  • 研究用向量化,定型后用事件驱动精修;
  • 两者在简单逻辑下等价,可互相验证。

下一节给向量化引擎补上交易成本与滑点的现实。