一、数据总线概述

什么是数据总线

数据总线,说白了就是数据在系统里跑来跑去的「高速公路」。

我习惯这么定义它:数据总线是连接各个模块的共享通信通道。在回测系统里,它负责把行情数据、订单数据、账户信息这些东西,从一个模块搬到另一个模块。

你想想看,一个典型的回测系统长什么样?

  • 行情模块:从数据源拉取K线、Tick数据
  • 策略模块:根据行情做决策
  • 风控模块:检查订单是否合规
  • 执行模块:模拟撮合交易
  • 记录模块:保存成交记录和权益曲线

这些模块之间怎么通信?靠的就是数据总线。

核心要点:数据总线不是某个具体的库或中间件,而是一种架构思想。它定义了数据流动的规则和路径。

数据总线在回测系统中的角色

我在做第一个回测框架时,犯过一个典型的错误——让各个模块直接调用对方的方法。结果呢?

  • 行情模块直接调用策略模块的on_tick()
  • 策略模块直接调用执行模块的send_order()
  • 执行模块直接调用记录模块的save_trade()

代码耦合得像一团乱麻。后来我重构了,引入数据总线,才真正体会到它的好处。

数据总线在回测系统里扮演三个角色:

角色 说明 我踩过的坑
解耦器 模块之间不直接依赖,只跟总线打交道 之前改一个模块,要改三个模块的接口
调度中心 控制数据流向,决定谁先处理、谁后处理 曾经因为顺序问题,导致回测结果偏差
性能瓶颈 所有数据都经过总线,它慢了整个系统都慢 嗯,这个后面会详细讲

说白了,没有数据总线的回测系统,就像没有交通管制的十字路口——早晚要出事故。

低延迟的核心挑战

做低延迟回测,说白了就是在跟时间赛跑。我见过太多团队,策略逻辑写得漂亮,结果回测跑一天都出不来结果。

为什么会这样?问题往往出在数据总线上。

低延迟的核心挑战,我总结为三点:

  1. 数据拷贝开销——数据从A模块传到B模块,每拷贝一次就多一次延迟
  2. 锁竞争——多个模块同时读写数据,锁一上,性能就掉
  3. 内存分配——频繁new/delete对象,GC一触发,延迟就炸

我曾经踩过的坑:有一次回测100万笔Tick数据,用了标准库的queue做总线。结果跑了3个小时还没跑完。一分析,发现80%的时间花在数据拷贝和锁等待上。后来换成无锁环形缓冲区,同样的数据量只跑了12分钟。

你想想看,一个Tick数据从行情模块到策略模块,中间要经历多少步骤?

  • 行情模块把数据写入总线(序列化 + 拷贝)
  • 总线通知策略模块(上下文切换 + 信号量)
  • 策略模块从总线读取数据(拷贝 + 反序列化)

每一步都有开销。低延迟设计的目标,就是把这些开销压到最低。

我的建议:做低延迟数据总线,优先考虑三点——零拷贝、无锁设计、对象池。后面几章我会逐一展开讲。

数据总线架构示意图

下面这张图,是我个人习惯用的数据总线架构。它展示了数据在回测系统里的流动路径。

回测系统数据总线架构 行情模块 Tick / K线数据 策略模块 信号 / 订单 风控模块 合规检查 执行模块 撮合 / 成交 数据总线 无锁环形缓冲区 零拷贝传输 事件驱动调度 记录模块 成交 / 权益 数据源 CSV / 数据库 图例 数据流入 数据流出 回写路径

这张图里,所有模块都只跟数据总线通信。没有模块之间的直接连线。这就是解耦的核心思想。

一个小技巧:实际编码时,我会把总线设计成模板类。这样不管传Tick数据还是订单数据,都用同一套机制。减少重复代码,也方便做性能优化。

好了,数据总线的基本概念就讲到这里。记住一句话:总线设计的好坏,直接决定了回测系统的性能和可维护性。后面我们会一步步深入,把每个细节都讲透。


专注资料整理