订单簿是交易系统的核心,其内部状态变化逻辑深刻影响着撮合效率与市场行为。本文将通过多个具体示例,深入解析订单簿中订单状态的完整生命周期。
首先,我们回顾一下订单簿的抽象层次结构。通常,一个限价订单簿可以抽象为4个层次和5个级别(此为个人便于理解的小结,并非行业标准定义)。
4层次模型:描述了数据的逻辑包含关系。
orderbook (第1层) -> asktree/bidtree (第2层) -> pricelevel (第3层) -> order (第4层)
5级别模型:描述了数据结构的层级关系。
orderbook (第1级) -> asktree/bidtree (第2级) -> pricelevel (第3级) -> orderlist (第4级) -> order (第5级)
通过这个模型,你可以在脑海中构建出一棵清晰的“订单簿树”。

其界面呈现通常如下所示:

订单簿中每个价格档位(Price Level)包含三个关键元素:价格、该价格下的总委托数量以及订单列表。订单列表通常按照下单时间先后排序(FIFO,先进先出)。Ask Tree(卖单树)中的最低卖价与Bid Tree(买单树)中的最高买价之间的差值,即为买卖价差。
下面,我们通过一系列示例,以“剩余委托数量(LeftQty)”的变化为线索,直观展示订单簿内部的状态流转。
一、示例1:单个订单的完整生命周期(按手数交易)
订单信息
- OrderNO: 10001
- 方向:买单
- 价格:10.00元
- 初始数量:5手(500股)
时间线变化
09:30:00 - 订单添加
MsgRecord: OrderNO: 10001 MsgType: 6 Qty: 5 LeftQty: 5
订单簿状态:
订单簿 = {
"买一(10.00)": [
{"OrderNO": 10001, "价格": 10.00, "数量": 5} # 5手
]
}
# 累计LeftQty: 5
09:31:15 - 部分成交1手
MsgRecord: OrderNO: 10001 MsgType: 1 Qty: 1 LeftQty: -1
订单簿状态:
订单簿 = {
"买一(10.00)": [
{"OrderNO": 10001, "价格": 10.00, "数量": 4} # 5-1=4手
]
}
# 累计LeftQty: 5 + (-1) = 4
09:32:45 - 部分成交2手
MsgRecord: OrderNO: 10001 MsgType: 1 Qty: 2 LeftQty: -2
订单簿状态:
订单簿 = {
"买一(10.00)": [
{"OrderNO": 10001, "价格": 10.00, "数量": 2} # 4-2=2手
]
}
# 累计LeftQty: 5 + (-1) + (-2) = 2
09:33:30 - 撤销1手
MsgRecord: OrderNO: 10001 MsgType: 5 Qty: 1 LeftQty: -1
订单簿状态:
订单簿 = {
"买一(10.00)": [
{"OrderNO": 10001, "价格": 10.00, "数量": 1} # 2-1=1手
]
}
# 累计LeftQty: 5 + (-1) + (-2) + (-1) = 1
09:34:10 - 剩余1手全部成交
MsgRecord: OrderNO: 10001 MsgType: 1 Qty: 1 LeftQty: -1
订单簿状态:
订单簿 = {
"买一(10.00)": [] # 订单被移除,价格档位消失
}
# 累计LeftQty: 5 + (-1) + (-2) + (-1) + (-1) = 0
二、示例2:多订单竞争同一价格档位(按手数)
初始状态
订单簿 = {
"买一(10.00)": [
{"OrderNO": 20001, "价格": 10.00, "数量": 3}, # 3手,先到
{"OrderNO": 20002, "价格": 10.00, "数量": 2} # 2手,后到
]
}
场景1:市场成交2手
09:35:00 - 成交2手(按时间优先)
MsgRecord: OrderNO: 20001 MsgType: 1 Qty: 2 LeftQty: -2
订单簿状态:
订单簿 = {
"买一(10.00)": [
{"OrderNO": 20001, "价格": 10.00, "数量": 1}, # 3-2=1手
{"OrderNO": 20002, "价格": 10.00, "数量": 2} # 不变
]
}
场景2:新增同价格订单
09:35:15 - 新增订单20003,价格10.00,数量4手
MsgRecord: OrderNO: 20003 MsgType: 6 Qty: 4 LeftQty: 4
订单簿状态:
订单簿 = {
"买一(10.00)": [
{"OrderNO": 20001, "价格": 10.00, "数量": 1},
{"OrderNO": 20002, "价格": 10.00, “数量": 2},
{"OrderNO": 20003, “价格": 10.00, “数量": 4} # 添加到队列末尾
]
}
场景3:大额成交6手
09:36:00 - 成交6手
成交顺序(时间优先原则):
- 订单20001的1手(全部成交)
- 订单20002的2手(全部成交)
- 订单20003的3手(部分成交)
相关消息记录:
# 成交订单20001的1手
MsgRecord: OrderNO: 20001 MsgType: 1 Qty: 1 LeftQty: -1
# 成交订单20002的2手
MsgRecord: OrderNO: 20002 MsgType: 1 Qty: 2 LeftQty: -2
# 成交订单20003的3手
MsgRecord: OrderNO: 20003 MsgType: 1 Qty: 3 LeftQty: -3
订单簿状态:
订单簿 = {
"买一(10.00)": [
{"OrderNO": 20003, "价格": 10.00, "数量": 1} # 4-3=1手
]
}
三、示例3:价格档位的变化(按手数)
初始订单簿
订单簿 = {
"买一(10.10)": [
{"OrderNO": 30001, "价格": 10.10, "数量": 2} # 2手
],
"买二(10.05)": [
{"OrderNO": 30002, “价格": 10.05, “数量": 3} # 3手
],
"买三(10.00)": [
{"OrderNO": 30003, “价格": 10.00, “数量": 4} # 4手
]
}
步骤1:买一价成交2手
09:40:00 - 成交2手
MsgRecord: OrderNO: 30001 MsgType: 1 Qty: 2 LeftQty: -2
订单簿状态:
订单簿 = {
"买一(10.05)": [ # 原买二升级为买一
{"OrderNO": 30002, “价格": 10.05, “数量": 3}
],
"买二(10.00)": [ # 原买三升级为买二
{"OrderNO": 30003, “价格": 10.00, “数量": 4}
]
# 买三暂时为空
}
步骤2:新增更高价格订单
09:40:30 - 新增订单30004,价格10.15,数量5手
MsgRecord: OrderNO: 30004 MsgType: 6 Qty: 5 LeftQty: 5
订单簿状态:
订单簿 = {
"买一(10.15)": [ # 新订单成为买一
{"OrderNO": 30004, “价格": 10.15, “数量": 5}
],
"买二(10.05)": [
{"OrderNO": 30002, “价格": 10.05, “数量": 3}
],
"买三(10.00)": [
{"OrderNO": 30003, “价格": 10.00, “数量": 4}
]
}
步骤3:买二价部分成交2手
09:41:00 - 成交2手(价格10.05)
MsgRecord: OrderNO: 30002 MsgType: 1 Qty: 2 LeftQty: -2
订单簿状态:
订单簿 = {
"买一(10.15)": [
{"OrderNO": 30004, “价格": 10.15, “数量": 5}
],
"买二(10.05)": [
{"OrderNO": 30002, “价格": 10.05, “数量": 1} # 3-2=1手
],
"买三(10.00)": [
{"OrderNO": 30003, “价格": 10.00, “数量": 4}
]
}
四、示例4:买卖方订单簿互动(按手数)
初始状态(买卖双方)
买单簿 = {
"买一(10.00)": [
{"OrderNO": 40001, “价格": 10.00, “数量": 5}, # 5手
{"OrderNO": 40002, “价格": 10.00, “数量": 3} # 3手
],
"买二(9.95)": [
{"OrderNO": 40003, “价格": 9.95, “数量": 4} # 4手
]
}
卖单簿 = {
"卖一(10.05)": [
{"OrderNO": 50001, “价格": 10.05, “数量": 2} # 2手
],
"卖二(10.10)": [
{"OrderNO": 50002, “价格": 10.10, “数量": 3} # 3手
]
}
# 买卖价差:10.05 - 10.00 = 0.05元
场景1:新增卖单,价格10.00
09:45:00 - 新增卖单50003,价格10.00,数量4手
MsgRecord: OrderNO: 50003 MsgType: 6 Qty: 4 LeftQty: 4
发生撮合:
- 与买一价(10.00)匹配。
- 成交顺序:先成交订单40001的5手,再成交订单40002的3手(时间优先)。
- 实际成交情况:订单40001成交4手,剩余1手;订单40002未成交(因为订单40001已满足全部4手需求)。
相关消息记录:
# 订单40001成交4手
MsgRecord: OrderNO: 40001 MsgType: 1 Qty: 4 LeftQty: -4
# 卖单50003全部成交
MsgRecord: OrderNO: 50003 MsgType: 1 Qty: 4 LeftQty: -4
订单簿状态变化后:
买单簿 = {
"买一(10.00)": [
{"OrderNO": 40001, “价格": 10.00, “数量": 1}, # 5-4=1手
{"OrderNO": 40002, “价格": 10.00, “数量": 3} # 不变
],
"买二(9.95)": [
{"OrderNO": 40003, “价格": 9.95, “数量": 4}
]
}
卖单簿 = {
"卖一(10.05)": [
{"OrderNO": 50001, “价格": 10.05, “数量": 2}
],
"卖二(10.10)": [
{"OrderNO": 50002, “价格": 10.10, “数量": 3}
]
}
# 卖单50003已成交消失
场景2:新增卖单,价格9.95
09:45:30 - 新增卖单50004,价格9.95,数量6手
MsgRecord: OrderNO: 50004 MsgType: 6 Qty: 6 LeftQty: 6
发生撮合:
- 与买一价(10.00)匹配(对手方价格优先,卖单价格9.95,但可以以更好的价格10.00成交)。
- 成交价格:10.00元。
- 成交顺序:先买一价10.00,再买二价9.95。
成交细节:
- 先成交订单40001的1手(买一价10.00)。
- 再成交订单40002的3手(买一价10.00)。
- 再成交订单40003的2手(买二价9.95)。
- 总计成交6手,满足卖单需求。
相关消息记录:
# 订单40001成交1手
MsgRecord: (OrderNO: 40001, MsgType: 1, Qty: 1, LeftQty: -1)
# 订单40002成交3手
MsgRecord: (OrderNO: 40002, MsgType: 1, Qty: 3, LeftQty: -3)
# 订单40003成交2手
MsgRecord: (OrderNO: 40003, MsgType: 1, Qty: 2, LeftQty: -2)
# 卖单50004全部成交
MsgRecord: (OrderNO: 50004, MsgType: 1, Qty: 6, LeftQty: -6)
订单簿状态:
买单簿 = {
# 买一价10.00已无订单
"买一(9.95)": [
{"OrderNO": 40003, “价格": 9.95, “数量": 2} # 4-2=2手
]
# 买二价暂时为空
}
卖单簿 = {
"卖一(10.05)": [
{"OrderNO": 50001, “价格": 10.05, “数量": 2}
],
"卖二(10.10)": [
{"OrderNO": 50002, “价格": 10.10, “数量": 3}
]
}
# 买卖价差:10.05 - 9.95 = 0.10元
五、示例5:集合竞价场景(按手数)
集合竞价开始(09:15)
买单簿 = {
"买一(10.00)": [
{"OrderNO": 60001, “价格": 10.00, “数量": 10} # 10手
],
"买二(9.95)": [
{"OrderNO": 60002, “价格": 9.95, “数量": 5} # 5手
]
}
卖单簿 = {
"卖一(10.05)": [
{"OrderNO": 70001, “价格": 10.05, “数量": 8} # 8手
],
"卖二(10.10)": [
{"OrderNO": 70002, “价格": 10.10, “数量": 12} # 12手
]
}
新增订单影响价格
09:18:00 - 新增卖单70003,价格10.00,数量3手
MsgRecord: OrderNO: 70003 MsgType: 6 Qty: 3 LeftQty: 3
撮合情况:与买一价10.00匹配,成交3手。(集合竞价期间仅模拟撮合,不立即更新订单簿状态和LeftQty)
买单簿 = {
"买一(10.00)": [
{"OrderNO": 60001, “价格": 10.00, “数量": 7} # 10-3=7手
],
"买二(9.95)": [
{"OrderNO": 60002, “价格": 9.95, “数量": 5}
]
}
卖单簿 = {
"卖一(10.00)": [ # 新价格档位
{"OrderNO": 70003, “价格": 10.00, “数量": 0} # 已全部成交
],
"卖二(10.05)": [
{"OrderNO": 70001, “价格": 10.05, “数量": 8}
],
"卖三(10.10)": [
{"OrderNO": 70002, “价格": 10.10, “数量”: 12}
]
}
# 注意:集合竞价期间撮合计算成交量和价格,但LeftQty待9:25统一计算更新。
09:20:00 - 新增买单60003,价格10.05,数量6手
MsgRecord: OrderNO: 60003 MsgType: 6 Qty: 6 LeftQty: 6
(此订单将和卖一价10.00或10.05进行撮合计算)
集合竞价结束(09:25:00)
假设最终成交价确定为:10.00元,成交总量为:9手。
成交分配模拟:
- 卖单70003的3手(价格10.00) ↔ 买单60001的3手。
- 卖单70001的6手(价格10.05,但根据规则降价到成交价10.00) ↔ 买单60001的剩余4手 + 买单60003的2手。
最终订单簿状态(开盘后,反映未成交部分):
买单簿 = {
"买一(10.00)": [
{"OrderNO": 60001, “价格": 10.00, “数量": 3}, # 7-4=3手
{"OrderNO": 60003, “价格": 10.05, “数量”: 4} # 6-2=4手,价格调整到成交价10.00
],
"买二(9.95)": [
{"OrderNO": 60002, “价格": 9.95, “数量": 5}
]
}
卖单簿 = {
"卖一(10.05)": [ # 70001已部分成交,剩余2手
{"OrderNO": 70001, “价格": 10.05, “数量”: 2} # 8-6=2手
],
"卖二(10.10)": [
{"OrderNO”: 70002, “价格": 10.10, “数量": 12}
]
# 卖单70003已全部成交
}
通过以上五个由简入繁的示例,我们清晰地演示了订单在簿记系统中的完整旅程。理解这些状态变化的底层逻辑,是设计高性能、高可靠的交易撮合引擎的关键。无论是处理常规的连续竞价,还是特殊的集合竞价场景,系统都需要在价格优先、时间优先的核心原则下,精准、高效地维护订单簿的树形层次结构,并确保在多订单竞争、价格档位动态变化等复杂并发场景下的数据一致性。对于构建此类低延迟金融系统,采用现代化的云原生架构和优化的数据结构往往是实现业务目标的技术基石。