2. 盘口快照数据结构解析
盘口快照(Order Book Snapshot)是行情系统在某一时刻对订单簿状态的完整切片。理解它的字段组成,是后续做逐笔事件联动、盘口重建和信号计算的前提。本节围绕三个问题展开:快照里到底有哪些字段、不同市场的快照差异在哪里、以及如何实际获取并解析一份快照。
一、快照的字段组成
一份典型的十档快照,可以拆成四组字段。第一组是时间与标识:交易所时间戳(精确到毫秒或微秒)、本地接收时间戳、合约代码、交易所代码。第二组是买卖十档量价:买一至买十的价格与数量、卖一至卖十的价格与数量,共 40 个数值字段。第三组是衍生指标:最新价、成交量、成交额、持仓量、昨收价、涨跌停价等。第四组是统计与状态:买卖总量、加权平均价、盘口价差等。
这里要特别注意两个约定。其一,价格与数量的对齐关系:买盘价格从高到低排列(买一最高),卖盘价格从低到高排列(卖一最低),档位索引 i 对应第 i 档,价格数组与数量数组必须同下标一一对应,否则重建盘口时会错位。其二,时间戳的参照系:交易所时间戳是撮合系统打上的,本地时间戳是行情网关收到数据时打上的,两者之差反映链路延迟,做逐笔联动时必须明确用哪一个作为事件排序依据,全文保持一致。
二、不同市场的快照差异
股票、期货、数字货币三类市场的快照结构差异明显,直接影响解析代码的写法。
股票市场(以 A 股为例):快照通常包含买卖十档,但价格受涨跌停限制,且存在集合竞价阶段,此时盘口可能只有虚拟撮合价而无真实挂单。字段上常见昨收、开盘、最高、最低、成交量(股)、成交额(元)。部分行情源只提供五档,需要确认档位深度。
期货市场:除十档量价外,必带持仓量和结算价,且合约有到期日,主力合约会切换。期货盘口还常见“开平仓”标志影响逐笔成交方向判断。夜盘与日盘的时间戳跨自然日,解析时不能简单按日期截断。
数字货币市场:档位深度往往远大于十档(常见 20 档甚至全量),数量为币本位小数,价格精度随交易对变化(如 BTC/USDT 价格精度 0.1,某些小币种精度 1e-8)。交易所通常提供 REST 快照 + WebSocket 增量推送的组合,快照自带 lastUpdateId 序列号,用于与增量流对齐。
三、快照的获取与样例解析
获取快照有两条常见路径。一是REST 拉取:向行情服务请求一次,得到当前时刻的完整快照,适合初始化盘口。二是WebSocket 订阅:服务端在盘口变化时推送快照或增量,适合实时联动。工程上通常先用 REST 拿一份基准快照,再用 WebSocket 增量流在其上叠加,并用序列号校验连续性。
下面是一份简化的数字货币快照 JSON 样例(示例数据,非实测),字段做了裁剪:
{
"symbol": "BTCUSDT",
"lastUpdateId": 1027024,
"exchangeTs": 1700000000123,
"localTs": 1700000000158,
"bids": [["42000.10","1.500"],["42000.00","0.800"],["41999.50","2.300"]],
"asks": [["42000.50","0.900"],["42001.00","1.200"],["42001.50","0.600"]],
"lastPrice": "42000.30",
"volume24h": "15234.78"
}
解析要点:bids 与 asks 是“价格-数量”二元组数组,价格是字符串而非浮点数,必须用高精度小数类型(如 Python 的 Decimal)解析,避免 42000.10 被存成 42000.099999。买一价 42000.10 高于买二价 42000.00,卖一价 42000.50 低于卖二价 42001.00,符合买盘降序、卖盘升序的约定。盘口价差 = 卖一价 − 买一价 = 0.40,中间价 = (42000.10 + 42000.50) / 2 = 42000.30。
再看时间戳:exchangeTs 为 1700000000123,localTs 为 1700000000158,链路延迟约 35 毫秒。做逐笔联动时,若用本地时间排序,需意识到这 35ms 的偏移会让快照与逐笔成交的先后关系产生系统性偏差;更稳妥的做法是以交易所时间戳为主键,本地时间仅用于监控链路质量。
四、解析后的校验清单
一份快照解析完,至少做三项校验再投入使用。第一,档位单调性:买盘价格严格递减、卖盘价格严格递增,出现逆序说明数据损坏或字段错位。第二,价差非负:卖一价应大于等于买一价,若为负说明买卖方向搞反。第三,序列号连续:与上一份快照的 lastUpdateId 比对,若出现跳号,说明中间丢失了增量,需要重新拉取基准快照重建盘口。这三项校验成本很低,却能拦住绝大多数解析层面的错误,是快照进入联动展示前的必要关口。