2、回测系统架构设计:系统整体架构、模块划分、数据流设计、核心组件介绍
做市策略的回测,说白了就是一场「模拟交易」。你想想看,我们总不能拿真金白银去试错吧?回测系统就是我们的沙盘,在历史数据上跑一遍策略,看看它到底行不行。
我个人习惯,在动手写代码之前,先把架构想清楚。这就像盖房子,先画好图纸,再搬砖。否则写到一半发现结构不对,那可就头疼了。今天我们就来聊聊,一个靠谱的回测系统,到底长什么样。
2.1 系统整体架构:三层结构
我设计的回测系统,通常分为三层。每一层各司其职,互不干扰。这样做的好处是,哪一层出了问题,就修哪一层,不会牵一发动全身。
核心架构:数据层 → 引擎层 → 策略层
数据层负责喂数据,引擎层负责模拟撮合,策略层负责做决策。
为什么会这样分?因为做市策略对数据的要求极高。你不仅要看价格,还要看订单簿的深度、买卖盘的厚度。如果数据层和引擎层混在一起,调试起来会非常痛苦。
我曾经在一个项目中,把数据清洗和回测逻辑写在了同一个函数里。结果数据格式一变,整个回测就崩了。从那以后,我坚决把数据层独立出来。
2.2 模块划分:五个核心模块
具体到代码层面,我习惯把系统拆成五个模块。每个模块都是一个独立的类或包。
| 模块名称 | 职责 | 关键类/函数 |
|---|---|---|
| 数据模块 | 加载、清洗、对齐历史数据 | DataLoader, MarketData |
| 事件引擎 | 驱动回测时钟,分发事件 | EventEngine, BacktestLoop |
| 撮合引擎 | 模拟订单簿,执行成交 | OrderBook, Matcher |
| 策略模块 | 实现具体的做市逻辑 | BaseStrategy, MMStrategy |
| 绩效模块 | 计算盈亏、夏普、最大回撤 | PerformanceAnalyzer |
嗯,这里要注意。很多新手会把「策略模块」和「绩效模块」混在一起。我个人建议分开。因为策略是动态的,绩效是静态的。混在一起,你很难定位问题是出在策略逻辑上,还是出在统计计算上。
2.3 数据流设计:从 Tick 到 绩效
数据是怎么在系统里流动的?我画了一张图,你看一眼就明白了。
数据流其实很简单:
- 数据模块把历史Tick喂给事件引擎。
- 事件引擎按时间顺序,把数据推给策略模块。
- 策略模块根据市场状态,生成买卖指令,发给撮合引擎。
- 撮合引擎模拟成交,把结果返回给策略,同时记录到绩效模块。
- 最后,绩效模块汇总所有交易,算出最终成绩。
这里有个坑,我曾经踩过。就是数据的时间对齐问题。做市策略用的是Tick级数据,不同交易所的时间戳精度不一样。有的精确到毫秒,有的精确到微秒。如果不做对齐,撮合引擎会乱套。我的解决办法是,在数据模块里统一转成纳秒时间戳,按时间排序后再喂给引擎。
2.4 核心组件介绍:三个关键角色
在这么多组件里,有三个是灵魂角色。搞懂了它们,整个系统就通了。
2.4.1 事件引擎:回测的心脏
事件引擎说白了就是一个循环。它从数据模块里拿一条数据,然后问策略:「嘿,现在市场变成这样了,你要不要下单?」
伪代码大概是这样的:
class EventEngine:
def run(self, data_stream):
for event in data_stream:
# 1. 更新市场状态
self.market.update(event)
# 2. 通知策略
self.strategy.on_market(event)
# 3. 处理策略的订单
orders = self.strategy.get_orders()
for order in orders:
self.matcher.execute(order)
# 4. 记录绩效
self.performance.record(event, orders)
我个人习惯,在这个循环里加一个「心跳检测」。如果某个策略在10秒内没有响应,就自动跳过。防止策略死循环把回测卡死。
2.4.2 撮合引擎:模拟真实的订单簿
做市策略的核心是订单簿。所以撮合引擎必须能模拟限价单、市价单、撤单等操作。
我建议用红黑树或跳表来实现订单簿。因为订单簿需要按价格排序,同时支持快速插入和删除。Python里可以用sortedcontainers库,性能还不错。
避坑指南: 我曾经用列表来实现订单簿,结果回测100万条数据跑了3个小时。后来换成红黑树,10分钟就跑完了。数据结构的选型,真的会影响回测速度。
2.4.3 绩效模块:别只看收益率
很多新手做回测,只看最终收益率。其实做市策略更看重的是稳定性和资金利用率。
我一般会计算这几个指标:
- 夏普比率:衡量风险调整后的收益。做市策略的夏普通常比较高,如果低于2,说明策略有问题。
- 最大回撤:做市策略理论上回撤很小。如果回撤超过5%,可能是流动性风险没控制好。
- 成交率:发出的订单有多少被成交了。做市策略的成交率应该在60%以上,否则说明报价太激进。
注意: 回测中的绩效数据,永远比实盘好看。因为回测假设了「无限流动性」和「零滑点」。实际跑起来,绩效至少要打八折。
好了,架构设计就聊到这里。记住一句话:好的架构,是改出来的,不是设计出来的。先跑通一个最简单的版本,再慢慢优化。别一开始就想搞个大而全的系统,那样反而容易陷入泥潭。
核心总结:
- 三层架构:数据层、引擎层、策略层
- 五个模块:数据、事件、撮合、策略、绩效
- 数据流:Tick → 事件 → 策略 → 撮合 → 绩效
- 关键组件:事件引擎(循环驱动)、撮合引擎(订单簿)、绩效模块(多维度评估)