想象一下股票市场就像一个农贸市场。

每支股票就像市场中的一个摊位区域,人们聚集在这里买卖产品。更多的交易为证券交易所带来更多手续费利润。所以他们的工作是促进尽可能多的”交易”。每个卖家可以设立摊位并指定他们愿意出售的价格。

如果没人买,他们可能会降低价格。

订单簿

买家想要最便宜的价格,所以他们通常会先去报价最低的摊位。

在”理想”世界中,买家会排成一队,按照他们愿意支付的价格排序以保证公平。这意味着出价更高的买家站在更前面。此外,买家可以通过改变他们愿意支付的价格来调整他们在队列中的位置。当买家的价格达到或超过卖家的价格时,交易就会发生。

这就是交易所匹配他们的时候!

买卖订单匹配

简单来说:

  • BUY 订单按降序排序(最高出价优先)
  • SELL 订单按升序排序(尽可能便宜买入)
  • 它们重叠的点是市场价格

在现实中,这要复杂得多……但这是基本思想。

核心需求

别担心,很简单!

  • 一个只交易股票的交易所
  • 用户可以下 BUY 或 SELL 订单
  • 用户也可以随时取消订单
  • 交易所必须实时匹配买家和卖家
  • 并且限制用户每天可以交易的股票数量
  • 它还应该实时发布市场数据

交易所让交易变得公平和透明。

在大多数交易所中:

  • 新订单 ≈ 50% 消息
  • 取消订单 ≈ 40% 消息
  • 执行订单 ≈ 2% 消息
  • 其余是…噪音

消息类型分布

关键术语

经纪人(Broker): 一个应用或网站,让用户可以 BUY 或 SELL,并查看交易所的价格。

订单簿(Order Book): 一支股票的所有当前 BUY 和 SELL 订单列表,显示谁想买卖、多少数量、什么价格。

市价单(Market Order): 你不设定价格的 BUY 或 SELL 订单。它以当前市场价格立即执行,只要有足够的流动性。此外,它在订单簿中享有优先权。

限价单(Limit Order): 你选择”确切”价格的 BUY 或 SELL 订单。 例如:

  • 100买入100 买入 → 以100 或更低价格成交
  • 100卖出100 卖出 → 以100 或更高价格成交

价差(Spread): 最高 BUY 价格和最低 SELL 价格之间的差异。

利润公式: 利润 = 卖出价格 - 买入价格 (所以低买高卖)

系统架构

交易所与许多”外部”服务交互:

  • 在线聊天支持
  • CAPTCHA 实现
  • 用户数据管理和跟踪
  • 发送电子邮件、短信和移动应用通知的服务

但让我们关注核心设计本身……

它的架构是异步和事件溯源的。

以下是交易所的三个关键组件:

  • 经纪人(Broker) - 让人们在交易所买卖股票
  • 网关(Gateway) - 经纪人向交易所发送 BUY 或 SELL 订单的入口点
  • 匹配引擎(Matching Engine) - 匹配买卖订单以创建交易的组件

让我们深入探讨!

经纪人

经纪人与交易所交互以:

  • 发送订单请求 - 下订单、接收状态更新、访问交易信息
  • 接收市场数据 - 历史数据用于分析、流式传输实时交易数据等

经纪人架构

用户使用 REST API 和 WebSocket 进行实时数据传输连接到经纪人。而经纪人使用金融信息交换(FIX)协议与网关通信。

FIX 是一个双向通信协议,用于通过”公共网络”安全地交换数据。它为订单消息分配唯一的序列号。此外,它使用校验和消息长度来验证数据完整性。

它接收来自经纪人的订单,并将它们转换为交易所的内部格式。然后它将交易执行结果发送回用户。也可以将网关放在交易所服务器附近(托管)以实现低延迟。

网关架构

网关有三个关键部分:

  • 风险管理器 - 确保用户有足够资金并阻止任何异常交易活动。此外,它确定交易所费用
  • 钱包 - 存储用户的交易资金和资产
  • 订单管理器 - 为公平性分配序列号并更新订单状态。此外,它将清除的订单发送到匹配引擎

让我们深入探讨……

网关用风险管理器和钱包服务验证订单。

然后它将请求传递给订单管理器。把订单管理器想象成一个包含所有订单的轻量级列表:未结、已取消和已拒绝的订单。它更新订单状态并处理取消请求。

订单管理器为每个订单(交易或取消)和执行填充(对于 BUY 和 SELL)分配一个全局递增的序列号。

订单管理器

序列号保证:

  • 公平性、及时性和准确性的排序
  • 快速恢复和确定性重放
  • 精确一次保证

此外,序列号使查找入站和出站序列中缺失的事件变得容易。

清除后,订单管理器将订单路由到匹配引擎。

消息队列

每种消息类型(新订单、取消、交易)都有自己的主题队列,有自己的序列号。这种分离有助于:

  • 维护每个流内的顺序
  • 独立处理每种消息类型并减少竞争
  • 使恢复更容易,因为交易所可以按确切顺序”重放”每个主题的事件

让我们继续!

匹配引擎

它验证序列号,匹配 BUY 和 SELL 订单,并基于交易创建市场数据。

匹配引擎有两个关键部分:

  • 订单簿 - 内存中的 BUY 和 SELL 订单列表
  • 匹配逻辑 - 匹配 BUY 和 SELL 订单并将那些交易结果作为市场数据发送

让我们深入探讨……

订单簿

它为每支股票(代码)维护一个内存中的未结订单列表。

实际上每支股票有两个列表:

  • 一个用于 BUY 订单
  • 另一个用于 SELL 订单

每个列表按价格和时间戳以先进先出(FIFO)方式排序。

订单簿结构

每个价格级别有一个单独的订单队列(双向链表):

  • 新订单添加到尾部 - O(1) 时间复杂度
  • 已填充或取消的订单使用指针从队列中移除 - O(1) 时间复杂度

它跟踪最高出价和最低要价以快速匹配。例如,BUY@96 和 SELL@98。

搜索所有价格级别和链表可能很慢 - O(n)。所以它使用索引将订单 ID 映射到内存中的订单对象:订单 ID → 指针(引用)。它允许通过索引在 O(1) 中按 ID 查找订单进行快速取消,然后将金额设置为 0。

已关闭的订单从订单簿中移除并添加到交易历史中。

匹配逻辑

它检查消息是否遵循正确的序列,并在以下情况下匹配 BUY 和 SELL 订单:

买入价格 ≥ 卖出价格

匹配逻辑

相同的订单序列(输入)必须始终产生相同的执行序列(输出)。所以匹配函数必须快速、准确且确定性。

本文为学习目的的个人翻译,译文仅供参考。

原文链接:Stock Exchange System Design

版权归原作者或原刊登方所有。本文为非官方译本;如有不妥,请联系删除。