第2章:回测系统架构设计
做量化交易这几年,我最大的感悟就是:回测系统的架构设计,直接决定了你策略研究的效率天花板。很多新手一上来就写个循环跑数据,结果数据量一上来就崩,或者策略逻辑稍微复杂点就改不动代码。嗯,这其实都是架构没想清楚。
今天我们就来聊聊,一个能支撑高频策略研发的回测系统,到底该怎么搭。
2.1 系统分层架构
我个人习惯把回测系统拆成四层。你想想看,如果所有代码都揉在一起,改个数据源都要动策略逻辑,那得多痛苦?
| 层级 | 名称 | 核心职责 |
|---|---|---|
| L1 | 数据层 | 行情数据接入、清洗、存储、缓存 |
| L2 | 引擎层 | 事件驱动、撮合逻辑、时间管理 |
| L3 | 策略层 | 信号生成、订单管理、风控 |
| L4 | 分析层 | 绩效归因、风险指标、可视化 |
说白了,每一层只管自己的事。数据层不用管策略怎么算,策略层也不用关心数据是从CSV读的还是从数据库拉的。我在项目中遇到过最坑的事,就是有人把数据清洗逻辑写在策略类里,结果换了个数据源,整个策略都得重写。
核心原则: 层与层之间通过接口通信,不要跨层调用内部方法。
2.2 模块划分
每一层内部,我建议再拆成更细的模块。这样后期维护、多人协作都方便。
数据层模块
- 数据源适配器:支持CSV、数据库、API等多种来源
- 数据清洗器:处理缺失值、异常值、复权计算
- 缓存管理器:内存缓存+磁盘缓存,避免重复IO
- 时间对齐器:不同频率数据的时间戳对齐
引擎层模块
- 事件调度器:管理Tick、Bar、定时器等事件
- 撮合引擎:模拟订单簿、成交逻辑
- 时间控制器:支持回放、快进、暂停
策略层模块
- 信号生成器:指标计算、模式识别
- 订单管理器:下单、撤单、订单状态跟踪
- 风控模块:资金管理、仓位限制、最大回撤控制
分析层模块
- 绩效计算器:夏普比率、最大回撤、胜率等
- 归因分析器:收益来源拆解
- 报告生成器:HTML/PDF报告输出
避坑指南: 我曾经把风控逻辑写在策略里,结果策略一改,风控忘了同步,回测结果虚高。后来我把风控独立成一个模块,策略只能通过接口查询风控状态,再也没出过问题。
2.3 数据流设计
数据怎么在系统里流转?这是架构设计的灵魂。我画了一张图,你看完就明白了。
数据流其实就三条主线:
- 行情数据流:数据层 → 引擎层 → 策略层。这是正向的,引擎层把数据包装成事件,策略层监听事件做计算。
- 订单指令流:策略层 → 引擎层。策略发出买卖指令,引擎层负责撮合。
- 成交结果流:引擎层 → 策略层 → 分析层。成交后,策略更新持仓,同时把记录发给分析层。
注意: 数据流必须是单向的,不要出现循环依赖。我曾经见过一个系统,策略层直接去数据层读数据,结果引擎层的时间控制完全失效,回测结果一塌糊涂。
2.4 性能目标设定
高频策略的回测,性能是硬指标。你想想看,如果回测一天的数据要跑10分钟,那你还怎么调参?
我一般会设定这几个性能目标:
| 指标 | 目标值 | 说明 |
|---|---|---|
| 单Tick处理耗时 | < 1μs | 包括事件分发、策略计算、订单检查 |
| 撮合延迟 | < 100ns | 订单簿匹配速度 |
| 内存占用 | < 4GB | 支持1年全市场Tick数据 |
| 回放速度 | ≥ 100x | 即1天数据在15分钟内跑完 |
我的经验: 性能优化要「先测量,后优化」。别一上来就搞什么内存池、无锁队列。先用profiler跑一遍,看看瓶颈到底在哪。我遇到过最离谱的事,优化了半天撮合引擎,结果发现瓶颈是日志打印——IO操作占了60%的时间。
具体怎么优化?几个方向:
- 数据结构选型:用数组代替链表,用连续内存减少缓存miss
- 避免内存分配:预分配对象池,不要在回测循环里new对象
- 并行化:多只股票的回测可以并行跑,但要注意共享状态的同步
- 减少IO:日志异步写入,数据尽量加载到内存
嗯,架构设计这块,说白了就是「高内聚、低耦合」这六个字。但真正落地的时候,细节特别多。上面这些是我踩过坑之后总结出来的,希望能帮你少走弯路。