设计股票交易所
· 阅读需 17 分钟
需求
买入
和卖出
订单的订单匹配系统。订单类型:- 市场订单
- 限价订单
- 止损订单
- 完全成交或取消订单
- 订单有效期
- 为数百万用户提供高可用性和低延迟
- 异步设计 - 广泛使用消息队列(顺便提一下,副作用:工程师在一个服务上发布到队列,不知道下游服务具体在哪里,因此无法做坏事。)
架构
组件及其相互作用
订单匹配系统
- 按股票代码分片
- 订单的基本数据模型(其他元数据省略):
Order(id, stock, side, time, qty, price)
- 订单簿的核心抽象是匹配算法。有许多匹配算法(参考 stackoverflow,参考 medium)
- 示例 1:价格-时间 FIFO - 一种将二维向量投射或展平为一维向量的方式
- x 轴是价格
- y 轴是订单。价格/时间优先队列,FIFO。
- 买方:按价格升序,按时间降序。
- 卖方:按价格升序,按时间升序。
- 换句话说
- 买方:价格越高,订单越早,越接近匹配中心。
- 卖方:价格越低,订单越早,越接近匹配中心。
x 轴
y 轴投射到 x 轴上
Id Side Time Qty Price Qty Time Side
---+------+-------+-----+-------+-----+-------+------
#3 20.30 200 09:05 卖出
#1 20.30 100 09:01 卖出
#2 20.25 100 09:03 卖出
#5 买入 09:08 200 20.20
#4 买入 09:06 100 20.15
#6 买入 09:09 200 20.15
来自 Coinbase Pro 的订单簿
- 示例 2:按比例分配
如何实现价格-时间 FIFO 匹配算法?
- 按股票分片,CP 优于 AP:一股一个分区
- 有状态的内存树图
- 定期迭代树图以匹配订单
- 使用 Cassandra 进行数据持久化
- 订单匹配服务的进出请求通过消息队列进行
- 故障转移
- 内存树图快照到数据库
- 在错误情况下,从快照恢 复并与缓存去重
如何实时将订单簿数据传输到客户端?
- websocket
如何支持不同类型的订单?
- 在树图中使用相同的
卖出或买入:数量 @ 价格
,但具有不同的创建设置和匹配条件- 市场订单:以最后市场价格下单。
- 限价订单:以特定价格下单。
- 止损订单:以特定价格下单,并在特定条件下匹配。
- 完全成交或取消订单:以特定价格下单,但仅匹配一次。
- 订单有效期:以特定价格下单,但仅在给定时间范围内匹配。
订单服务
- 保留所有活动订单和订单历史。
- 接收到新订单时写入订单匹配。
- 接收匹配的订单并与外部清算所结算(异步外部网关调用 + 定时任务同步数据库)