2. 价格档位的数据表示
在订单簿系统中,价格档位(Price Level)是最基本的聚合单元。它把同一价格上的所有订单归并为一个节点,对外只暴露“价格 + 总量 + 订单数”三个核心字段。理解价格档位如何被表示、如何被聚合与拆分、以及在内存中如何排布,是构建高性能撮合与行情系统的前提。本节围绕存储结构、价格精度与刻度、聚合与拆分、内存布局四个层面展开,并给出可直接参考的实现示例。
一、档位价格与数量的存储结构
一个价格档位至少需要保存:价格(price)、该价位剩余总量(quantity)、该价位的订单数量(order count),以及一个指向该价位订单链表的头指针(用于撮合时按时间优先取单)。在 C++ 中可表示为:
struct PriceLevel {
int64_t price; // 以最小刻度为单位的整数价格
uint64_t quantity; // 该价位剩余总量
uint32_t order_count;// 该价位挂单笔数
Order* head; // 时间优先链表头
Order* tail; // 链表尾,便于 O(1) 追加
};
关键设计点是:价格用整数存储,不用浮点数。浮点数在累加、比较时会产生舍入误差,导致“同一价格”被判定为不同档位,或撮合时价格判断出错。因此价格在内部统一转换为“最小刻度整数”,例如以 0.01 元为刻度时,12.34 元存为 1234。数量同样使用整数(按最小交易单位,如股或张),避免小数累计误差。
二、价格精度与刻度
价格精度由“刻度(tick size)”决定。刻度是最小价格变动单位,不同市场差异很大:A 股主板通常为 0.01 元,部分品种为 0.001 元;期货、外汇、加密货币的刻度可能小至 0.00001 甚至更细。系统内部应维护一个全局刻度参数 tick_size,并约定所有价格都以“刻度整数”参与运算。
价格与刻度整数的换算关系为:price_int = round(price_real / tick_size),反向为 price_real = price_int * tick_size。例如 tick_size = 0.01,则 12.34 元对应 1234;若 tick_size = 0.001,则 12.34 元对应 12340。刻度一旦确定,必须在撮合、行情、风控各模块保持一致,否则会出现“同一价格被拆成两个档位”的严重问题。工程上通常把刻度作为配置项在启动时加载,并在所有价格入口处做一次归一化校验。
三、档位聚合与拆分
聚合指新订单进入时,若其价格已存在对应档位,则只更新该档位的 quantity 与 order_count,并把订单追加到链表尾部,不新建档位。这样同一价位的多笔订单共享一个档位节点,查询和行情推送都以档位为单位,效率高。
拆分发生在订单被撤销或成交后:当某档位的 order_count 降为 0 时,该档位应从订单簿中移除;若只是部分成交,则只减少 quantity 与对应订单,档位保留。需要注意“档位删除”与“档位保留但数量为 0”的区别——前者释放内存并更新索引,后者会造成行情中出现空档,通常应避免。
下面用一个示例说明聚合过程(示例参数,非实测):假设 tick_size = 0.01,当前卖一档 12.34 元已有 2 笔订单共 500 股。此时新来一笔 12.34 元、300 股的卖单,聚合后该档位变为 quantity = 800、order_count = 3,链表追加新订单;若随后其中一笔 200 股被撤销,则 quantity 变为 600、order_count 变为 2,档位仍保留。
四、内存布局图解
价格档位在内存中的组织方式直接决定撮合与行情查询的性能。常见做法是“价格索引 + 档位数组/哈希表 + 订单链表”三层结构:用有序结构(如红黑树或跳表)按价格排序保存档位指针,用哈希表做价格到档位的 O(1) 查找,档位内部用双向链表维护时间优先顺序。下图展示了一个卖盘订单簿的档位内存布局与聚合关系。
从图中可以看出三层结构的分工:左侧有序索引负责“按价格排序、快速找到最优档位”,中间档位节点负责“聚合数量与笔数”,右侧订单链表负责“时间优先的撮合顺序”。这种布局让“取最优价”与“同价取最早单”两个高频操作都能以较低代价完成。
五、实现要点与常见陷阱
实际落地时有几个容易出错的点值得强调。第一,价格归一化必须前置:所有外部输入(行情、下单、风控)在进入订单簿前统一转换为刻度整数,避免浮点价格混入。第二,档位删除要同步更新索引:当 order_count 归零时,必须同时从有序索引和哈希表中移除,否则会出现“幽灵档位”。第三,数量与笔数要原子更新:聚合与拆分涉及 quantity、order_count、链表三个字段,应保证在同一临界区内完成,避免并发下出现数量与链表不一致。第四,刻度变更需全链路生效:若系统支持多品种不同刻度,应按品种隔离刻度参数,不能全局共用。
综上,价格档位的数据表示核心在于“整数价格 + 刻度归一 + 聚合节点 + 时间优先链表 + 有序索引”这一组合。它既保证了价格比较的精确性,又通过聚合降低了行情与撮合的数据量,是订单簿工程实现中必须打牢的基础结构。