引言:交易所是金融基础设施里最”硬核”的一类系统
在前面的十四篇里,我们从钱的建模、复式记账、账务数据库,一路走到了支付、清算、跨境、央行系统、数字货币。这些系统的共性是:围绕”一笔一笔付款”展开——谁付谁、金额多少、什么时间到账。而从本篇开始,系列进入另一条主线:交易所(Exchange)与市场基础设施。
交易所的工程难度和支付系统不在一个量级。一个支付网关做到 1 万 TPS(交易/秒)已经足以处理双 11,而纽交所(NYSE)Pillar、纳斯达克 INET、上交所新一代交易系统、芝加哥商品交易所 CME Globex 的撮合引擎在峰值时每秒要处理数百万笔订单,端到端延迟必须压到几十微秒到几纳秒。币安(Binance)现货引擎在 2021 年牛市日均成交额超 760 亿美元,单对 BTC/USDT 一个交易对在极端行情下每秒几万笔订单,全市场上千个交易对并行撮合。这背后是一整套从 FPGA、内核旁路(Kernel Bypass)、无锁队列(Lock-free Queue)、精确时钟同步(PTP)到跨机房复制的系统工程。
更关键的是,交易所的错误是不可逆的。一笔支付错了还能退款、冲正;一笔成交一旦进入清算链路,已经在登记结算机构落账,撤销的代价是惊动监管、赔偿对手方、修改当日结算文件。2012 年骑士资本(Knight Capital)因一行上线脚本漏掉了八台服务器之一的旧代码,在 45 分钟内向市场发出 400 万笔错误订单,账面亏损 4.4 亿美元,公司当周破产被收购。这是工程事故写入 MBA 教科书的少数案例之一。
本篇面向三类读者:
- 架构师:希望建立交易所的整体图景,知道一个撮合系统在系统栈的什么位置、和上下游如何交互;
- 低延迟工程师:想了解 LMAX Disruptor、DPDK、CPU Pinning、FPGA 等极限优化手段的应用场景;
- 金融科技从业者:需要理解证券、期货、加密交易所的共性与差异,为后续选型或对接做准备。
本篇是”全景图”,后续 16(撮合引擎深度)、17(行情分发)、18(登记结算)会分别下钻到具体子系统。
一、交易所的五大核心子系统
无论是 1792 年梧桐树下的纽交所,还是 2017 年诞生的币安,任何一家交易所从工程视角看,都由五个核心子系统构成。它们的边界清晰,职责单一,且基本是顺序级联的。
1.1 五大子系统概览
| 子系统 | 英文 | 职责 | 延迟敏感度 | 对应后续文章 |
|---|---|---|---|---|
| 订单网关 | Order Gateway / OMS | 客户端接入、协议转换、前置风控、订单分发 | 高(μs 级) | 本篇 |
| 撮合引擎 | Matching Engine | 订单簿维护、价格时间优先撮合、生成成交 | 极高(ns 级) | 第 16 篇 |
| 行情系统 | Market Data | L1/L2/L3 行情聚合与分发(MBP/MBO、快照+增量) | 高(μs 级) | 第 17 篇 |
| 清算与风控 | Clearing & Risk | 保证金、持仓、强平、盘中风险监控 | 中(ms 级) | 第 19 篇 |
| 结算与账户 | Settlement & Account | T+N 资金/证券过户、账户余额维护 | 低(分钟/小时) | 第 18 篇 |
这五个子系统在交易所的部署里是串联+分流的关系:客户端的订单顺着订单网关—前置风控—撮合引擎流下来,成交结果分两路——一路实时推给行情系统向市场广播,另一路进入清算风控打保证金、更持仓,再进结算系统在日末完成登记过户。
1.2 分层架构总览(SVG 深色主题)
这张图的要点:撮合引擎是唯一不能水平扩展的核心(每个交易对一个 shard,内部单线程、单机),它上下两侧的所有其它组件——网关、行情、风控、结算——都可以水平扩展,因而交易所的容量瓶颈永远在撮合层。
1.3 子系统之间的时间尺度
一条订单从客户端进入、到撮合完成、到行情对外分发、到日终结算完成,跨越六个数量级的时间尺度,这是非常独特的系统特征:
- 网关接入:1–50 微秒(μs),瓶颈在网卡和内核协议栈
- 前置风控:亚微秒(ns 级),FPGA 可压到 200–500 ns
- 撮合:亚微秒(几百 ns 到 几 μs),LMAX Disruptor、内存驻留
- 行情分发:1–20 微秒,组播传播到席位
- 清算更持仓:毫秒(ms)级,可以异步
- 结算过户:分钟到小时,T+1 日终批处理
设计交易所的核心经验是:把同步热路径做短,把异步冷路径做厚。订单—撮合—成交回报这条链路必须是纳秒级的纯内存操作,而保证金扣减、PnL 重算、资金清分这些可以并发、可以延迟、可以在 T+1 才落地。这和一般业务系统”请求来了一把梭”的做法完全相反。
二、订单网关(OMS):客户世界与撮合世界的分界线
2.1 职责
订单网关(Order Gateway,习惯上也叫 OMS 或简称 OG)是客户端流量进入交易所的第一站,它的职责可以归纳为六条:
- 多协议接入:FIX 4.x/5.x(机构主流)、OUCH(纳斯达克专有)、ITCH(行情协议对偶)、WebSocket + JSON(加密交易所常用)、REST(非延迟敏感场景)、二进制私有协议;
- 会话管理:登录认证、心跳、序列号、断线重连、消息回放;
- 协议归一化:把五花八门的外部协议统一成内部二进制订单消息格式,通常固定长度以方便无锁队列使用;
- 限流与流量整形:每个席位的订单速率、撤单速率、消息总量各有配额,超限直接拒绝;
- 前置风控(见 2.4);
- 订单路由:按交易对/合约把订单分发到对应的撮合引擎实例。
2.2 典型接入协议对比
| 协议 | 典型用户 | 特点 |
|---|---|---|
| FIX(Financial Information eXchange) | 投行、券商、基金 | ASCII 文本、Tag=Value、会话型、广覆盖、但解析慢 |
| FIX/FAST、SBE | 低延迟机构 | 二进制编码,解析几十纳秒 |
| OUCH / ITCH | 纳斯达克、多家股票所 | 二进制、定长、极简 |
| WebSocket + JSON | 加密交易所散户 | 易用、跨语言、但单消息数十微秒解析 |
| REST | 非敏感交易(取消、查询) | HTTP/1.1 或 HTTP/2 |
| 私有 TCP | 券商自研柜台 | 定制优化、接入门槛高 |
2.3 OMS 层数据结构
订单进入 OMS 后会被归一化为一条内部消息:
// order.proto —— 内部统一订单消息
message OrderIn {
uint64 seq_no = 1; // 网关分配全局序号
uint64 session_id = 2; // 席位会话
uint64 cl_ord_id = 3; // 客户端委托号(幂等去重键)
uint32 symbol_id = 4; // 数字化 symbol(减少字符串比较)
enum Side { BUY = 0; SELL = 1; }
Side side = 5;
enum OrdType { MARKET=0; LIMIT=1; STOP=2; STOP_LIMIT=3; ICEBERG=4; PEGGED=5; }
OrdType ord_type = 6;
int64 price_ticks = 7; // 价格用最小报价单位表示的整数
int64 qty = 8; // 数量(股/张/最小单位)
enum TIF { DAY=0; IOC=1; FOK=2; GTC=3; GTD=4; }
TIF tif = 9;
uint64 ts_ns_in = 10; // 网关入站纳秒时间戳
}几个关键设计点:
price_ticks用整数,不用浮点(参见第 2 篇《钱的建模》);symbol_id用 32 位整数替代字符串,查表由 OMS 完成;cl_ord_id是客户端生成的唯一委托号,OMS 按(session_id, cl_ord_id)做幂等去重,避免网络重传造成重复下单;ts_ns_in精确到纳秒,后续全链路的延迟归因都依赖这个基准时间戳。
2.4 前置风控(Pre-trade Risk)
前置风控是交易所和券商共同承担的闸门:在订单进入撮合之前就拒绝明显不合理的委托。典型规则:
- 可用资金检查:买入订单的名义金额 ≤ 账户可用(考虑杠杆和保证金比例);
- 持仓限额:多头单向累计头寸不超过客户合约上限;
- 单笔数量/金额上限:防 Fat-finger(胖手指),例如某合约单笔不超过 500 手;
- 价格保护:限价单价格偏离最新成交价不得超过 ±X%(防乌龙指);
- 自成交防御(Self-trade Prevention, STP):同一账户的买卖单相遇时取消较小的一侧,而不是成交;
- 合约有效性:交割月、涨跌停板、临停状态;
- 黑名单 / 制裁名单:特定账户禁止交易特定标的。
2010 年 5 月 6 日美股”Flash Crash”后,美国证监会(SEC)强化了 Market Access Rule(15c3-5),强制要求所有经纪商在订单进入交易所前完成上述风控检查。交易所侧通常也会再做一道,形成两层防护。
为什么要做前置而不是事后?因为撮合一旦成交就不可逆。一笔错单撤单可能需要交易所决策层批准并公告(中国 A 股在极端乌龙指情况下可以取消成交,但流程很重),远不如在撮合前拒绝。
2.5 FPGA 前置风控
机构客户对撮合延迟极度敏感,但前置风控本身就是几条 if 语句,如果放在 CPU 上经过内核栈要一两微秒,叠加 JIT 不确定性,抖动很大。于是以 Xilinx(现 AMD Xilinx)Alveo 和 Intel(现 Altera)为代表的 FPGA 方案被用来做Wire-speed 风控:
- 订单包在 10/25/40/100 Gbps 网线上进入 FPGA;
- FPGA 并行读取账户风控参数(从片上 BRAM 或 HBM),执行若干比较;
- 通过则原样转发到撮合引擎入口,不通过则丢弃并产生拒单回报;
- 端到端风控延迟可压到 200–500 纳秒,抖动 < 50 ns。
国内上交所在 2019 年新一代交易系统切换时也部分引入了 FPGA 加速,用于行情组播下发和部分校验环节。国外诸如 Jump Trading、Citadel Securities、Virtu Financial 的核心风控与撮合对接几乎全部 FPGA 化。
三、撮合引擎:交易所的”单点心脏”
撮合引擎(Matching Engine)是交易所最核心、最不能扩展、也最令工程师着迷的组件。本篇只做全景概述,第 16 篇会把算法、数据结构、重放、灾备完整展开。
3.1 基本职责
撮合引擎接收来自订单网关的合法订单,维护一个或多个订单簿(Order Book),按预定义的撮合规则生成成交(Trade),并把新订单变化和成交以事件流方式发出,供行情和清算两路订阅。
3.2 主流撮合规则
| 规则 | 别名 | 应用场景 |
|---|---|---|
| 价格时间优先 | Price-Time Priority、FIFO | 绝大多数现货、期货 |
| 价格比例优先 | Pro-rata | 部分利率、短期债券期货 |
| 价格时间 + Top-of-Book 保护 | Price-Time-Pro-rata Hybrid | CME 欧洲美元等 |
| 定盘/集合竞价 | Call Auction | 开盘/收盘、熔断后复牌 |
| 隐藏/冰山处理 | Hidden / Iceberg | 机构大单拆分 |
3.3 单机百万 TPS:LMAX Disruptor 的启示
2011 年,伦敦外汇零售经纪商 LMAX 公开了其核心撮合系统:单机 Java 实现,每秒 600 万笔订单,99% 延迟 < 50 μs。LMAX 的关键架构选择——后来被抽象成开源框架 Disruptor——在此后十年成为低延迟系统的教科书:
- 单线程业务逻辑:撮合核心单线程运行,消除所有锁,CPU 核心独占;
- 无锁环形缓冲(Ring Buffer):生产者-消费者之间用预分配的定长环形数组,避免 GC 和动态内存;
- CAS + 内存屏障代替锁:用
volatile语义发布/获取序号; - 批量处理:一次处理多条消息以摊薄开销;
- 所有状态内存驻留 + 事件日志:订单簿完全在堆内存或堆外内存中,持久化只记录事件流,崩溃靠重放;
- 确定性:输入序列决定输出序列,便于灾备副本重放到一致状态。
这六条设计原则几乎被所有现代撮合引擎采纳,包括 CME Globex、纳斯达克 INET、上交所新一代、Binance 撮合引擎(C++)、Deribit、FTX(已破产,但其撮合引擎代码公开片段仍广被引用)。
3.4 订单簿数据结构速览
常用实现是价格层有序容器 + 每层 FIFO 双向链表:
- 外层:
TreeMap<price, Level>或数组+跳表;加密交易所常用std::map<int64_t, PriceLevel>; - 层内:
intrusive list<Order>,保留插入顺序,成交时从头取; - 常用辅助:按
order_id到节点指针的 hash,支持 O(1) 撤单; - 极限优化:价格直接作为数组下标(tick 范围有限时),访问 O(1)。
第 16 篇会详细比较 B+树、跳表、平衡树、分层数组这几种组织方式在不同品种下的权衡。
3.5 撮合过程的 Mermaid 图
sequenceDiagram
autonumber
participant C as 客户端
participant OG as 订单网关
participant R as 前置风控
participant M as 撮合引擎
participant MD as 行情
participant CL as 清算
C->>OG: 新单 BUY 10@100.50
OG->>R: 归一化后转发
R-->>OG: 通过
OG->>M: OrderIn(seq=1001)
M->>M: 遍历卖盘,匹配至 100.50
M-->>MD: Trade 事件(6@100.50)
M-->>MD: BookUpdate(剩余 4@100.50 挂单)
M-->>CL: ExecReport(fills)
M-->>OG: ExecReport 回报
OG-->>C: 成交确认 + 剩余委托
3.6 为什么撮合必须”一单一线程、一对一机”
工程上曾有过无数人想让撮合水平扩展——按品种分片很好,但单一品种内部,价格时间优先这件事天然是串行的:任何并行撮合都可能破坏时间优先的公平性,引来监管和交易者的抗议。
因此现代交易所的做法几乎一致:
- 按 symbol/合约分片,每片一个撮合实例;
- 每个实例单线程、CPU 核心独占;
- 通过加机器来扩展品种数,不通过加线程来扩展单品种。
这也决定了交易所永远要优化的是单核性能,而不是堆核数。Intel 的 Ice Lake、AMD 的 3D V-Cache EPYC、ARM 的 Neoverse 都是被交易所和 HFT 公司竞相采购的核心硬件。
四、行情系统(Market Data)
行情系统从撮合引擎订阅事件流,聚合为可对外发布的行情产品,按不同深度和频次分发给订户。第 17 篇会详细展开。
4.1 L1 / L2 / L3 三个级别
| 级别 | 内容 | 典型用户 |
|---|---|---|
| L1 | 最优买卖一档 + 最新成交 | 散户 App、财经网站 |
| L2(MBP, Market-By-Price) | 买卖 5/10/20 档、每档累计量 | 活跃交易者、量化入门 |
| L3(MBO, Market-By-Order) | 每一条挂单明细(匿名) | 专业做市商、高频策略 |
4.2 快照 + 增量的经典模式
订阅者先收一份全量快照(Snapshot)建立初始状态,之后用增量(Incremental Update)维护。增量消息序号连续,丢失时订阅者必须请求重传或重新拉一份快照。
Snapshot: BookState @ seq=100000
Incremental: seq=100001 Insert Order(O1, BID, 100.00, 10)
seq=100002 Modify Order(O1, qty=7)
seq=100003 Trade(3@100.00)
...
4.3 组播 vs TCP
- UDP 组播(Multicast):纳斯达克、CME、上交所、深交所、港交所的交易所级分发都是组播。带宽一次发送,N 个席位同时收;代价是需要席位自己处理丢包、重传请求(通常用 TCP 辅助通道)。
- TCP 点对点:加密交易所(Binance、Coinbase、OKX)面向互联网分发,绝大多数是 WebSocket over TCP,因为组播在公网不可用。TCP 行情在峰值压力下经常排队、延迟抖动大,这是加密交易所的工程痛点之一。
4.4 行情产品的商业价值
传统交易所的 L2/L3 行情是付费产品。纳斯达克一年行情营收超 10 亿美元;LSE、德交所、CME 都不便宜。中国 A 股 Level-2 行情由中证报价系统和财经终端分销,专业席位年费数万到数十万。这是交易所除了手续费外最主要的收入来源之一,反过来也决定了行情分发系统的工程完整度——它是”产品”而不是”副产物”。
五、清算与风控:成交之后的第二条战线
5.1 盘中风控 vs 盘后清算
前置风控负责”不让错单进来”;盘中风控(Intraday Risk)负责”在持仓变化时持续监控账户健康”。对期货和加密衍生品尤其关键:
- 逐笔盯市(Mark-to-Market):每笔成交、每次价格跳动后重算所有持仓账户的浮动盈亏;
- 保证金监控:账户权益 / 维持保证金 < 阈值时触发追保通知;
- 强平(Liquidation):账户无法在规定时间内补足保证金,风控下达强平单,有些交易所由撮合引擎内部直接完成,有些走清算所;
- 熔断/涨跌停:价格或指数偏离过大时暂停撮合。
加密交易所的强平在极端行情下是最容易出事的环节:2021 年 5 月 19 日加密市场单日下跌 30%,Binance、OKX、火币等的强平引擎因订单簿深度不足触发”强平穿仓”,由保险基金补缺,之后演化出自动减仓(ADL, Auto-Deleveraging)机制。
5.2 中央对手方(CCP)
在证券和期货市场,中央对手方(Central Counterparty, Central Clearing)是清算的核心法律构造:买卖双方成交后,CCP “介入”交易,成为所有买家的卖家、所有卖家的买家,承担违约风险。中国的中证登(CSDC)、上海清算所、中金所清算中心,美国的 DTCC、CME Clearing,欧洲的 LCH 都属此类。
CCP 的工程影响:
- 成交后所有持仓由 CCP 对清算会员清算,席位对 CCP 而非对手方有对应的义务;
- CCP 要求保证金(初始、维持、盘中追缴);
- CCP 设立违约基金、风险瀑布(Default Waterfall)机制应对极端违约。
CCP 的具体工程会在第 18 篇《证券登记结算》展开。
5.3 清算系统的数据特征
清算子系统不是低延迟系统而是高吞吐、强一致、可审计的系统。典型要求:
- 日终能在规定窗口内完成全部席位的持仓对账、盈亏计算、保证金划转;
- 所有修改必须有审计日志,任何一笔调整能回溯到原始事件;
- 双机房热备、数据库同步复制,RPO = 0。
技术栈常见组合:撮合事件流(Kafka/Pulsar/内部总线) → 流处理(Flink/自研 C++ 流) → 账务数据库(Oracle/OceanBase/TiDB) → T+1 离线对账(Spark/Hive)。第 19 篇《实时风控引擎》会专门讲其中的规则引擎和特征工程。
六、结算与账户:最终落地
“结算(Settlement)”是资金/证券的最终所有权转移,区别于”清算(Clearing)“仅是计算应收应付。第 11 篇已经从通用支付视角讲过清算与结算,本节只补充交易所特有的部分。
6.1 T+N 模型
| 品种 | 结算周期 | 说明 |
|---|---|---|
| 美股 | T+1(2024-05-28 起,原 T+2) | SEC 规则 15c6-1 修订 |
| 中国 A 股 | 股票 T+1、资金 T+0 可交易、T+1 可取 | CSDC 规则 |
| 中国期货 | 当日结算 T+0 | 每日无负债结算 |
| 加密现货 | 实时(秒级) | 链下记账,实时过户 |
| 加密永续 | 实时 + 资金费率 8h 结算 | Funding Rate |
| CBDC / 稳定币 | 秒级 | 第 14 篇 |
T+1 相对 T+2 缩短了交收期,降低了对手方信用风险,但对机构的资金/借券调度提出更高要求——尤其是跨境套利(美股 T+1、欧股 T+2 错位)。
6.2 账户体系
交易所侧通常不直接保管客户的证券和资金,而是:
- 资金账户:客户的钱放在托管银行,交易所见到的是清算会员维度的汇总账户;
- 证券账户:股票登记在登记结算机构(CSDC、DTC)名下,客户在会员处开子账户;
- 加密交易所例外:币安等中心化交易所直接持有客户资产的私钥,这是其信任模型和 2022 年 FTX 事件的根本问题;自托管(Self-custody)是后 FTX 时代用户和监管共同的诉求。
七、订单类型大全
7.1 基础订单类型
| 类型 | 中文 | 语义 |
|---|---|---|
| Market | 市价单 | 以最优对手价立即成交,不保证价格 |
| Limit | 限价单 | 指定价格及以下/以上成交,不成交则挂单 |
| Stop (Stop-Loss) | 止损单 | 达到触发价后转为市价单 |
| Stop-Limit | 止损限价单 | 达到触发价后转为限价单 |
| IOC | 即成即撤 | Immediate-Or-Cancel,未成交部分取消 |
| FOK | 全成或撤 | Fill-Or-Kill,不能全量成交则全撤 |
| GTC / GTD | 长期有效 / 指定日前有效 | Good-Till-Cancelled / Good-Till-Date |
| Post-Only | 仅挂单 | 会吃单成交则撤单(用于赚 maker 返佣) |
7.2 高级订单类型
- Iceberg(冰山单):显示量 100 手 / 总量 10000 手,成交显示量后自动补充;
- Hidden(隐藏单):完全不显示在行情中,仅在撮合时参与;
- Pegged(盯市单):价格随市场最优价/中间价动态调整,常见 Midpoint Peg、Primary Peg;
- TWAP:Time-Weighted Average Price,在时间窗口内均匀拆单;
- VWAP:Volume-Weighted Average Price,按历史/实时成交量分布拆单;
- MOO/MOC:Market-On-Open / Market-On-Close,集合竞价撮合;
- Discretionary:显示价与实际成交愿意价不同,给撮合引擎”自由裁量”空间。
并非所有交易所都支持所有类型——例如中国 A 股只支持限价单和市价单两大类,且市价单还有”最优五档即时成交剩余撤销/转限价”等变种;而纳斯达克、NYSE、CME 的订单类型有 50+ 种,TWAP/VWAP 通常不是交易所原生而是券商/算法交易系统层实现的。
八、订单生命周期状态机
8.1 状态与转移
stateDiagram-v2
[*] --> New: 客户端提交
New --> Rejected: 前置风控失败
New --> Pending: 网关接受
Pending --> Working: 进入订单簿
Pending --> Rejected: 撮合引擎拒绝(标的无效/涨跌停)
Working --> PartiallyFilled: 部分成交
PartiallyFilled --> PartiallyFilled: 继续部分成交
Working --> Filled: 全部成交
PartiallyFilled --> Filled: 剩余全部成交
Working --> Canceled: 撤单成功
PartiallyFilled --> Canceled: 剩余撤单
Working --> Expired: TIF 到期
PartiallyFilled --> Expired: 剩余到期
Rejected --> [*]
Filled --> [*]
Canceled --> [*]
Expired --> [*]
8.2 FIX 协议里的 ExecType 与 OrdStatus
FIX 把”发生了什么”和”订单当前处于什么状态”分离成两个字段:
ExecType(150):本次事件类型,0 = New, 4 = Canceled, 5 = Replaced, 8 = Rejected, F = Trade, C = Expired, ...OrdStatus(39):订单当前聚合状态,0 = New, 1 = Partially Filled, 2 = Filled, 4 = Canceled, 8 = Rejected, ...
这套设计在几乎所有交易所内部事件模型里都能找到影子。工程实现上要注意:ExecType
是事件流的一部分,必须持久化;OrdStatus
是事件流聚合的结果,可以重算。
8.3 状态机实现的常见坑
- 撤单与成交竞争:订单正在被撮合时,撤单请求到达。正确做法是撤单进入同一事件队列串行处理,撮合完成后再处理撤单,如果订单已全成则返回”too late to cancel”;
- 部分成交后 TIF 判断:IOC 的语义是”未成交部分立即撤销”,所以 IOC 限价单一旦吃完能吃的对手单就结束,剩余不挂;
- 消息回放幂等性:主备切换时消息可能重放,状态机必须对同序号事件幂等。
九、低延迟工程技术栈
这一节把交易所侧的低延迟手段清单化。很多技术在第 16 篇撮合引擎里会展开,这里先建立地图。
9.1 网络层
- 内核旁路(Kernel Bypass):DPDK(通用)、Solarflare/Xilinx Onload(商业)、libvma、VPP;应用直接从网卡收发包,绕开内核协议栈,延迟从 5–10 μs 降到 < 1 μs;
- 用户态 TCP:mTCP、F-Stack,在旁路基础上实现 TCP/UDP;
- RDMA:RoCE v2、InfiniBand,主要用于撮合引擎与灾备副本之间的同步;
- Multicast UDP:行情组播;
- NIC 时间戳:硬件打时间戳,精度 < 10 ns。
9.2 CPU 与内存
- CPU
pinning/isolation:
isolcpus=内核参数把若干核心从调度器隔离,撮合线程独占; - NUMA 感知:数据、线程、网卡尽量在同一 NUMA 节点;
- 大页内存(Huge Pages):2 MB/1 GB,减少 TLB miss;
- Prefetch
指令:
__builtin_prefetch提前载入下一笔订单到缓存; - 关闭超线程:避免兄弟核抢占;
- 关闭 C-states / P-states:避免 CPU 频率切换引起的延迟抖动。
9.3 并发原语
- 无锁队列:SPSC(单生产者单消费者)性能最佳;MPSC、MPMC 代价递增;
- Disruptor 环形缓冲:业界事实标准;
- 序号驱动:所有事件有严格递增序号,消费者按序号消费,避免依赖时间戳。
9.4 语言与运行时
- C++ 为主:几乎所有交易所撮合引擎都是 C++;
- Java 以 LMAX 为代表:需要 JIT 预热、GC 调优(ZGC / Shenandoah 低停顿);
- Rust 新兴:dYdX v4 的部分组件、一些新加密交易所尝试;
- 避免 GC 语言做热路径:Go 被用于加密交易所的网关层较多,但极少用于撮合核心。
9.5 硬件加速
- FPGA:前置风控、协议解析、部分撮合(如 Jane Street 的一些内部系统);
- 智能网卡(SmartNIC):Nvidia BlueField、AMD Pensando,正在替代部分 FPGA 场景;
- 定制交换机:Arista 7130 系列内建 FPGA,用于低延迟镜像和过滤;
- 时钟卡:白兔(White Rabbit)、Meinberg PTP 卡,同步到 UTC ns 级。
十、时钟与因果:交易所的”时间是什么”
10.1 为什么时间在交易所里特别重要
- 价格时间优先是撮合规则的一半:没有时间,优先级无法确定;
- 监管报告要求所有订单事件带有统一时间戳(欧盟 MiFID II 要求 HFT 报单时间戳精度达到 1 μs);
- 事故复盘离不开全链路时间对齐;
- 跨机房一致性依赖时钟因果来推导事件顺序。
10.2 NTP vs PTP
- NTP(Network Time Protocol):精度毫秒级,互联网用;
- PTP(Precision Time Protocol,IEEE 1588):精度 10–100 纳秒,交易所标配;
- 白兔(White Rabbit):在 PTP 基础上做到亚纳秒,欧洲粒子物理组织 CERN 发起,部分交易所使用;
- GPS 原子钟 + PTP Grandmaster:通过 GPS 获得 UTC 再用 PTP 分发,是当前主流方案。
10.3 时间戳精度
现代交易所在多个环节打时间戳:t0(网关入站)、t1(风控出)、t2(撮合入)、t3(撮合出)、t4(行情出)、t5(网关出站给客户)。运营团队每天分析每段延迟的
P50/P99/P99.99,不到 1 μs 的抖动都是”事故”。
十一、主流交易所对比
11.1 传统交易所
| 交易所 | 核心系统 | 关键信息 |
|---|---|---|
| 纽交所 | Pillar(2016 上线替换多套旧系统) | FIX/Pillar Binary、并购 Archipelago、2022 完成所有板块迁移 |
| 纳斯达克 | INET | 2004 收购 Island 的 INET 引擎、OUCH/ITCH 协议、被全球 20+ 市场作为底座复用(含纳斯达克北欧、香港、东京部分板块) |
| 芝加哥商品交易所 | CME Globex | 始于 1992,期货/期权全球最大电子市场,二进制协议、FPGA 加速 |
| 洲际交易所 | ICE Trading Platform | WTI、Brent 原油期货、合并 NYSE 后继续使用自有平台 |
| 上交所 | 新一代交易系统(2019) | 自研、FPGA 加速、撮合性能 60 万笔/秒量级(公开资料)、STEP/FIX 接入 |
| 深交所 | 第五代交易系统 | 2016 上线、2022 持续升级 |
| 中金所 | 新一代期货交易系统 | 合约撮合、保证金、CCP 一体化 |
| 港交所 | Orion Trading Platform (OTP-C) | 证券、衍生品、LME 金属期货 |
| 东京证交所 | arrowhead 4.0(2024) | 富士通,响应时间压到亚毫秒 |
11.2 加密交易所(中心化)
| 交易所 | 核心栈 |
|---|---|
| Binance | C++ 撮合引擎 + Go 网关(来自公开工程分享)、MySQL + 自研存储 |
| Coinbase | Java/Go 多栈,撮合早期 Erlang,后迁移 Java |
| OKX / 火币 / Gate | C++ 撮合 + Go/Java 网关,架构趋同 |
| Deribit | 欧式期权龙头,撮合为 OCaml → 后重写为 Rust/C++ |
| Kraken | Cython/C++ 撮合、广泛采用 Rust 进行生态扩展 |
11.3 去中心化交易所(DEX)
去中心化交易所的”撮合”方式和传统交易所完全不同,是本篇最值得单独记一笔的变化:
- Uniswap v2/v3/v4:AMM(Automated Market Maker)恒定乘积做市,没有订单簿,所有”成交”是用户直接与流动性池兑换;v3 引入集中流动性(Concentrated Liquidity),v4 引入 hooks 插件;
- Curve:稳定币专用 AMM,曲线更平缓;
- dYdX v4:2023 年从以太坊迁到自建的 Cosmos 链,订单簿上链(应用链专用),撮合由验证人节点共同完成;
- Hyperliquid:自建 HyperBFT 共识,订单簿完全在链上,TPS 公开宣称 20 万+,是近年 DEX 工程的一个新标杆;
- 链上 CLOB(Central Limit Order Book):Serum/OpenBook(Solana)、Vertex(Arbitrum)等。
DEX 的工程性能目前仍远低于中心化交易所(Binance 现货顶峰 200 万 TPS,DEX 顶峰 20 万 TPS 级别),但它带来了自托管、抗审查、可组合这三个中心化交易所永远无法提供的属性。第 25 篇会讨论行业展望。
十二、熔断与故障隔离
12.1 涨跌停与熔断机制
- 中国 A 股:个股 ±10%(ST 股 ±5%、科创板和创业板注册制后 ±20%、北交所 ±30%);整市场 2016 年引入过 5%/7% 熔断,4 天 4 次熔断后暂停;
- 美股:2013 年引入 Limit Up-Limit Down(LULD),基于标准普尔 500 的 Market-Wide Circuit Breakers 7%/13%/20% 三档;
- CME:价格波动区间(Price Limits)+ 异常价格保护(Velocity Logic);
- 加密:大多数中心化交易所设置自动减仓(ADL)和保险基金,但没有统一涨跌停制度。Binance 等会有单笔下单价格保护、衍生品标记价格(Mark Price)机制缓解插针影响。
12.2 2010 年 5 月 6 日 Flash Crash
道琼斯指数在几分钟内下跌约 1000 点再反弹。SEC/CFTC 联合报告将原因归结为:一笔 41 亿美元的 E-mini S&P 500 期货卖单(由 TWAP 算法执行)与流动性不足的市场碰撞,叠加 HFT 的瞬时退出,造成连锁下跌。
工程教训:
- 断路器(Circuit Breaker)必须跨市场:股票跌停时,期货不跌停也无意义;
- 单边限价单需要防雪崩:算法单需按成交量比例限制;
- 行情延迟会放大事故:当时 CQS(合并行情系统)延迟上升到秒级,加剧恐慌。
12.3 2012 年 8 月 1 日 Knight Capital
骑士资本在上线新代码时,运维手动部署到 8 台服务器,漏掉了其中 1 台。那台机器上旧代码的一段测试路径被配置标志激活,以每秒数千笔的速度向纽交所发出错误订单。45 分钟内造成 4.4 亿美元账面亏损,公司当周被 Getco 收购。
工程教训:
- 配置驱动的代码路径危险:被废弃的代码应该物理删除,不是靠 flag 屏蔽;
- 部署必须原子化:脚本化、幂等化、可回滚;
- Kill Switch:交易所侧和券商侧都应有一键拉断开关,骑士案例中从发现到人工拉断用了 45 分钟;
- Market Access Rule 15c3-5 在事故发生前已发布,但骑士的风控规则没有覆盖本次错单的场景——前置风控必须基于异常行为而不仅是规则。
12.4 加密交易所的”针”
加密市场没有涨跌停,极端行情容易出现”插针”——瞬间价格偏离 30% 后回归,但这段时间的强平已不可逆。应对措施:
- 标记价格(Mark Price):用指数价格而非最新成交价触发强平;
- 自动减仓(ADL):保险基金不足时按盈利排序削减对手盘;
- 保险基金(Insurance Fund):强平溢价归入基金,用于补足未来穿仓。
十三、加密交易所的特殊工程
13.1 冷热钱包分层
中心化加密交易所持有用户资产,必须设计冷热钱包分层:
- 热钱包(Hot Wallet):连网、支持即时提现、余额不超过日提现额度的 5–10%;
- 温钱包(Warm Wallet):多签(Multi-sig)或 MPC,日常从冷到热补充;
- 冷钱包(Cold Wallet):离线硬件签名、地理分散,存放 90%+ 资产;
- 定期储备证明(Proof of Reserves, PoR):FTX 事件后行业惯例,基于 Merkle 树公开余额摘要,用户可验证自身资产被包含。
13.2 链上出入金
- 充币:用户把币转到交易所分配的充币地址,交易所监听链上事件,按确认数入账;不同链的确认数要求:BTC 3–6 个、ETH 12–64 个、高吞吐链几十到上百;
- 提币:热钱包签名发送交易,监听确认后通知用户;提币手续费定价是重要收入;
- 链上清算:稳定币、Layer-2(Arbitrum、Base、Optimism)、跨链桥(Wormhole、LayerZero、Axelar)都是交易所后端工程复杂度的来源。
13.3 DEX 撮合上链
去中心化永续交易所(如 dYdX v4、Hyperliquid)的订单簿上链对传统撮合工程师既熟悉又陌生:
- 熟悉的是:仍然是价格时间优先 + 撮合 + 成交回报;
- 陌生的是:所有订单、所有撤单、所有成交都必须进入共识,TPS 被区块时间和出块大小制约;dYdX v4 用 Cosmos SDK 实现了约 2000 TPS 的订单吞吐,Hyperliquid 用自研 HyperBFT 做到了 20 万 TPS 级(公开数据);
- MEV(Maximal Extractable Value):链上撮合必须应对区块提议者的抢跑、夹击、订单重排序攻击,是传统交易所没有的新维度。
十四、数据模型与接口示例
14.1 订单表(示例)
CREATE TABLE orders (
order_id BIGINT PRIMARY KEY,
session_id BIGINT NOT NULL,
cl_ord_id VARCHAR(64) NOT NULL,
account_id BIGINT NOT NULL,
symbol_id INT NOT NULL,
side TINYINT NOT NULL, -- 0 BUY, 1 SELL
ord_type TINYINT NOT NULL,
price_ticks BIGINT NULL, -- 市价单为 NULL
qty BIGINT NOT NULL,
cum_qty BIGINT NOT NULL DEFAULT 0,
avg_price_ticks BIGINT NULL,
tif TINYINT NOT NULL,
status TINYINT NOT NULL, -- 见 8.2
ts_ns_in BIGINT NOT NULL,
ts_ns_last BIGINT NOT NULL,
UNIQUE KEY uniq_session_clord (session_id, cl_ord_id),
KEY idx_account_status (account_id, status),
KEY idx_symbol_status (symbol_id, status)
);14.2 成交表
CREATE TABLE trades (
trade_id BIGINT PRIMARY KEY,
symbol_id INT NOT NULL,
maker_order_id BIGINT NOT NULL,
taker_order_id BIGINT NOT NULL,
maker_account BIGINT NOT NULL,
taker_account BIGINT NOT NULL,
price_ticks BIGINT NOT NULL,
qty BIGINT NOT NULL,
ts_ns BIGINT NOT NULL,
KEY idx_symbol_ts (symbol_id, ts_ns)
);14.3 FIX 下单报文(新订单 D)
8=FIX.4.4|9=142|35=D|49=MYCLIENT|56=EXCHANGE|34=215|52=20260422-09:30:01.123|
11=ORD123|21=1|55=AAPL|54=1|60=20260422-09:30:01.121|38=100|40=2|44=180.50|59=0|10=072|
- 35=D:新订单
- 55=AAPL:标的
- 54=1:买
- 40=2:限价
- 44=180.50:价格
- 38=100:数量
- 59=0:DAY
14.4 WebSocket 下单(加密交易所示例)
{
"op": "order.new",
"req_id": "c-20260422-001",
"symbol": "BTC-USDT",
"side": "BUY",
"type": "LIMIT",
"price": "65000.5",
"qty": "0.12",
"tif": "GTC",
"post_only": true,
"ts": 1745325001000
}十五、工程坑点汇总
下面是笔者和同行在交易所相关系统里踩过的、每条都代表过一次故障的经验:
- 浮点价格。任何用
double表达价格的系统最终都会在加法累积误差处翻车,尤其是均价重算。统一使用”最小报价单位 tick 整数表示”。 - 时间戳回退。NTP
同步偶尔回跳,撮合基于时间戳判断先后直接乱掉。应使用单调时钟(
CLOCK_MONOTONIC)做内部序号,UTC 时间仅用于对外。 - cl_ord_id 冲突。客户端重连后发了重复委托号,OMS 幂等去重必须做;一旦不做就是跟客户端打”成交/不成交”的官司。
- 撤单风暴。某些策略在行情变化时撤一批再挂一批,产生 10x 于下单量的撤单消息,撮合引擎队列被撤单塞满导致新单延迟激增。解决:按 session 分配撤单配额。
- 冰山单对撮合时间优先的干扰。补充量进入订单簿时按”原始时间”还是”补充时间”享有优先级?不同交易所规则不同,必须规则先定死。
- 部分成交下的 IOC 剩余处理。有过案例是 IOC 剩余部分”被挂单”,引发监管罚单。
- TIF=DAY 的日切处理。夜盘品种的 DAY 到底是自然日还是交易日?每个市场定义不同,代码必须读规则不能拍脑袋。
- 撮合与行情不一致。撮合出的事件与行情系统发出的消息顺序不一致导致客户端重建订单簿后状态错误。必须在撮合侧分配全局序号,行情系统严格按序号分发。
- 灾备副本重放偏差。副本用不同版本的撮合引擎代码重放历史事件,规则微调导致结果不同。灾备切换时对不上账。解决:灰度必须双跑比对,严禁一边切代码一边切数据。
- 加密交易所提币”双花”。热钱包用同一个 UTXO 发两笔提币,第二笔被节点拒绝但用户看到提币失败要求重发,最终一笔成功一笔失败但账务状态漂移。必须把链上签名与账务扣款绑定成一个本地事务。
- 冷启动订单簿。灾备切换后订单簿要从快照+增量重建,快照大小若为几十 GB,重建时间影响 RTO。设计上要把快照切片、并行加载。
- 前置风控参数热更新。参数变更不应重启撮合,但热更又要保证同一订单看到的是一致视图。常见做法是双 buffer 切换。
十六、选型建议与落地清单
16.1 读者画像对应的选型
1)券商自研柜台 / 连接交易所侧的 OMS
不用追求 FPGA 级延迟(意义不大,瓶颈在交易所侧),但要:
- 会话复用 + 低延迟 TCP;
- 幂等 + 重传语义;
- 完整订单状态机,和 FIX 语义对齐;
- 严格前置风控 + 可审计日志;
- 数据库采用支持高并发单账户热点写入的方案(第 4 篇)。
2)量化策略 / 做市商接入层
- 选低延迟协议(FIX/FAST、SBE、OUCH);
- 专线或同机房托管(Colocation);
- 协议直连,不经过内部总线;
- 本地维护订单簿以避免等待回报;
- 时钟同步到 PTP。
3)自研现货 / 衍生品交易所(加密、新兴市场)
- 撮合引擎:C++ + Disruptor 风格、单核独占、事件流持久化;
- 前置风控:独立进程,串行在撮合前;
- 行情:内部总线 → 外部 WebSocket 广播;
- 清算:独立 Kafka 消费链,强一致账务数据库;
- 钱包:冷热分层 + MPC + 储备证明;
- 业务开始用 PostgreSQL/TiDB 足矣,撮合内核不依赖数据库。
4)去中心化交易所(DEX)
- AMM 还是订单簿要基于品种决定:稳定币和主流现货用 AMM,衍生品和长尾资产用订单簿;
- 订单簿上链:优先考虑应用链(Cosmos SDK / Substrate / Move)而非以太坊 L1;
- MEV 缓解:批量拍卖(Batch Auction)、密封订单(Encrypted Mempool);
- 链上风控:保证金计算可以链下算链上验证。
16.2 落地清单(MVP 版本)
一个中心化加密现货交易所的 MVP 落地清单:
这张清单上每一个条目都是一个迭代周期,任何一个做不好都能让交易所在黑天鹅事件里崩溃。顺序很重要:账户和资金对账优先于撮合性能,风控优先于功能完备。
十七、深入:一条订单的完整旅程
为了把前面十六节的零碎模块串起来,这一节用一个具体的场景追踪一笔订单从产生到结算的完整旅程。场景设定:机构用户
A 通过 FIX 专线向 T 交易所提交一笔
BUY 10000 @ 180.50 的 AAPL 限价单。
17.1 T+0 09:30:01.120000000
A 的策略引擎生成委托指令。本地 OMS 打第一个纳秒时间戳
t_app,把订单封装为 FIX 35=D
报文,通过内核旁路(Solarflare
Onload)发到交易所边缘路由。
17.2 09:30:01.120003500(+3.5 μs)
交易所机房托管 Rack 内,边缘交换机镜像一路给 FPGA 前置风控卡,一路转发给软件网关。FPGA 在 320 ns 内完成可用资金、单笔上限、价格偏离三项检查,全部通过,直接把归一化后的二进制订单送入撮合引擎的无锁入口队列;软件网关同时把订单写入审计日志(异步、不阻塞)。
17.3 09:30:01.120004800(+1.3 μs)
撮合引擎的单一业务线程从 Ring Buffer 拿到订单。此时 AAPL
订单簿卖一为 180.50 7500 股(订单
O_m1,maker)、卖二 180.51 15000
股。撮合线程判定:
- 按价格时间优先,订单 A 在 180.50 吃掉 O_m1 的全部 7500 股;
- 剩余 2500 股按规则继续撮合 180.51?不,因为这是限价 180.50,剩余 2500 股挂入买一。
在同一次函数调用内:
- 生成 trade_id=T1,记录
(maker=O_m1, taker=A, price=180.50, qty=7500, ts_ns=...); - 将 O_m1 从订单簿移除;
- 在买一价档插入订单 A 剩余 2500 股;
- 输出 4 条事件到出口 Ring
Buffer:
Trade、BookUpdate(卖一被吃)、BookUpdate(买一新增)、ExecReport(A: partial fill + working)。
整个过程在 800 纳秒内完成,全部纯内存操作。
17.4 09:30:01.120006200(+1.4 μs)
事件进入出口分发器,分两路:
- 行情路:行情系统按 MBO/MBP 两种视角各自维护订阅者缓冲,在 ~8 μs 内通过组播送达所有订阅席位;L1 简化版本 ~12 μs 到达普通用户;
- 清算路:成交事件进入清算系统的 Kafka 主题,清算服务实时扣减 A 账户 USD 余额 7500 × 180.50 = 1,353,750,并在持仓表中新增 AAPL 7500 股的多头(临时,T+1 才过户)。做市商 M 账户同步减 AAPL 7500 股、增 USD 1,353,750。
17.5 09:30:01.120011000(+5 μs)
成交回报
ExecReport(partial, filled=7500, leaves=2500, avg=180.50)
回到 A 的 OMS。A 的策略再次基于新的仓位状态计算是否撤掉剩余
2500 股。
17.6 16:00:00.000
收盘。剩余挂单 A 的 2500 股未成交,按 DAY TIF
自动过期,生成 ExecType=Expired
事件。日终撮合引擎把快照序号 seq=<final>
冻结。
17.7 T+0 晚间批处理
- 清算所(DTCC NSCC 部分)进行多边净额轧差(Multilateral Netting):A 账户当日合计净买 AAPL 若干股,净付 USD 若干;
- 生成 T+1 应收应付清单;
- CCP 开始为 T+1 交收做保证金计算和资金调度。
17.8 T+1 09:00 美东
- A 的托管行向 DTC 交付 USD;
- DTC 把对应 AAPL 股份从卖方账户过户到 A 的托管账户;
- DvP(Delivery versus Payment)在同一时刻完成,任何一方违约则两边都不发生。
至此,一笔订单跨越 24 小时,从客户端的 1 纳秒时间戳开始,到最终在美国证券存管机构 DTC 完成过户,经手了网关、风控、撮合、行情、清算、净额、CCP、托管、DTC 九个以上独立系统。每个环节的错误都可能造成资金风险或合规问题——这就是交易所工程的复杂度。
十八、容量规划:交易所”单位”背后的数字
很多团队在设计交易所时卡在一个问题上:容量规划到底按什么单位做? 这里给出一组经验数字,仅供参考,不同市场差别巨大。
18.1 常见容量基准(公开资料汇编)
| 指标 | 纳斯达克 | 上交所 | Binance 现货 | CME Globex |
|---|---|---|---|---|
| 日订单量(峰值) | 约 1000 亿条消息/日(含行情) | 数十亿条消息/日 | 百亿级订单/日 | 数十亿条消息/日 |
| 日成交笔数 | 约 1–2 亿笔 | 数亿笔 | 数亿笔(全品种) | 数百万笔(主合约) |
| 单撮合实例峰值 TPS | 百万级 | 60 万级(公开) | 数十万级 | 百万级 |
| 端到端延迟(P50) | < 100 μs | < 100 μs | 数百 μs | < 100 μs |
| 端到端延迟(P99.99) | < 1 ms | < 1 ms | 数 ms | < 500 μs |
18.2 工程规划经验法则
- 行情消息量 ≈ 订单量 × 3–10:每条订单产生 1 条订单变化事件,每次成交额外产生 1 条 Trade 和若干 BookUpdate;大客户订阅 MBO 时倍数更高。
- 撤单量 ≈ 下单量的 80%–95%:在活跃品种和做市商策略为主的市场里,撤单量远高于新单量。容量必须按总消息量规划。
- 开盘集合竞价峰值 ≈ 盘中平均的 5–20 倍:设计撮合吞吐必须以开盘峰值为准。
- 订阅扇出 1:N 的 N 不要小于 1 万:即使内部直连机构也会有大量分支,行情分发必须以万级订阅者为目标。
18.3 存储规划
- 撮合事件流按每条 64–128 字节压缩前估算,日订单 10 亿条产生约 64–128 GB 原始日志;压缩后 1/5;保留 7 年(监管常见要求)约几十 TB/年;
- 行情快照按每 10 秒一张、每张几十 MB 估算,日产几 TB 原始;
- 订单数据库索引设计必须考虑”查看自己当日订单”与”风控历史回放”两类查询;
- 重要:事件流是真实 source of truth,订单/成交数据库只是物化视图,可以按需重建。
十九、常见面试与架构评审问题
最后列一组笔者在这个方向的同行聚会或面试中经常听到的问题,读者可以用作自我检查:
- 为什么撮合引擎不做成多线程并行?如果要多线程,可以在哪些边界上做?
- 一只股票同时分配到两个撮合实例为什么会破坏公平性?有没有例外?
- LMAX Disruptor 的核心创新是什么?Ring Buffer 和普通并发队列的区别在哪里?
- FIX 协议为什么在低延迟场景不是最佳选择?SBE/OUCH 相比有什么优势?
- 行情的快照+增量模式在什么情况下会出问题?如何设计恢复?
- 加密交易所和传统交易所在”结算”上最根本的区别是什么?
- 如果让你设计一个新的 DEX 订单簿上链方案,你会怎么折中 TPS 与去中心化程度?
- Flash Crash 和 Knight Capital 事件各自的首要工程教训是什么?
- PTP 和 NTP 的适用场景,以及在不可用时如何对客户端订单排序?
- 为什么说”前置风控要基于异常行为而不仅是规则”?具体可以用哪些指标?
答案散落在本篇和后续 16、17、18 篇里,留给读者主动拼装。
二十、可观测性:交易所的”仪表盘”
交易所的可观测性投入远远高于一般互联网系统,原因简单——几微秒的抖动可能是几千万美元的套利窗口,几毫秒的消息丢失可能触发监管介入。
20.1 四层监控视角
- 硬件层:网卡丢包、交换机端口错误、CPU 频率切换、PTP 漂移、FPGA 温度与错误计数;
- 进程层:撮合线程 CPU 占用率、Ring Buffer 水位、GC 停顿(若 Java)、页错误、上下文切换;
- 协议层:FIX 会话状态、序号连续性、心跳丢失、WebSocket 重连率;
- 业务层:订单拒单率、撤单占比、单合约 TPS、成交额偏离、做市商履约率、行情订阅扇出。
20.2 延迟归因(Latency Attribution)
端到端延迟必须能被拆解到每一段:
total = (t_net_in - t_app_send)
+ (t_risk_in - t_net_in)
+ (t_match_in - t_risk_out)
+ (t_match_out - t_match_in)
+ (t_md_out - t_match_out)
+ (t_exec_out - t_match_out)
+ (t_app_recv - t_exec_out)
每个时间戳来自硬件(NIC 时间戳)或用户态(RDTSC)采样。每天结束时按合约和会话维度给出 P50/P99/P99.99,异常值触发告警与工单。
20.3 审计与合规
所有订单事件、成交事件、风控决策、参数变更必须不可篡改地长期留存。常见做法:
- 事件日志顺序写入 append-only 文件,按天切片、哈希链接;
- 每日日志的 SHA-256 摘要在独立系统备份或上链;
- 对监管提供查询接口,通常要求能在 T+5 内交付任意一笔订单的全量生命周期。
MiFID II 要求 HFT 相关主体保留 5 年以上详细订单日志;中国证监会对证券经纪业务的电子数据保存要求也不低于 5 年。
二十一、测试、灰度与灾备演练
交易所软件不同于一般业务系统——错误的代价直接挂钩监管和真金白银。任何一次变更前的验证、上线时的灰度、事故时的灾备切换,都必须有工程化的方法论。
21.1 三层测试金字塔
- 单元测试:撮合核心函数、订单簿操作、边界条件(如撤单时订单簿为空、冰山单补充遇到自成交);
- 场景重放测试:用生产环境过去若干天的事件流喂给新版本撮合引擎,比对新旧版本的成交序列、订单簿终态;任何偏差都必须能解释;
- 端到端压测:在镜像环境模拟开盘集合竞价、黑天鹅插针、撤单风暴、行情订阅暴增四类场景,连续跑满 4 小时不抖动。
21.2 灰度上线
撮合引擎的灰度不同于互联网服务——不能按用户流量比例灰度(同一合约的订单不能分到两个实例)。典型做法:
- 按合约灰度:先选 1–2 个低流动性合约切到新版本,观察 1–2 周;再扩散到 10%、50%、100%;
- 影子模式:新老两套系统同时接收订单流,新系统只计算不落地,比对成交、订单簿;
- 回滚演练:上线当日必须预演回滚步骤,时间要求压到 5 分钟内。
21.3 灾备与切换
- 主备架构:主撮合实例写事件流到内部总线,备实例重放事件流保持同态;
- RPO = 0:事件流同步复制到备中心,主挂则备继续,零数据丢失;
- RTO < 30 s:切换过程中订单网关短暂拒单,切换完成后继续接收;
- 周度灾备演练:至少每周一次在非交易时段做主备切换;年度全市场级演练(国内交易所在休市日例行演练)。
21.4 混沌工程在交易所里的边界
互联网系统流行的 Chaos Monkey 在交易所环境里要非常小心:
- 可以注入的故障:磁盘 IO 延迟、网络丢包(在副本侧)、冷缓存、配置错误;
- 不能随意注入的:直接杀撮合核心进程、丢弃成交事件、篡改订单簿——这些只能在完全镜像环境演练;
- 核心原则:生产侧只注入”能被系统自愈的故障”,不能注入”需要人为干预才能恢复的故障”。
二十二、未来方向:交易所架构的下一个十年
本篇收尾时不妨把视线拉远。过去十年交易所架构最大的变化是:加密交易所把证券工程文化从机构圈普及到了所有软件工程师。下一个十年,几条值得关注的方向:
- 链上订单簿成熟化:dYdX v4、Hyperliquid、Aevo 等把 CLOB 推上链,工程性能逼近中心化交易所的 1/10,足以承载中小规模品种;
- MEV 工程成为主流:加密领域的 Flashbots、MEV-Boost、批量拍卖(CoW Protocol、UniswapX)正在重定义”公平撮合”的含义,这些概念未来可能反向影响传统市场;
- AI 做市:强化学习与大模型辅助策略生成已经在某些做市商内部规模化部署,交易所侧需要更强的异常检测来应对策略同质化引发的系统性风险;
- 更短的结算周期:美股已经 T+1,T+0 的呼声持续;加密现货已经在”几秒钟”级别,稳定币链上结算会继续把”原子成交即结算”带进主流市场;
- FPGA/ASIC 更普及:头部做市商之外,中型券商和交易所也开始使用 SmartNIC 把撮合前处理下沉到硬件;
- 去中心化身份与合规:KYC、AML 在链上的零知识证明实现(例如 Polygon ID、Sismo、zkPass)为 DEX 的合规路径提供可能。
这些方向将在系列的最后一篇(第 25 篇《金融科技工程展望》)做收束。
二十三、与本系列相关文章的衔接
- 第 2 篇《钱的建模》:价格 tick 整数化、金额精度;
- 第 3 篇《复式记账工程化》:成交落账的借贷模型;
- 第 4 篇《账务数据库设计》:热点账户、分片;
- 第 11 篇《清算 vs 结算 vs 资金归集》:T+N、DvP/PvP;
- 第 14 篇《数字人民币、稳定币与 CBDC》:加密交易所的链上出入金;
- 第 16 篇《撮合引擎实现》:订单簿数据结构、撮合算法、确定性重放的深度展开;
- 第 17 篇《行情分发:MBP/MBO、快照+增量、组播/TCP、FIX/ITCH》:本篇行情章节的下钻;
- 第 18 篇《证券登记结算》:CCP、T+1、DvP 的深度展开;
- 第 19 篇《实时风控引擎》:本篇清算风控的规则引擎与特征工程;
- 第 24 篇《金融级可靠性》:交易所双活、单元化、RPO/RTO。
二十四、参考资料
- NYSE Pillar 架构白皮书:https://www.nyse.com/publicdocs/nyse/markets/nyse/NYSE_Pillar_Gateway_Fix.pdf
- Nasdaq Market System 简介:https://www.nasdaq.com/solutions/nasdaq-market-technology
- CME Globex 参考:https://www.cmegroup.com/confluence/display/EPICSANDBOX/CME+Globex
- LMAX Disruptor 论文(Martin Thompson 等):https://lmax-exchange.github.io/disruptor/disruptor.html
- SEC/CFTC《2010 Flash Crash 联合调查报告》(2010-09-30):https://www.sec.gov/news/studies/2010/marketevents-report.pdf
- Knight Capital 事故 SEC 调查结论(2013-10-16):https://www.sec.gov/litigation/admin/2013/34-70694.pdf
- SEC Rule 15c3-5(Market Access Rule):https://www.sec.gov/rules/2010/11/risk-management-controls-brokers-or-dealers-market-access
- MiFID II 时间戳精度(ESMA/2015/1464):https://www.esma.europa.eu/sites/default/files/library/2015/11/2015-esma-1464_-_final_report_-_draft_rts_and_its_on_mifid_ii_and_mifir.pdf
- 上交所新一代交易系统公告(2019):https://www.sse.com.cn/aboutus/mediacenter/hotandd/c/c_20190816_4889237.shtml
- 中国证监会《证券交易所管理办法》:http://www.csrc.gov.cn/csrc/c100028/common_list.shtml
- Binance Engineering Blog:https://www.binance.com/en/blog/engineering
- dYdX v4 白皮书:https://dydx.exchange/dydx-chain-whitepaper.pdf
- Hyperliquid 官方文档:https://hyperliquid.gitbook.io/hyperliquid-docs
- Uniswap v4 白皮书:https://github.com/Uniswap/v4-core/blob/main/docs/whitepaper/whitepaper-v4.pdf
- DPDK 官方文档:https://doc.dpdk.org/
- IEEE 1588 PTP:https://standards.ieee.org/ieee/1588/6825/
上一篇:《数字人民币、稳定币与 CBDC:双层运营、离线支付、链上/链下清算》
下一篇:《撮合引擎实现:撮合算法、价格优先时间优先、状态机、低延迟工程》
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【金融科技工程】撮合引擎实现:撮合算法、价格优先时间优先、状态机、低延迟工程
深入剖析中央限价订单簿(CLOB)撮合引擎的数据结构与算法,覆盖价格时间优先、Pro-Rata、订单类型、自成交预防、集合竞价、确定性回放、WAL 快照、单线程事件循环与 Disruptor 模型,并给出 Rust/Go 简化实现与单元测试清单。
【金融科技工程】金融科技工程全景:从支付到交易所的系统分类与读图
金融科技(FinTech)不是普通后端加一张账户表。钱的原子性、监管的硬边界、一个小数点的代价,把这个领域推进到工程强度最高的那一档。本文是【金融科技工程】25 篇的总目录与阅读地图:先交代为什么它比一般业务系统更难,再给出对账体、支付体、交易体、风控合规体四维分类,把后续 24 篇挂到骨架上,最后给出一份绿地项目的落地顺序建议。
【金融科技工程】行情分发:MBP/MBO、快照+增量、组播/TCP、FIX/ITCH
从 L1/L2/L3 分级、FIX FAST/ITCH/SBE 协议到 UDP 组播+重传通道、内核旁路与微波传输,系统梳理交易所行情系统的生产、分发与消费;给出 snapshot+incremental 恢复机制、Conflation 与 Full Tick 权衡、kdb+/ClickHouse/QuestDB tick 存储、事件时间回放与 K 线合成实现,并附 Binance WebSocket Diff Depth 维护本地订单簿的 Go/Python 示例。
金融科技工程
面向中国工程团队的金融科技系列。从账务底盘、支付、清结算、交易所、风控合规到可靠性与灾备,中国与全球视角并举,讲清楚金融系统在工程落地中的真实挑战。