4. 快照行情协议解析入门

快照行情是交易所对外发布市场状态最基础、最常用的数据形态。它不像逐笔行情那样记录每一笔成交与每一次委托变化,而是在固定或事件触发的时间点上,对当前市场买卖盘、最新成交、累计成交量等关键信息做一次“切片”。理解快照协议,是后续做行情接入、盘口重建、策略信号计算的前提。

本节围绕快照字段含义、买卖盘档位、最新价与成交量、时间戳格式,以及交易所快照样例结构拆解展开,帮助你建立从“看到字段”到“读懂市场状态”的完整认知。

一、核心原理:快照是市场状态的切片

快照行情的本质,是把订单簿在某一时刻的可见状态压缩成一条结构化消息。交易所通常按固定频率(如每500毫秒、1秒)或按行情变化阈值推送快照。每条快照至少回答四个问题:

  • 谁:交易标的代码、交易所、市场类型。
  • 什么时间:行情时间戳、发送时间戳。
  • 买卖意愿:买一至买N、卖一至卖N的价格与数量。
  • 成交结果:最新价、成交量、成交额、开高低收等统计值。

与逐笔行情相比,快照丢失了订单簿变化的中间过程,但胜在数据量小、解析简单、对网络抖动容忍度高。对于中低频策略、盘口监控和行情展示,快照往往是首选。

关键认知:快照不是“实时全量订单簿”,而是交易所愿意公开的那一层盘口。不同交易所的档位深度、是否含隐藏单、是否含总委托量,差异很大。

二、买卖盘档位:从买一到买N的排列逻辑

买卖盘档位是快照中最核心的部分。通常用 BidPrice[1..N] 与 BidVolume[1..N] 表示买盘,用 AskPrice[1..N] 与 AskVolume[1..N] 表示卖盘。买一价格最高,卖一价格最低,买一与卖一之间的差额就是盘口价差。

档位深度N因交易所而异:有的只提供买一卖一,有的提供五档、十档,甚至二十档。档位越多,对订单簿的还原越精细,但消息体也越大。解析时要注意:

  1. 档位价格是否已排序,通常买盘降序、卖盘升序。
  2. 数量单位是股、手还是张,不同市场不同。
  3. 空档位如何表示,常见为价格0、数量0或直接缺省。
  4. 是否包含“总买量/总卖量”等汇总字段。

下面是一个典型的五档快照字段清单:

字段名 含义 示例 注意事项
Symbol 合约代码 IF2406 需与交易所定义一致
BidPrice1 买一价 3560.2 价格精度按最小变动价位
BidVolume1 买一量 12 单位可能是手
AskPrice1 卖一价 3560.4 卖一应大于买一
AskVolume1 卖一量 8 数量为0表示无挂单
LastPrice 最新价 3560.4 可能是成交价或结算价
Volume 累计成交量 152340 通常是当日累计
Turnover 累计成交额 5.42e9 注意单位与精度
UpdateTime 行情时间 20240607103000123 格式需按交易所解析

三、最新价、成交量与时间戳格式

最新价(LastPrice)是最近一笔成交的价格,但它不一定等于当前买一或卖一。若市场刚发生主动成交,最新价可能等于卖一或买一;若长时间无成交,最新价可能停留在历史位置。成交量(Volume)通常是当日累计值,解析时要区分“累计”与“增量”,避免重复累加。

时间戳格式是快照解析中最容易出错的环节。常见格式包括:

  • YYYYMMDDHHMMSSsss:如 20240607103000123,表示2024年6月7日10点30分00秒123毫秒。
  • Unix毫秒时间戳:如 1717727400123,需转换为本地时间。
  • 交易所自定义整型:如 103000123,表示10:30:00.123。

解析时间戳时,务必确认时区、是否含毫秒、是否为交易日内的相对时间。建议统一转换为UTC毫秒后再做策略计算。

下面是一段Python伪代码,演示如何解析常见快照时间戳:

def parse_exchange_time(ts: str):
    # 格式:YYYYMMDDHHMMSSsss
    if len(ts) == 17:
        dt = datetime.strptime(ts[:14], "%Y%m%d%H%M%S")
        ms = int(ts[14:17])
        return dt.replace(microsecond=ms * 1000)
    # 格式:Unix毫秒
    if len(ts) == 13:
        return datetime.fromtimestamp(int(ts) / 1000)
    raise ValueError("unknown time format")

四、交易所快照样例结构拆解

不同交易所的快照消息结构差异较大,但通常遵循“消息头 + 业务字段 + 校验”的分层模式。以某期货交易所的二进制快照为例,其结构可拆解为:

struct Snapshot {
    uint32  msgType;        // 消息类型,如1001表示快照
    char    symbol[16];     // 合约代码
    double  bidPrice[5];    // 买一至买五价
    uint32  bidVolume[5];   // 买一至买五量
    double  askPrice[5];    // 卖一至卖五价
    uint32  askVolume[5];   // 卖一至卖五量
    double  lastPrice;      // 最新价
    uint64  volume;         // 累计成交量
    double  turnover;       // 累计成交额
    uint32  updateTime;     // 时间,如103000123
    uint32  checksum;       // 校验和
};

解析这类结构时,要特别注意字节序(大端/小端)、字段对齐、浮点数精度和字符串截断。建议先用交易所提供的样例报文做单元测试,再接入实时流。

常见误区:直接把快照中的累计成交量当作增量使用,导致成交量重复计算;忽略时间戳时区,导致跨市场对齐错误;把空档位的价格0当作真实价格参与计算。

五、复盘:从一条快照到市场状态判断

假设你收到一条快照:买一3560.2/12手,卖一3560.4/8手,最新价3560.4,累计成交量152340手。你可以快速判断:

  • 盘口价差为0.2,流动性尚可。
  • 最新价等于卖一,说明最近一笔是主动买入。
  • 买一量大于卖一量,短期买压略强。
  • 累计成交量需与上一条快照对比,才能得到增量。

把多条快照按时间序列排列,就能还原出盘口变化、成交活跃度和价格趋势。这正是快照行情在实战中的核心价值:用有限的数据,稳定地刻画市场状态。

快照行情结构拆解与盘口状态判断 快照消息结构 消息头:类型 / 合约 / 时间 买盘:BidPrice[1..N] / BidVolume[1..N] 卖盘:AskPrice[1..N] / AskVolume[1..N] 成交:LastPrice / Volume / Turnover 校验:Checksum / 字节序 时间戳格式:YYYYMMDDHHMMSSsss 盘口状态判断 卖一 3560.4 × 8 卖二 3560.6 × 15 价差 = 0.2 买一 3560.2 × 12 买二 3560.0 × 20 最新价 3560.4 累计量 152340 判断:最新价=卖一,主动买入;买量>卖量,买压略强