技术博客

集合竞价 vs 连续竞价:两种定价机制对撮合系统的不同要求

第 7 / 141 篇 · 2026-02-06 · secfin · 集合竞价撮合定价机制

A 股每个交易日有两个"性质完全不同的市场":9:15~9:25 的开盘集合竞价(以及 14:57~15:00 的收盘集合竞价),和 9:30~14:57 的连续竞价。同样一堆买卖委托,前者攒起来一次性定价,后者来一笔撮合一笔。对撮合系统来说,这是批处理和流处理两种范式在同一个进程里的切换。

连续竞价:流处理,来一笔配一笔

连续竞价的规则就一句话:价格优先、时间优先,新来的委托和订单簿里已排队的最优对手方立即撮合。买入价 ≥ 卖一价就成交,成交价取先到一方的价格;吃不掉全部剩余就挂进订单簿排队。

撮合引擎的核心数据结构是订单簿:按价格分档,每档内部按时间排 FIFO 队列。来一笔市价或限价买单,从卖一档开始往深里吃,直到委托量耗尽或价格触及限价。这是纯流处理:每来一条消息做一次决策,延迟敏感(极速柜台整个环路要压到微秒级),单笔决策的计算量很小。订单簿结构和撮合循环的完整实现放到"订单簿数据结构"和"撮合算法"两篇,这里只定性。

集合竞价:批处理,攒起来算一个价

集合竞价期间,所有委托只进订单簿不成交,到 9:25 定时点做一次集中撮合,产出唯一一个开盘价。定价目标是最大成交量原则:选一个价格,使这个价位上能够成交的总量最大。具体判定依次是:

  1. 能实现最大成交量的价格;
  2. 高于该价的买入申报和低于该价的卖出申报全部成交;
  3. 与该价相同的买方或卖方至少一方全部成交;
  4. 满足以上条件的价格有多个时,取使未成交量最小的价位;仍多个,上交所取中间价、深交所取距昨收最近价(两市细则略异)。

形式化一点。设候选价格集合为所有申报价出现过的价位 $\{p_1 < p_2 < \cdots < p_n\}$。对每个候选价 $p$,累计买单量 $B(p) = \sum_{p_i \ge p} b_i$(所有愿意以不低于 $p$ 买的量),累计卖单量 $S(p) = \sum_{p_i \le p} s_j$(所有愿意以不高于 $p$ 卖的量),则可成交量为

$$ V(p) = \min\big(B(p),\, S(p)\big), \qquad p^* = \arg\max_p V(p) $$

平局时按上面第 3、4 条破例。所有成交都按 $p^*$ 一个价格执行——集合竞价里没有"你的买价和对手卖价谁先到"的问题,这是它和连续竞价最本质的区别:前者是"选一个清算价",后者是"两笔委托相遇的价格"。

最大成交量定价:累计买卖曲线候选价格(升序)→量B(p):≥p 的累计买量(递减)S(p):≤p 的累计卖量(递增)交点:max min(B,S)开盘价 = 此处价格

图上两条曲线一个是单调减的累计买量、一个是单调增的累计卖量,可成交量 $V(p)$ 是两条线的下包络,峰值就在交点附近。算法实现很朴素:把所有申报价排序,两个方向各做一次前缀和,扫一遍取 argmax,$O(n \log n)$ 主要来自排序。真正的工程复杂度不在算法,在下面的流程细节。

9:15~9:25 的十分钟里系统在干什么

集合竞价的十分钟不是静态的"攒单",有几个特殊时段规则直接影响柜台行为:

  • 9:15~9:20:可申报可撤单。这一段的订单簿允许"演戏"——挂大单再撤,制造虚假供需诱导跟风。所以这段时间的虚拟开盘价参考价值低。
  • 9:20~9:25:只许申报不许撤单。订单簿开始沉淀真实意愿,虚拟开盘价逐渐收敛。
  • 9:25~9:30:交易所不接受申报也不撮合(券商收单暂存,9:30 统一报送)。9:25 撮出的开盘价和首笔成交量一次性广播。

期间交易所会周期性发布虚拟开盘参考价——用当前订单簿"假装撮一次"算出的参考价、匹配量、未匹配量。注意这三分钟热度信息对券商系统是实打实的流量:虚拟价刷新会进行情流推给所有客户端。所谓"开盘前模拟撮合",就是定价算法在快照上的只读执行,与正式撮合共用同一份定价代码,只是结果不落账——这也是为什么定价函数必须是纯函数(输入订单簿快照,输出价格和成交分配),有副作用的实现没法被复用。

两种机制对系统的不同要求

维度 连续竞价 集合竞价
范式 流处理:事件驱动,逐笔决策 批处理:定时触发,全局求解
延迟目标 微秒级,单笔撮合越快越好 秒级,10 分钟窗口里算一次
状态变化 每笔都改账(成交、排队) 期间只排队,一次性批量成交
关键风险 热点订单簿的并发与顺序性 9:25 单点的吞吐峰值与正确性
定价权 委托相遇自然产生 算法显式计算

对券商柜台侧,差异体现在两个地方。回报处理:9:25 那一瞬间会涌来全天最密集的一批成交回报(集合竞价成交全部集中在同一时点下发),柜台回报通道的峰值容量按这个时刻设计,不是按连续竞价的均值。账务批量性:集合竞价的成交回报是成批到达的同一价格成交,清算侧可以按价格分组压缩处理。

对交易所撮合侧,差异是两套代码路径一个引擎:连续竞价循环和集合竞价定价共享订单簿数据结构,但驱动方式一个是事件一个是定时器。9:30 整点的切换——集合竞价攒下的未成交委托(价格优于开盘价的残余量)直接转入连续竞价订单簿继续排队——是状态连续性最容易出 bug 的地方:转簿时要保持原始时间优先顺序,不能因为重新入簿而丢时间戳。

为什么要有集合竞价

连续竞价在流动性充分时是好机制,但开盘时刻市场经历了隔夜信息积累,供需严重失衡,如果直接连续竞价,第一笔成交价会由最早的两笔随机委托决定,波动巨大。集合竞价用十分钟时间换信息聚合:让所有意愿同时表达,用一个全局最优价格出清,开盘价的代表性远好于"第一笔碰巧的成交"。收盘集合竞价(2018 年起深交所先行,后全市场推广)同理:收盘前操纵股价的"尾市拉抬"在连续竞价下成本很低,改成集合竞价后,操纵者要和整个三分钟的订单簿博弈。

所以两种机制不是新旧替代,而是各管一段:连续竞价负责"平时的高频相遇",集合竞价负责"关键时刻的共识定价"。撮合系统要同时驾驭流处理和批处理两种范式,根因就在业务上这两个时刻的诉求根本不同。