第三章 做市商系统架构:低延迟系统设计、行情数据接入、订单路由、风控模块

做市商系统,说白了就是一台“抢时间”的机器。我做了这么多年量化,最深的体会就是:谁能在微秒级别内做出反应,谁就能赚钱。这一章,我带你拆解一套完整的做市商系统架构,看看每个模块到底是怎么运作的。

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 行情处理流水线

  1. 网络接收:用DPDK直接从网卡拿数据,不经过内核。
  2. 协议解析:用FPGA或SIMD指令集并行解析。
  3. 数据清洗:去重、排序、补全缺失数据。
  4. 行情快照:维护一个内存中的Order Book(订单簿),实时更新。
  5. 信号生成:根据订单簿计算买卖价差、深度、波动率等指标。

避坑指南:我曾经在数据清洗环节漏掉了“重复行情”的过滤,结果策略在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 风控执行流程

  1. 预检:订单发出前,检查是否超过风控阈值。
  2. 实时监控:每秒更新一次风控指标,发现异常立即报警。
  3. 熔断机制:连续3次触发风控,自动熔断10分钟。
  4. 事后分析:每天生成风控报告,分析违规原因。

我的经验:风控模块一定要独立于交易模块。我曾经把风控逻辑写在策略代码里,结果策略出bug时,风控也跟着失效了。现在我的风控模块是单独的进程,用心跳检测和交易模块通信,一旦心跳断了,自动停止所有订单。

3.5 系统架构总览

下面这张图是我自己设计的做市商系统架构。你看,数据从行情接入开始,经过处理、路由、风控,最后到交易所。每个环节都有独立的模块,互不干扰。

做市商系统架构图 行情数据接入 FAST/FIX协议解析 低延迟处理引擎 FPGA + 无锁队列 订单路由 智能路由策略 风控模块 实时监控 + 熔断 交易所 订单执行 数据流方向:行情 → 处理 → 路由 → 交易所 风控模块实时监控所有环节 核心延迟目标:端到端 < 50μs 从行情到达 → 订单发出,全程不超过50微秒

3.6 实战中的避坑指南

最后,分享几个我踩过的坑:

  • 别信“理论延迟”:厂商给的延迟数据都是在理想环境下测的。我建议你自己写个压测工具,在真实环境下跑一遍。
  • 日志别写太多:我曾经为了调试,每笔订单都写日志,结果磁盘IO成了瓶颈。现在我只记录异常和关键事件。
  • 回测和实盘是两回事:回测时延迟可以忽略,但实盘时每一微秒都重要。我建议在回测引擎里加入延迟模拟,否则实盘会给你“惊喜”。

最后一句:做市商系统没有“完美”的架构,只有“最适合当前市场”的架构。保持灵活,持续优化,才是王道。

蓝海数据掘金营,专注资料整理