2. 沪深逐笔委托数据格式总览
逐笔委托是Level-2行情中最基础、也最容易被低估的一类数据。它记录的是每一笔“新订单进入撮合系统”的事件,而不是成交结果。做字段映射之前,必须先建立一个整体认知:上交所和深交所的逐笔委托,在传输协议、消息组织方式、字段命名和语义约定上都有明显差异。如果一上来就逐字段对照,很容易在“序号含义”“频道归属”“价格单位”这些地方踩坑。本节先把两市的格式骨架摆清楚,为后续逐字段映射打地基。
一、两种协议形态:二进制与文本
上交所的逐笔委托以二进制流为主。典型场景是通过FAST协议或私有二进制协议下发,字段按固定偏移排列,整数用大端或小端字节序编码,价格、数量多为整型放大若干倍后的定点数。二进制的好处是紧凑、解析快,代价是必须严格依赖接口文档中的偏移量和类型定义,一旦错位,后续字段全部读错。
深交所的逐笔委托则常见文本与二进制并存。早期通过文本格式(如以分隔符切分的定长或变长记录)下发,字段以ASCII字符表示,可读性强、调试方便;后续版本也提供二进制格式以提升吞吐。文本协议的优势是字段边界直观,劣势是解析时要处理分隔符、空值、字符编码和数值转换。
因此,字段映射的第一步不是比对字段名,而是确认“当前拿到的是哪种协议形态”。同一个业务含义的字段,在二进制里是4字节整数,在文本里可能是右对齐的字符串,映射代码必须分别处理。
二、公共字段:消息头、消息体、序号与频道号
两市的数据都采用“消息头+消息体”的分层结构。消息头承载路由和定位信息,消息体承载业务字段。理解这个分层,是建立映射框架的关键。
消息头通常包含消息类型、消息长度、序号、频道号等。消息类型决定消息体如何解析;消息长度用于在流式数据中切分边界;序号用于排序和去重;频道号用于区分不同产品类别或不同撮合通道。
序号是最容易混淆的字段。上交所的序号往往在单个频道内连续递增,用于标识该频道内消息的先后顺序;深交所的序号语义则与具体频道和消息类型相关。映射时不能简单地把两边的“序号”画等号,而要明确:它是全局序号还是频道内序号?是否跨消息类型连续?是否在日间重置?这些语义差异直接影响去重和排序逻辑。
频道号是另一个关键公共字段。上交所按频道组织行情,不同频道对应不同产品集合;深交所也有类似的通道划分。频道号决定了“这条委托属于哪个撮合范围”,在合并多频道数据时,必须把频道号作为主键的一部分,否则不同频道的同序号消息会被错误覆盖。
三、业务字段的映射框架
消息体中的业务字段,核心是“谁、在什么时间、对什么产品、以什么价格、买卖多少、什么订单类型”。两市在这些字段上的命名和编码方式不同,但业务语义可以对齐。映射框架可以按以下层次组织:
- 标识层:订单编号、频道号、序号,用于唯一确定一笔委托;
- 产品层:证券代码、市场标识,用于定位标的;
- 方向层:买卖方向,注意两市对“买/卖”的编码值可能不同;
- 价格数量层:委托价格、委托数量,注意定点数放大倍数和单位;
- 类型层:订单类型(限价、市价、本方最优等),两市枚举值不一致;
- 时间层:委托时间,注意精度和时区约定。
下面这张图把两市的格式骨架和公共字段关系做了一个整体对照,帮助建立“先分层、再对齐”的认知。
四、映射时的三个实操判断
第一,先确认协议形态再写解析器。二进制解析要校验消息长度与偏移,文本解析要先切分再转数值。两者不能共用同一套读取逻辑。
第二,把序号和频道号作为联合主键。无论哪市数据,去重和排序都应基于“频道号+序号”,而不是单独用序号。跨频道合并时,这一点尤其重要。
第三,价格和数量要统一到同一量纲再比较。二进制常用整型放大(如价格乘以10000),文本可能是带小数点的字符串。映射层应先把两边都转成同一精度的定点整数或十进制,再做业务计算,避免浮点误差。
# 映射层伪代码示意(示例参数,非实测)
def normalize_order(raw, market):
if market == "SSE": # 上交所二进制
seq = read_int32(raw, offset=8, endian="big")
channel = read_int16(raw, offset=12, endian="big")
price = read_int64(raw, offset=40, endian="big") / 10000.0
qty = read_int64(raw, offset=48, endian="big")
else: # 深交所文本
f = raw.split("|")
seq = int(f[2])
channel = f[3]
price = Decimal(f[6])
qty = int(f[7])
return {"key": (channel, seq), "price": price, "qty": qty}
这段示意代码的重点不在具体偏移量,而在于展示映射层的职责:把两种形态的原始数据,归一成统一的内部结构,并保留“频道号+序号”作为主键。实际偏移和分隔符位置必须以对应版本的接口文档为准。