回测系统核心架构:四大模块的职责划分
做高频交易回测,说白了就是模拟真实市场环境,验证你的策略到底能不能赚钱。我见过太多人一上来就写策略代码,结果回测数据对不上、执行延迟算错、分析结果全是坑。嗯,这其实都是架构没想清楚。
今天我就带你拆解一下回测系统的核心架构。我个人习惯把系统分成四层:数据层、策略层、执行层、分析层。每一层各司其职,层与层之间通过标准接口通信。你想想看,这样设计的好处是什么?——任何一个层出了问题,你只需要替换那一层,不用动其他代码。
1. 数据层:回测的基石
数据层是整个系统的地基。地基不稳,上面盖什么都白搭。我在项目中遇到过最头疼的事,就是回测跑出来收益惊人,结果发现是数据里混了未来信息——tick 数据的时间戳对错了时区。
数据层要干三件事:
- 数据获取与存储:从交易所、数据供应商拉取行情数据。高频交易通常需要 Level 2 甚至 Level 3 的 tick 级数据。
- 数据清洗与对齐:去掉异常 tick、处理缺失值、对齐不同品种的时间轴。这一步最容易被忽视,但坑最多。
- 数据接口封装:对外提供统一的查询接口,比如
get_ticks(symbol, start, end)。策略层不需要关心数据是从 CSV 读的还是从数据库拉的。
2. 策略层:你的交易大脑
策略层是大家最熟悉的部分。说白了,就是写你的交易逻辑。但很多人把策略层搞得太重,什么数据清洗、订单管理全塞进来,最后代码乱成一锅粥。
策略层只负责两件事:
- 信号生成:根据数据层提供的行情,计算买卖信号。比如均线金叉、波动率突破、订单簿不平衡等。
- 订单决策:信号来了,要不要下单?下多少?要不要加风控检查?
举个例子,一个简单的做市策略:
class MarketMakingStrategy:
def on_tick(self, tick):
# 计算最优买卖价
bid_price = tick.mid_price - self.spread / 2
ask_price = tick.mid_price + self.spread / 2
# 检查库存风险
if self.position > self.max_position:
return # 不再买入
# 生成订单
self.send_order(side='buy', price=bid_price, qty=100)
self.send_order(side='sell', price=ask_price, qty=100)
3. 执行层:模拟真实交易环境
执行层是回测系统里最容易出偏差的地方。你想想看,策略说「我要以 10.00 元买入 1000 股」,但真实市场里可能根本没人卖给你,或者成交价滑到了 10.02 元。执行层就是模拟这个过程。
执行层核心模块:
| 模块 | 职责 | 常见坑点 |
|---|---|---|
| 订单路由 | 将策略订单发送到模拟撮合引擎 | 订单类型支持不全(如冰山订单) |
| 撮合模拟 | 根据订单簿数据模拟成交 | 未考虑盘口深度,导致成交价过于理想 |
| 滑点模型 | 模拟市场冲击和延迟造成的价格偏差 | 滑点参数设置过于随意 |
| 延迟模拟 | 模拟网络延迟、交易所处理延迟 | 忽略延迟会导致策略「预知未来」 |
我记得有一次帮朋友调试回测,他的策略年化收益 300%,我一查执行层——好家伙,撮合用的是「最优价成交」,完全没考虑盘口深度。真实市场里,大单进去价格早被打飞了。
4. 分析层:回测的照妖镜
分析层是最后一步,也是很多人草草了事的一步。跑完回测看一眼收益率就完事了?太天真了。分析层要回答三个问题:
- 赚了多少?——总收益率、年化收益率、夏普比率、最大回撤。
- 怎么赚的?——归因分析:是方向性交易赚的,还是做市赚的?是高频信号贡献大,还是低频信号贡献大?
- 风险有多大?——VaR、CVaR、持仓集中度、换手率。
我个人习惯在分析层加一个「压力测试」模块。把历史极端行情(比如 2010 年闪电崩盘、2020 年 3 月流动性枯竭)喂进去,看看策略会不会爆仓。这个步骤能帮你筛掉 80% 的伪策略。
各层之间的协作流程
四层不是各自为政的。它们通过事件驱动的方式协作:
- 数据层推送新的 tick 数据
- 策略层收到 tick,计算信号,生成订单指令
- 执行层收到订单指令,模拟撮合,返回成交结果
- 分析层记录每一笔成交,更新绩效指标
这个流程每来一个 tick 就循环一次。高频回测里,一天可能有几百万个 tick,所以性能优化也很关键。嗯,这个我们后面章节再细聊。
公众号:蓝海资料掘金营,微信deep3321