第三章 做市商系统架构:低延迟系统设计、行情数据接入、订单路由、风控模块
做市商系统,说白了就是一台“抢时间”的机器。我做了这么多年量化,最深的体会就是:谁能在微秒级别内做出反应,谁就能赚钱。这一章,我带你拆解一套完整的做市商系统架构,看看每个模块到底是怎么运作的。
3.1 低延迟系统设计:每一微秒都是钱
先问个问题:为什么低延迟这么重要?
你想想看,做市商赚的是买卖价差。如果别人比你快1毫秒抢到单子,你的报价就废了。我见过太多团队,策略很牛,但系统延迟高,结果被高频玩家反复收割。
3.1.1 硬件层面的优化
- FPGA加速:用硬件逻辑代替软件处理。我个人习惯把行情解析和订单生成都放在FPGA上,延迟能从微秒级降到纳秒级。
- 网卡绑定:用Solarflare或Mellanox的网卡,开启DPDK(数据平面开发套件),绕过内核协议栈。嗯,这里要注意:不要用标准TCP/IP,那玩意儿延迟太高,做市商根本玩不起。
- 物理位置:把服务器放在交易所机房里,或者离交易所最近的托管机房。我曾经为了省2微秒,专门租了交易所隔壁的机柜。
3.1.2 软件层面的优化
- 无锁编程:用原子操作和内存屏障代替锁。我建议用Disruptor这种无锁队列,吞吐量能翻好几倍。
- 内存池:避免动态内存分配。所有数据结构预先分配好,运行时只做指针交换。
- CPU亲和性:把关键线程绑定到特定CPU核心上,避免上下文切换。
核心原则:低延迟设计不是“尽量快”,而是“可预测的快”。你要保证99.9%的订单都在固定时间内完成,而不是偶尔快一次。
3.2 行情数据接入:从原始数据到可交易信号
行情数据是系统的“眼睛”。如果眼睛花了,后面的动作全是错的。
3.2.1 数据源与协议
| 数据源 | 协议 | 延迟 | 我的建议 |
|---|---|---|---|
| 交易所直连 | FIX/FAST | <10μs | 首选,但成本高 |
| 行情聚合商 | WebSocket | 1-5ms | 适合回测,不适合实盘 |
| 第三方数据商 | Binary | 100μs-1ms | 备选方案 |
我个人习惯用交易所直连的FAST协议。为什么?因为FAST协议压缩率高,带宽占用小,而且解析速度快。我在项目中遇到过一个问题:用FIX协议解析行情时,CPU占用率飙到80%,换成FAST后直接降到15%。
3.2.2 行情处理流水线
- 网络接收:用DPDK直接从网卡拿数据,不经过内核。
- 协议解析:用FPGA或SIMD指令集并行解析。
- 数据清洗:去重、排序、补全缺失数据。
- 行情快照:维护一个内存中的Order Book(订单簿),实时更新。
- 信号生成:根据订单簿计算买卖价差、深度、波动率等指标。
避坑指南:我曾经在数据清洗环节漏掉了“重复行情”的过滤,结果策略在1秒内下了10次重复订单,差点被交易所封号。从那以后,我强制要求所有行情数据必须带时间戳和序列号,严格去重。
3.3 订单路由:把指令变成成交
订单路由是系统的“手”。行情看对了,但订单发不出去,或者发错了地方,一切都白搭。
3.3.1 路由策略
- 智能路由:根据当前市场深度、手续费、延迟等因素,自动选择最优交易所。
- 分片路由:大订单拆成小单,分散到多个交易所,减少市场冲击。
- 暗池路由:对于大额订单,优先走暗池,避免暴露意图。
你想想看,如果比特币在币安和OKX上有价差,你的路由系统能不能在1毫秒内判断出哪个更划算?我建议用“延迟加权”算法:把每个交易所的历史延迟和当前延迟都算进去,而不是只看价格。
3.3.2 订单生命周期管理
// 伪代码示例:订单状态机
enum OrderState {
PENDING_NEW, // 待发送
NEW, // 已发送
PARTIALLY_FILLED, // 部分成交
FILLED, // 完全成交
CANCELLED, // 已取消
REJECTED // 被拒绝
};
void onOrderUpdate(Order& order, OrderUpdate update) {
switch (update.type) {
case ACK: order.state = NEW; break;
case FILL: order.state = PARTIALLY_FILLED; break;
case CANCEL: order.state = CANCELLED; break;
case REJECT: order.state = REJECTED; break;
}
// 更新风控指标
riskManager.updateExposure(order);
}
注意:订单状态机必须是无状态的,或者用分布式缓存(如Redis)保存状态。我见过有人用本地内存保存订单状态,结果系统重启后所有订单都丢了,损失惨重。
3.4 风控模块:别让系统“裸奔”
风控是系统的“刹车”。没有风控的做市商系统,就像没有刹车的跑车——快是快,但迟早要出事。
3.4.1 实时风控指标
| 指标 | 阈值 | 说明 |
|---|---|---|
| 最大持仓量 | 100 BTC | 超过后自动平仓 |
| 最大亏损 | 总资金的2% | 触发后停止所有交易 |
| 订单频率 | 100笔/秒 | 防止系统过载 |
| 价差偏离 | 超过市场价差50% | 可能是数据异常 |
3.4.2 风控执行流程
- 预检:订单发出前,检查是否超过风控阈值。
- 实时监控:每秒更新一次风控指标,发现异常立即报警。
- 熔断机制:连续3次触发风控,自动熔断10分钟。
- 事后分析:每天生成风控报告,分析违规原因。
我的经验:风控模块一定要独立于交易模块。我曾经把风控逻辑写在策略代码里,结果策略出bug时,风控也跟着失效了。现在我的风控模块是单独的进程,用心跳检测和交易模块通信,一旦心跳断了,自动停止所有订单。
3.5 系统架构总览
下面这张图是我自己设计的做市商系统架构。你看,数据从行情接入开始,经过处理、路由、风控,最后到交易所。每个环节都有独立的模块,互不干扰。
3.6 实战中的避坑指南
最后,分享几个我踩过的坑:
- 别信“理论延迟”:厂商给的延迟数据都是在理想环境下测的。我建议你自己写个压测工具,在真实环境下跑一遍。
- 日志别写太多:我曾经为了调试,每笔订单都写日志,结果磁盘IO成了瓶颈。现在我只记录异常和关键事件。
- 回测和实盘是两回事:回测时延迟可以忽略,但实盘时每一微秒都重要。我建议在回测引擎里加入延迟模拟,否则实盘会给你“惊喜”。
最后一句:做市商系统没有“完美”的架构,只有“最适合当前市场”的架构。保持灵活,持续优化,才是王道。