2. 盘口基础与多档数据解析
要模拟大额卖单如何穿透多档盘口,第一步不是写撮合逻辑,而是先把“盘口”这个数据结构看透。限价订单簿(Limit Order Book,LOB)是交易所对当前所有未成交限价委托的组织方式,它按价格优先、时间优先排序,并分别维护买方和卖方两侧。理解它的字段、档位含义与更新机制,才能让后续的穿透计算有真实的输入基础。
一、限价订单簿的基本结构
订单簿的核心是两条按价格排序的队列:买方(Bid)价格从高到低排列,卖方(Ask)价格从低到高排列。最优买价(Best Bid)与最优卖价(Best Ask)之间的差额就是买卖价差(Spread)。每一侧通常只对外披露前若干档,形成“多档盘口”。以常见的十档盘口为例,卖方十档从卖一(最低卖价)向上递增,买方十档从买一(最高买价)向下递减。
每一档包含两个关键量:价格与挂单量。挂单量是该价位上所有未成交委托的数量总和,单位取决于标的,股票通常为“股”或“手”,期货为“手”,数字货币为“币”。需要特别注意的是,盘口展示的是“静态快照”,而真实订单簿是持续变化的:新委托进入、成交消耗、撤单都会改变某一档的数量甚至让该档消失。
二、盘口数据字段解析
一个标准的多档盘口快照通常包含以下字段,理解每个字段的语义是正确建模的前提:
| 字段 | 含义 | 建模时的作用 |
|---|---|---|
| symbol | 标的代码 | 区分不同合约/股票 |
| timestamp | 快照时间戳(毫秒/微秒) | 判断数据新鲜度与对齐 |
| bid_price[i] / bid_size[i] | 买方第 i 档价格与挂单量 | 卖单穿透时的消耗对象 |
| ask_price[i] / ask_size[i] | 卖方第 i 档价格与挂单量 | 买单穿透时的消耗对象 |
| last_price | 最新成交价 | 校验穿透后的成交均价 |
| spread | 买卖价差 | 衡量流动性与冲击成本起点 |
其中 bid_size 与 ask_size 是穿透模拟最核心的输入。举例来说,若买一价为 10.00 元、挂单量 5000 股,买二价 9.99 元、挂单量 8000 股,那么一笔 10000 股的卖单会先吃掉买一的 5000 股,剩余 5000 股继续消耗买二,最终成交均价约为 (10.00×5000 + 9.99×5000) / 10000 ≈ 9.995 元。这个简单算式正是多档穿透的雏形。
三、多档盘口的层级与流动性含义
档位越深,价格越不利,但往往挂单量越大。多档盘口实际上刻画了一条“流动性阶梯”:靠近盘口的一档流动性最好、冲击成本最低,越往后越稀疏。把各档挂单量按价格累加,可以得到“累计可成交量曲线”,它直接决定一笔大单能走多深、均价被拉低多少。这也是后续章节计算滑点和冲击成本的基础。
上图把订单簿的两侧结构、价差位置以及一笔 20000 股卖单的穿透路径放在同一视图中。可以看到,卖单从买一开始逐档消耗,累计到买三时已满足数量,因此成交止于买三,买四未被触及。这个“累计量 ≥ 委托量”的判断,就是多档穿透模拟最核心的循环条件。
四、常见盘口数据源与获取方式
不同市场的数据源差异较大,建模前要明确数据粒度与更新频率:
- 交易所官方行情:如上交所/深交所 Level-1(最优一档)与 Level-2(十档),期货交易所的深度行情。Level-2 提供多档快照,是穿透模拟的首选。
- 券商/期货公司柜台接口:通过 CTP、恒生等柜台获取,字段规范但需处理推送频率与快照对齐。
- 第三方数据服务:如 Wind、聚宽、Tushare 等,适合回测与研究,需注意其盘口为抽样或聚合后的快照。
- 数字货币交易所 WebSocket:如 depth 频道推送增量或全量盘口,更新频率高,需自行维护本地订单簿。
实际工程中,盘口数据常以“快照 + 增量”两种形式出现。快照是某一时刻的完整多档状态,增量只推送变化的价格档。若使用增量数据,必须在本地维护一份订单簿副本,按“先快照、后增量”的顺序重放,否则会出现档位错乱。下面是一段简化的增量更新伪代码,体现“定位档位—覆盖或删除”的处理逻辑:
# 本地订单簿:bids/asks 为 {价格: 数量} 字典
def apply_delta(side, price, size):
book = bids if side == "bid" else asks
if size == 0:
book.pop(price, None) # 数量为 0 表示该档被撤空
else:
book[price] = size # 覆盖该档挂单量
# 重排后取前 N 档作为盘口快照
sorted_prices = sorted(book, reverse=(side == "bid"))
return [(p, book[p]) for p in sorted_prices[:10]]
这段代码的关键在于:数量为 0 时必须删除该档,而不是保留为 0,否则后续累计成交量会把“空档”误算进去。很多穿透模拟的偏差,恰恰来自对增量数据的处理不严谨。
五、建模前的数据检查清单
在把盘口数据送入穿透模型之前,建议先做几项基础校验,避免“垃圾进、垃圾出”:
- 检查 bid_price[0] < ask_price[0],若出现买价高于卖价,说明数据错位或跨市场拼接错误。
- 检查各档价格严格单调:买方递减、卖方递增,出现乱序需重新排序。
- 检查挂单量非负,且累计量足以覆盖待模拟委托量,否则需标记“深度不足”。
- 核对时间戳与成交回报的时间差,过大的延迟会让快照失去参考意义。