2. 盘口数据基础

要理解盘口深度曲线与累计可成交量,第一步不是画曲线,而是把“盘口数据到底是什么形状”搞清楚。盘口数据本质上是订单簿(Order Book)在某一时刻的切片:它记录了买方向与卖方向上若干档位的价格和挂单数量。只有先明确订单簿的结构、字段含义以及快照与增量两种数据形态的差异,后续的深度曲线计算和累计可成交量推导才有可靠的数据基础。

一、订单簿的基本结构

订单簿是一个按价格优先、时间优先原则组织的双边队列。买盘(Bid)一侧按价格从高到低排列,卖盘(Ask)一侧按价格从低到高排列。最优买价(Best Bid)与最优卖价(Best Ask)之间的差额就是买卖价差(Spread),两者之间的区域称为价差区间。订单簿的“档位”通常用 Level 1、Level 2、Level 3 表示:Level 1 只含最优买卖价,Level 2 含多档聚合价格与数量,Level 3 则细化到单笔订单。本课程讨论的盘口深度主要基于 Level 2 的聚合档位数据。

需要特别强调一个约定:买盘价格从高到低、卖盘价格从低到高,这是“由内向外”的排列方向。后文所有“第 N 档”均指从最优价向外数的第 N 档,买盘第 1 档是最优买价,卖盘第 1 档是最优卖价。方向约定一旦确定,全文与图示保持一致,避免累计计算时把内外方向弄反。

二、价格与数量字段

一个典型的 Level 2 档位记录至少包含以下字段:

  • 价格(price):该档位的成交报价,通常以最小价格变动单位(tick size)为粒度。
  • 数量(size / quantity):该价位上当前挂单的总量,单位可能是股、手或张,取决于标的类型。
  • 方向(side):bid 或 ask,标识该档位属于买方还是卖方。
  • 档位序号(level):从最优价向外数的第几档。
  • 时间戳(timestamp):该档位数据对应的撮合时间或推送时间。

在实际数据中,数量字段的口径必须核对清楚:有的数据源给的是“该价位挂单总量”,有的给的是“该价位新增或撤销的变动量”,还有的以“手”为单位而价格以“元”为单位。口径不一致会直接导致累计可成交量算错一个数量级。因此拿到数据后,第一件事是确认价格单位、数量单位以及数量是绝对量还是变动量。

三、快照数据与增量数据

盘口数据按推送方式分为快照(Snapshot)与增量(Incremental / Delta)两类。快照是某一时刻订单簿的完整切片,包含当前所有档位的价格与数量,可以直接使用;增量数据只推送发生变化的部分,例如“卖一价从 10.02 变为 10.03,数量增加 500”,需要在前一状态基础上逐条应用才能还原当前订单簿。

两者的关键差异在于:快照自带完整状态、可独立解析,但数据量大、推送频率受限;增量数据量小、实时性高,但必须维护本地订单簿状态,且对丢包、乱序、重复极为敏感。工程上常见的做法是“快照打底 + 增量叠加”:先拉取一份快照建立本地订单簿,再持续应用增量更新,并定期用新快照做校准。若增量序列号出现跳号,说明中间有丢失,此时必须重新拉取快照重建,而不能继续叠加,否则本地订单簿会与真实市场持续偏离。

订单簿结构 · 快照与增量数据关系 卖盘 Ask(由内向外,价格递增) 卖5 10.06 800 卖4 10.05 1200 卖3 10.04 600 卖2 10.03 1500 卖1 10.02 1000 ← 最优卖价 买卖价差 Spread = 10.02 − 10.01 = 0.01 买1 10.01 1200 ← 最优买价 买2 10.00 900 买3 9.99 2000 买盘 Bid(由内向外,价格递减) 快照 Snapshot(完整切片) 包含全部档位:价格 + 数量 + 方向 + 时间戳 可独立解析,直接构建本地订单簿 数据量大,推送频率相对低 用途:初始化、定期校准、丢包后重建 示例:卖1 10.02 / 1000,买1 10.01 / 1200 增量 Delta(变化量) 只推送发生变化的档位与数量变动 必须叠加到本地状态,不能单独使用 数据量小、实时性高,依赖序列号保序 序列号跳号 → 丢弃本地状态,重新拉快照 示例:卖1 数量 1000 → 1500(+500)

四、获取方式与本地维护

获取盘口数据通常有两条路径:一是通过行情网关订阅推送,二是通过 REST 接口主动拉取快照。推送方式适合实时维护,拉取方式适合初始化与校准。以常见的行情接口为例,订阅后先收到一份快照,随后是带序列号的增量流。本地维护的核心逻辑可以概括为:

1. 拉取快照 snapshot,构建本地订单簿 book
2. 订阅增量流,逐条读取 delta(seq, side, price, size)
3. 若 seq == last_seq + 1:应用更新
     - size 为绝对量:book[side][price] = size
     - size 为变动量:book[side][price] += size
     - 若结果数量为 0:删除该档位
4. 若 seq 跳号或乱序:标记 book 失效,重新拉取快照
5. 定期(如每 30 秒)用新快照覆盖本地 book 做校准

这里有一个容易被忽略的细节:增量数据中的数量到底是绝对量还是变动量,必须依据数据源文档确认。若把变动量当绝对量覆盖,订单簿会迅速失真;若把绝对量当变动量累加,数量会越滚越大。判断方法之一是观察同一价位连续两条增量:若第二条数量明显小于第一条且价格未变,多半是绝对量;若数量呈小幅增减波动,则可能是变动量。

五、从订单簿到深度曲线

有了结构清晰的订单簿,深度曲线就有了原料。以买盘为例,从买1开始向外逐档累加数量,得到“价格—累计数量”的阶梯关系;卖盘同理。累计可成交量则是在给定价格约束下,把可成交的档位数量加总。例如市价卖出 2500 股,会依次吃掉买1的 1200 股、买2的 900 股、买3的 400 股,成交均价约为 (10.01×1200 + 10.00×900 + 9.99×400) / 2500 ≈ 10.0024 元。这个计算完全依赖订单簿档位的价格与数量字段是否准确、方向是否一致。

实践建议:在正式计算深度曲线前,先做一次数据自检——检查买1价是否小于卖1价、各档价格是否单调、数量是否非负、时间戳是否递增。这四项检查能拦截绝大多数因快照与增量混用导致的状态错误。

总结来说,订单簿提供了盘口的骨架,价格与数量字段是骨架上的血肉,快照与增量则决定了这份骨架如何被实时、准确地维护。把这三件事理清楚,后续的深度曲线绘制与累计可成交量计算才不会建立在错误的数据地基上。