4. 上交所逐笔委托关键字段剖析
逐笔委托数据是Level-2行情的核心组成,它把每一笔新进入撮合队列的委托单独记录下来,而不是像快照那样只给出盘口聚合结果。要正确使用这份数据,第一步不是写代码,而是把字段含义吃透。上交所逐笔委托中,委托编号(Order No)、买卖方向与订单类型、价格与数量精度、时间戳粒度这四组字段,决定了后续能否把委托与成交正确关联、能否还原订单簿。本节围绕这四组字段逐一拆解。
一、委托编号:不是流水号,而是订单的“身份证”
上交所逐笔委托中的委托编号是一个由交易所撮合系统分配的整数标识,用于唯一标识一笔委托在其生命周期内的身份。它的编码规则有几个关键特征需要牢记:
- 当日唯一、跨日重置:委托编号在同一个交易日内单调递增分配,但不同交易日之间会重新从低位开始。因此“编号 10086”在周一和周二可能对应完全不同的订单,任何跨日缓存都必须以“交易日期 + 委托编号”作为联合主键,绝不能只用编号做全局键。
- 按通道/席位分配区间:上交所撮合系统按参与人(交易单元)分配编号段,同一交易单元当日提交的委托编号通常落在连续或近似连续的区间内。这带来一个实用推论:编号的跳跃往往意味着中间有撤单或其他参与人的委托插入,而不是数据丢失。
- 与成交回报中的编号对应:逐笔成交记录中会携带买方和卖方的委托编号,这正是把“委托流”和“成交流”缝合起来的唯一可靠纽带。委托编号是关联键,不是排序键——排序应使用时间戳加序号。
二、买卖方向与订单类型:一字之差,撮合逻辑完全不同
买卖方向字段取值简单(买/卖),但订单类型字段才是容易出错的地方。上交所逐笔委托中常见的订单类型标识包括:
- 限价订单(A):指定价格和数量,进入订单簿排队,是最常见的类型。
- 市价订单(B):不指定价格或指定保护价,立即与对手方最优价撮合,剩余部分按规则处理。市价单在逐笔委托中出现时,其价格字段可能为 0 或保护价,解析时不能直接当作有效报价使用。
- 本方最优订单(U):以本方最优价挂单,价格字段同样可能不携带真实价格。
- 撤单记录:撤单在逐笔委托流中通常以独立记录出现,订单类型标识为撤单(如 D),数量字段表示撤单量,价格字段可能无意义。把撤单误当成新委托,会直接导致订单簿数量虚增。
因此,构建订单簿时必须先按订单类型分流:新委托入簿、撤单出簿、成交扣减。方向字段则决定入买方簿还是卖方簿。二者组合起来,才构成一条记录的处理语义。
三、价格与数量精度:整数存储,单位换算
上交所逐笔委托的价格和数量字段均以整数形式传输,需要按约定单位换算:
- 价格:以“元”为单位的定点数,通常保留到 0.01 元(即分)。例如字段值 1234 表示 12.34 元。部分品种(如债券、基金)价格精度可能不同,需按品种规则处理。
- 数量:以“股”为单位的整数。A 股委托数量通常为 100 股的整数倍(科创板等另有规则),但字段本身不做校验,解析时不应假设整除。
精度处理的核心原则是:全程用整数运算,只在展示层除以 100。用浮点数累加价格和数量,在百万级逐笔数据上会产生可见的舍入误差,导致订单簿对账不平。若需要计算成交金额,用“整数价格 × 整数数量”后再统一换算,避免中间步骤引入小数。
四、时间戳:粒度决定你能还原到什么程度
上交所逐笔委托的时间戳通常精确到毫秒(部分通道或历史版本可能为秒级),表示该笔委托被撮合系统接收并处理的时刻。理解时间戳要注意三点:
- 它是交易所处理时间,不是报单时间:从券商报单到交易所接收存在网络与柜台延迟,逐笔时间戳反映的是撮合系统侧的时刻,不能用来衡量投资者下单速度。
- 同一毫秒内可能有多笔记录:毫秒粒度下,同一时间戳对应多条委托是常态。因此排序必须使用“时间戳 + 委托编号”或数据流中的序号字段,单靠时间戳无法确定先后。
- 与成交时间戳对齐:逐笔成交也带毫秒时间戳,关联委托与成交时,应以委托编号为主键,时间戳仅用于校验先后顺序是否合理(成交时间不应早于委托时间)。
五、把字段落到解析代码里
下面是一段示意性的解析片段,展示如何把上述规则固化到代码中(参数为教学示例,非实测数据):
# 假设一条逐笔委托记录已解析为字典 rec
order_no = int(rec["order_no"]) # 64位整型,勿用float
side = rec["side"] # 'B' 买 / 'S' 卖
otype = rec["order_type"] # 'A'限价 'B'市价 'U'本方最优 'D'撤单
price = int(rec["price"]) # 单位:分
qty = int(rec["qty"]) # 单位:股
ts_ms = int(rec["timestamp"]) # 毫秒
key = (trade_date, order_no) # 跨日唯一主键
if otype == 'D':
book.remove(key, qty) # 撤单出簿
elif otype in ('A', 'U'):
book.insert(side, price, qty, key) # 入簿
elif otype == 'B':
book.match_market(side, qty, key) # 市价撮合,价格字段不可信
这段代码体现的正是前面四条规则:整型存储、类型分流、整数价格、联合主键。实际工程中还需处理乱序到达(按时间戳+序号重排)、重复推送(按委托编号去重)以及撤单量小于原委托量的部分撤单情形。
六、常见误区速查
| 误区 | 后果 | 正确做法 |
|---|---|---|
| 只用委托编号做全局键 | 跨日数据串号,关联到错误订单 | 交易日期 + 委托编号 |
| 把撤单当新委托入簿 | 订单簿数量虚增,盘口失真 | 先按订单类型分流 |
| 用浮点存价格并累加 | 舍入误差累积,对账不平 | 整数分存储,展示层换算 |
| 仅按时间戳排序 | 同毫秒记录顺序错乱 | 时间戳 + 序号/委托编号 |
| 市价单价格字段当报价用 | 计算出不存在的价格档位 | 市价单价格字段忽略或按保护价处理 |
把这四组字段的语义、精度和关联规则固定下来,后续无论是做委托成交关联、订单簿重建还是微观结构分析,都有了可靠的地基。字段理解上的一个小偏差,往往会在百万级数据上放大成系统性错误,因此值得在动手写关联逻辑之前反复核对。