现货交易

撮合系统架构设计

类 Binance 现货交易系统的完整架构设计,涵盖订单流转、撮合引擎、订单簿、K 线、存储与前端展示。

1. 系统总览

现货撮合系统由 6 个核心层组成,遵循「事件驱动 + 单线程撮合」的设计原则,通过 Kafka 解耦各服务,保证撮合的确定性与顺序性。

整体架构图

各层职责

① 客户端层

Web / App 通过 HTTPS REST 下单查询,通过 WebSocket 接收实时行情、订单状态推送。

② 接入层

API Gateway 负责路由、JWT 鉴权、Rate Limit 限流。WebSocket 网关维护长连接并订阅 Push Service 事件。

③ 核心业务层

Order Service 接收下单请求,调用 Risk Service 做风控校验(余额、仓位、价格合理性),通过后将订单事件发布到 Kafka。Account Service 管理冻结/解冻资金。

④ 消息总线(Kafka)

核心解耦层。order.new / trade.done / market.tick 三类 Topic 按交易对分区,保证同一交易对内顺序消费。

⑤ 撮合层

每个交易对一个单线程撮合进程,顺序消费 order.new,在内存 Order Book 中完成价格匹配,产生 trade.done 事件写回 Kafka。无锁、无 IO,极低延迟。

⑥ 下游处理层

Settlement Service 消费成交事件,更新账户余额并写入 PostgreSQL。Market Data Service 聚合成 K线并存入 TimescaleDB。Push Service 广播实时数据给 WebSocket 客户端。

核心设计原则

单线程撮合

每个交易对独立的单线程引擎,无锁竞争,撮合结果天然有序可重放

事件驱动

Kafka 解耦所有服务,任何服务崩溃可从 Kafka offset 重放恢复

内存优先

订单簿全量驻留内存(Redis 做快照),撮合全程无磁盘 IO

幂等处理

每笔 trade 有全局唯一 tradeId,下游服务幂等消费防止重复结算

水平扩展

按交易对分片,增加交易对只需扩容 Kafka 分区 + 撮合进程

故障恢复

撮合引擎重启后从 Redis 快照 + Kafka 未消费消息重建状态

2. 订单类型

限价单 Limit

以指定价格或更优价格成交,进入订单簿等待撮合

市价单 Market

立即以最优价格成交,不进订单簿

止损限价 Stop-Limit

触发价到达后转为限价单

止损市价 Stop-Market

触发价到达后转为市价单

IOC

Immediate or Cancel,立即成交剩余取消

FOK

Fill or Kill,必须全部成交否则取消

GTC

Good Till Cancel,一直挂单直到手动撤销

Post-Only

只做 Maker,若立即成交则拒绝

3. 下单流程

下单链路拆成「接入 → 风控 → 事件写入 → 撮合 → 回执 / 推送」,保证交易对内严格顺序。

同步返回

API 快速返回接收状态 + clientOrderId;撮合结果异步推送。

幂等

clientOrderId + userId 唯一;重复请求直接返回已有状态。

隔离

每个 symbol 一个 Kafka 分区 + 一个撮合进程,避免锁竞争。

补偿

任何环节失败可通过 Kafka offset 重放,资金冻结/解冻幂等。

4. 订单队列

Kafka 主题设计

  • order.new.{symbol}:生产者 Order Service;分区键=交易对,保证顺序;消费者=对应撮合进程。
  • trade.done.{symbol}:生产者 Matching Engine;消费者 Settlement / MarketData / Push。
  • cancel.req:生产者 API;消费者撮合引擎,用于从订单簿删除挂单。

消息体示例(order.new):

{
  "orderId": "snowflake",
  "clientOrderId": "web-123",
  "userId": 42,
  "symbol": "BTCUSDT",
  "side": "BUY",
  "type": "LIMIT",
  "price": "42000.5",
  "quantity": "1.2",
  "timeInForce": "GTC",
  "flags": { "postOnly": false, "reduceOnly": false },
  "ts": 1700000000000
}

5. 订单簿设计

订单簿在内存维护,两侧分离:买盘按价格从高到低,卖盘从低到高;同价位队列按时间先后。

数据结构

PriceLevel = 有序映射(price → FIFO 队列),全局用双向优先队列或跳表维持最佳价。

排序规则

价格优先、时间优先;Post-Only 在会立即成交时拒绝。

快照

Redis 定期持久化订单簿快照;重启后快照 + Kafka 未消费记录重放。

可视化

深度图/盘口展示直接消费 Push Service 的 orderBook 更新事件。

交互式订单簿模拟器 — 点击买入/卖出体验撮合
价格 (USDT)数量 (BTC)累计
42200.001.20008.5000
42150.002.80007.3000
42100.000.50004.5000
42050.001.20004.0000
42000.002.80002.8000
Spread: 50.00 (0.119%)
41950.001.50001.5000
41900.002.30003.8000
41850.001.80005.6000
41800.003.20008.8000
41750.002.000010.8000
系统就绪,可以开始下单

6. 撮合引擎

成交价格

按对手盘口最佳价成交;市价单一路吃穿价位;限价单价格保护。

时间复杂度

O(n) 随吃单层数递增;单线程无锁,避免并发开销。

状态更新

每次部分成交更新双方剩余数量与平均成交价,订单完成后写 trade.done。

风控钩子

匹配前后调用风险模块检查账户可用度/仓位限制,异常则中断并回滚该订单事件。

撮合过程逐步演示 — 点击「下一步」查看撮合
Step 0
Step 1
Step 2
Step 3
Step 4
Step 0: 新订单到达
收到限价买单: BUY 42050 × 3 BTC。检查卖盘是否有 ≤ 42050 的挂单。
42100.002.0000
42050.001.5000
42020.000.8000
42000.001.0000
41950.001.5000
41900.002.3000
方向BUY
限价42050
原始量3 BTC
剩余量3.0000 BTC
状态NEW

7. 拆单与部分成交

大单被视为一个订单在引擎内逐价位拆解;每次部分成交都生成 Trade 事件并更新订单状态。

Partial Fill

订单状态从 NEW → PARTIALLY_FILLED → FILLED;剩余量 & 累计成交额实时维护。

剩余挂单

限价单吃完可成交部分后,剩余量以原限价挂入订单簿;市价单若剩余且无流动性则触发 IOC/FOK 规则。

拆单策略

对手盘按价位逐级消耗,不需要预拆子单;每个撮合结果对应一个 tradeId。

滑点控制

可设置最差可接受价格;超过则停止继续吃单并回挂/取消。

8. 成交与结算

  • 结算幂等:tradeId 全局唯一,重复消费直接忽略或校验数量。
  • 余额模型:先冻结买单 quote,再消耗;卖单冻结 base。成交后释放剩余冻结并写实际成交数额。
  • 推送:订单状态、成交回报、账户余额变更通过 WebSocket / 事件总线广播。

9. 手续费计算

角色区分

Maker(挂单) vs Taker(吃单);撮合时即可判定角色。

费率模型

基础费率 * VIP 折扣 *(是否用平台币抵扣);合约支持资金费率/强平费用。

扣费顺序

优先使用抵扣币余额,不足时用成交币种扣取;费用记录在 trade.done 事件内。

审计

结算写入 fees 表并与订单表关联,支持按用户/交易对汇总。

10. 撤单机制

撤单同样通过 Kafka 统一处理,保证同一交易对顺序;避免直接操作内存导致竞态。

  • 客户端发送 cancel 请求(包含 orderId / clientOrderId / symbol);Order Service 校验归属与状态。
  • 写入 cancel.req,撮合进程按顺序消费,若订单仍在盘口则移除并生成 cancel.done。
  • 撤单幂等:不存在/已成交的订单返回当前状态,不重复解冻;成功撤单释放冻结资金。
  • FOK/IOC 在撮合阶段自动撤销未成交部分,无需额外指令。

11. 杠杆 / 做多做空

保证金模型

逐仓:每个仓位独立保证金;全仓:共享保证金池。下单时冻结所需保证金 + 手续费缓冲。

仓位方向

做多:买入基础资产;做空:借入基础资产卖出。下单标记 reduceOnly 防止反向加仓。

强平触发

基于 Mark Price 计算维持保证金率,低于阈值触发强平订单(系统单优先撮合)。

资金费率

合约按周期结算资金费率;对多/空分别扣/补,写入资金费率流水。

12. K 线系统

  • 实时聚合:收到成交事件更新当前窗口 OHLCV;窗口完成写入 TSDB/Redis 缓存。
  • 多周期:以 1m 为基础向上合成 5m/15m/1h;补齐缺口时插入空蜡烛。
  • 推送:WebSocket 订阅 K 线 / Ticker / 深度增量,客户端可按 symbol+interval 订阅。

K 线蜡烛图示例

下方展示 Canvas 渲染的蜡烛图,支持切换周期、鼠标悬停查看 OHLCV 详情:

13. 存储设计

Redis

热数据与盘口快照;Key 按 symbol 分片;TTL 快照用于快速恢复。

PostgreSQL

订单表(含状态/平均成交价/剩余量)、成交表(tradeId 唯一)、资金流水表、手续费表。

TimescaleDB

K 线 OHLCV、逐笔成交归档;支持按 symbol+interval hypertable。

Kafka

事件流事实来源,可按 offset 重放;持久化与报警监控确保可靠性。

14. 前端展示

行情面板

Ticker / 24h 数据订阅;行情列表可从 Market Data 服务获取缓存。

深度 & 成交

深度图/盘口表订阅 orderBook 增量;最近成交列表展示 trade.done。

下单面板

支持市价/限价/止损、Post-Only、IOC/FOK、杠杆倍数、reduceOnly;提交后展示状态和部分成交进度。

风险提示

展示预估成交价、最差滑点、占用保证金、可平仓数量;平仓按钮生成反向市价单。