CHAPTER 02

市场如何撮合

拆开交易所这台撮合引擎:订单簿、竞价规则、买卖五档,这是全书程序员最有快感的一章。

股价不是谁定的,是撮合出来的。交易所本质上是一个确定性的匹配服务:接收全市场的委托请求,按两条固定规则排序,能配对的当场成交,配不上的排队等着。整套逻辑简单到可以在一页纸上写完,规则全部公开,行为完全可预测。

理解这台引擎有两个直接好处。第一,你会知道按下「买入」之后到底发生了什么,不再把成交价的波动理解成「有人在操纵」。第二,散户交易成本里被白白浪费的那部分,大多发生在这一层:单子怎么下、什么时候下、下多大。

2.1 订单簿:两个有序队列

交易所为每一只股票维护一个订单簿(Order Book)。它就是两个按价格排序的队列:

A 股的最小价格变动单位是 0.01 元,所以价格轴是离散的整数格子(以分为单位)。每个价格档位下面挂着若干笔委托,按进入交易所主机的先后顺序排成一条 FIFO 队列。委托的最小数量单位是「手」,买入 1 手 = 100 股。

买一价永远低于卖一价,两者之差叫价差(spread)。这个缺口是订单簿的空档:没人愿意跨过去,就一笔都不会成交。一旦有人跨过去——出一个不低于卖一的买价,或不高于买一的卖价——撮合立即发生。所谓「股价涨了」,物理含义就是买盘不断跨过价差、把卖盘一档一档吃光。

程序员视角 订单簿就是一个 max-heap(买盘)加一个 min-heap(卖盘)。撮合引擎只做一件事:反复检查两个堆的堆顶能不能配对,能配就弹出成交,不能配就把新单 push 进去排队。真实交易所为了性能一般不用堆,而是用「价格数组 + 每档双向链表」,因为价格档位有限且连续,数组下标寻址是 O(1)。但心智模型是一样的。
# 订单簿 = 两个按价格排序的队列,每档之内先到先得
bids = MaxHeap()   # 买盘:出价越高越靠前
asks = MinHeap()   # 卖盘:要价越低越靠前

def on_order(o):
    book = asks if o.side == BUY else bids
    while o.qty > 0 and book and crosses(o, book.top()):
        best = book.top()                  # 对手方最优价
        n = min(o.qty, best.qty)
        trade(price=best.price, qty=n)     # 成交价取「先挂单」一方的价格
        o.qty -= n; best.qty -= n
        if best.qty == 0: book.pop()
    if o.qty > 0 and o.type == LIMIT:
        push(o)                            # 没吃完的部分挂上去排队

注意 trade(price=best.price) 这一行。A 股的成交价取先挂单一方的价格:卖一挂在 10.24 元,你出价 10.30 元买,成交价是 10.24 元而不是 10.30 元,多出来的 6 分钱不会被吃掉。这是很多新手的第一个惊喜——挂高价买入并不会让你买贵,只会让你排到队伍最前面、优先成交。

2.2 撮合规则只有两条

整台引擎的排序规则只有两条,没有第三条:

第一个结论:机构没有插队特权。基金公司的一手和你的一手在同一档位上排同一条队,谁先到谁先成交。所谓公平,是这条规则给的。

第二个结论:想优先成交,合法手段只有出价更有诚意(价格优先)或更早挂单(时间优先)。涨停板上排队买入常常一整天买不到,就是因为前面已经有几百万手在同一价格上排着,时间优先把你钉在了队尾。

避坑 「时间」指的是委托到达交易所主机的时间,不是你点下按钮的时间。中间还隔着券商柜台的风控校验和一段网络。这就是为什么涨停板集合竞价抢筹几乎不可能靠手速赢——你和专业席位之间差的是链路,不是手指。别为这件事花钱升级设备。

2.3 限价单与市价单

你能提交的委托只有两大类,区别就是有没有 price 这个参数。

限价单带价格:「以不高于 10.24 元买入 10 手」。能成交就成交,不能就挂上去排队。保证是「价格绝不劣于我说的数」,代价是可能一直不成交。

市价单不带价格:「立刻按对手方现在的价格买 10 手」。保证是「大概率立刻成交」,代价是你不知道最终成交价。A 股的市价单细分成几种,名字吓人,含义都很直白:

委托类型行为适用
最优五档即时成交剩余撤销只吃对手方前五档,剩余部分立刻撤销沪、深
最优五档即时成交剩余转限价只吃对手方前五档,剩余部分转成限价单挂上去沪、深
对手方最优价格按对手方第一档价格成交(买入按卖一价)
本方最优价格按本方第一档价格挂单(买入挂在买一价)
即时成交剩余撤销(FAK)/全额成交或撤销(FOK)成交多少算多少剩余撤销;或者要么全成交要么全撤

「最优五档」是交易所替你做的兜底:即使交一张不设上限的市价买单,它最多也只吃到卖五,不会一路穿到涨停板。此外,连续竞价阶段还有有效竞价范围(俗称价格笼子):科创板、创业板要求买入申报价不高于基准价的 102%、卖出不低于 98%,超出范围直接拒单;主板机制类似,并额外允许「基准价上下 10 个最小变动单位」作为孰高/孰低的兜底。具体数值以交易所现行业务规则为准,设计意图是一致的——防止离谱报价把价格瞬间打飞。

程序员视角 市价单 = 一次没设 timeout、没设重试上限、也没做参数校验的下游调用。平时下游健康(盘口厚),它跑得又快又好;一旦下游抖动(盘口稀薄),它会把你所有的预算一次性烧光。限价单则是带了参数校验和熔断阈值的调用:宁可失败,也不接受一个离谱的结果。默认用限价单,是给自己加的一层防御性编程。

2.4 集合竞价:一次批处理

开盘前的 9:15 到 9:25,交易所不撮合。它只做一件事:把所有委托攒起来。到 9:25 那一刻,用一次全局计算,求出一个使成交量最大的价格,然后把这个价格附近所有能成交的单子,统统按这一个价格成交掉。这个价格就是开盘价。

为什么这样设计?隔夜积压了大量信息(财报、政策、外盘),一开门就逐笔撮合的话,第一笔单会以一个近乎随机的价格成交,随后价格剧烈跳动。批处理把这段时间的所有信息一次性折叠成同一个价格,公平得多。

这个阶段还有一条关键的分段规则:

避坑 9:15–9:20 显示的「虚拟开盘价」和巨额挂单,随时可以撤掉,所以经常是假的:挂一笔天量买单把虚拟开盘价顶到涨停,9:19:59 撤掉,成本为零。真正有约束力的只有 9:20 之后的委托。别拿前五分钟的盘口做任何判断,那是一块可以随意写、不会落盘的缓存。

收盘时也有一次同样机制的集合竞价:14:57–15:00,全程不可撤单,15:00 一次性撮合产生收盘价,申报价格被限制在基准价上下 2% 以内。这条规则让收盘价难以被尾盘一两笔大单随意拉动,因此以收盘价为基准的指数、基金净值都更可信。

程序员视角 集合竞价是批处理 job:攒够一批请求,跑一次全局最优化(求使成交量最大的那个价格),一次性输出结果。连续竞价是流式处理:来一条处理一条,状态实时更新。同一个业务,两种执行模型——批处理牺牲延迟换全局最优和抗扰动,流式牺牲全局最优换实时性。交易所在开盘、收盘这两个信息最密集的时刻用批处理,中间用流式,是一个非常干净的架构选择。

图 2-1 · 集合竞价怎么算出开盘价

0 500 1000 1500 累计委托量(手) 9.97 9.98 9.99 10.00 10.01 10.02 10.03 两线交点在 10.00 与 10.01 之间 不在 1 分的价格档上,不能直接用 卖盘 900 手 买盘 700 手(短边) 在相邻档里比 min(买, 卖): 10.00 档 min(950, 600) = 600 手 10.01 档 min(700, 900) = 700 手 → 开盘价 累计买盘(愿以该价或更高买入) 累计卖盘(愿以该价或更低卖出)
价格越高,愿意买的人越少、愿意卖的人越多,两条累计曲线必然相交。A 股股票的申报价格最小变动是 0.01 元,横轴一格就是一分钱。两线交点通常不落在整分的档位上:交易所在离散档位里挑让 min(买量, 卖量) 最大的那一档——10.01 档能成交 700 手,多于 10.00 档的 600 手,所以开盘价是 10.01,成交量取短边 700 手,所有落在成交区间内的委托都按这一个价格成交。

2.5 连续竞价:来一条处理一条

9:30 开始,引擎切换到流式模式。交易时段是 9:30–11:30 和 13:00–15:00。每收到一笔新委托,就立刻和订单簿另一侧比对:买入价 ≥ 卖一价(或卖出价 ≤ 买一价)就成交,成交完还有剩余就挂上去排队。撮合本身是微秒级的,没有「每秒撮合一次」这种批次。

所以「最新价」这个数字,含义非常具体:它是最近一笔成交的价格,仅此而已。它不代表公司值多少钱,也不代表你现在一定能按这个价买到——它只是历史上某一微秒发生过的一次配对。

另外,15:05–15:30 还有盘后固定价格交易:所有成交统一按当日收盘价撮合,只排时间优先。2026 年 7 月的交易新规把它从科创板、创业板扩容到了沪深主板股票和 ETF,适用范围以交易所最新公告为准。

2.6 买卖五档:盘口怎么读

行情软件上那个「卖五到卖一、买一到买五」的小表格,就是订单簿最靠近价差的十个价格档位的切片。每一档两个数:价格,以及这一档上所有委托的总量。

读盘口只需要问两个问题:每档有多厚?档与档之间隔多远?厚且密,说明流动性好,你的单子进出不会撼动价格;薄且稀,说明一笔中等大小的单子就能把价格推走几个百分点。

图 2-2 · 一笔市价买单如何逐档吃掉卖盘

盘口:每档 = 价格 + 挂单量 卖盘在上(要价从低到高),买盘在下(出价从高到低) 卖五 10.28 12 手 卖四 10.27 9 手 卖三 10.26 6 手 卖二 10.25 4 手 卖一 10.24 3 手 最新成交价 10.23 价差 0.01 元 买一 10.23 5 手 买二 10.22 8 手 买三 10.21 15 手 买四 10.20 26 手 买五 10.19 9 手 市价买入 10 手,逐档吃掉: ① 卖一 3 手 × 10.24 元 = 3 072 元 ② 卖二 4 手 × 10.25 元 = 4 100 元 ③ 卖三 3 手 × 10.26 元 = 3 078 元 合计成交 10 手,付出 10 250 元 成交均价 10.25 元 / 股 比卖一价 10.24 元多付 0.10% ——这 0.10% 就是滑点 撮合后:卖一变成 10.26 元 × 3 手, 价格被这一笔单子推高了 3 分钱。
市价单从对手方最优价开始,一档一档往上吃,直到数量填满。吃掉的档位越多,成交均价偏离首档价格越远。这张盘口的卖一到卖三总共只有 13 手,所以一笔 10 手的单子就已经能推动价格。
避坑 普通行情(Level-1)里的五档盘口是每 3 秒一张快照,不是实时流。两张快照之间发生的挂单、撤单、成交,你一概看不到。这意味着:一,你看到的「巨量买单」可能在你下单前的 2.9 秒里已经撤了;二,任何基于盘口逐笔变化的「主力意图分析」,在采样精度上就不成立。Level-2 行情提供十档和逐笔委托,但那是解决数据精度问题,不是解决预测问题。

2.7 流动性与滑点:你的单子会不会撼动价格

流动性的工程定义很简单:把一定数量的股票立刻变成现金,需要付出多大的价格代价。代价越小,流动性越好。

代价有两个来源。一是价差:大盘蓝筹买一卖一常年只差一两分,可以忽略;冷门小盘股能差到几分甚至更多。二是冲击成本,也就是图 2-2 那样的逐档吃单——单子越大、盘口越薄,吃穿的档位越多,成交均价越差。

散户的单子通常小到吃不穿一档,日常感受不到。但这几种情况会让滑点突然变贵:

于是有一条几乎零成本的纪律:默认永远用限价单。多花两秒填个价格,就把「成交价不确定」这类风险整个关掉。想成交快,就把买入限价定得比卖一价高一两分,照样立刻成交,同时给自己留了上限。

避坑 别把「成交量大」当成买入理由,但一定要把「成交量小」当成回避理由。一只日均成交额只有几千万的股票,无论故事讲得多好,你都可能在需要离场的那天发现自己出不来。流动性是仓位的容量上限,这是一个硬约束,和你的判断对不对无关。

2.8 A 股竞价制 vs 美股做市商制

上面讲的整套机制叫订单驱动(order-driven):所有人的委托进同一个订单簿,互相直接配对,交易所只做撮合,自己不参与买卖。A 股的主体就是这套集中竞价制度。

美股主流是报价驱动(quote-driven):做市商同时挂出买价和卖价,随时用自己的账户接下你的单子,赚价差作为提供流动性的报酬。而且美股不是一个市场,是几十个交易场所(多家交易所加暗池),监管要求订单以全市场最优报价 NBBO 成交,券商会把单子路由到价格最好的地方——这是美股常有「成交价比我挂的还好」的原因。

两种制度各有代价。竞价制透明、规则简单、一视同仁,但冷门股票没人负责提供流动性,盘口可能极薄。做市商制保证随时有对手方,代价是你付了价差,而且路由链条复杂(比如订单流付费 PFOF),透明度不如前者。

A 股也在做混合尝试:科创板自 2022 年 10 月 31 日起在竞价基础上引入做市商,由有资格的券商双边报价改善流动性。但对个人投资者,心智模型依然是订单簿加两条优先规则,做市商只是簿里一个报价特别勤快的参与者。

A 股(竞价制为主)美股(做市商制为主)
价格形成全部委托进同一订单簿互相配对做市商双边报价,多场所竞价
对手方另一个投资者常常是做市商的自营账户
市场结构沪、深、北三家交易所,各股票单一场所数十个交易场所 + 暗池,NBBO 最优价保护
流动性保障无人负责,冷门股盘口可能极薄做市商有义务持续报价
你付出的隐性成本价差 + 冲击成本价差(做市商的利润)+ 路由差异

2.9 一笔订单的一生

最后把链路串起来。你在手机上点「买入」之后,这笔委托要穿过四个系统。

图 2-3 · 从点击「买入」到真正过户

你的 App 券商柜台 交易所撮合引擎 中国结算 限价委托:买入 10 手 @ 10.24 元 校验资金、持仓、权限后报盘 进入订单簿排队 价格优先 → 时间优先撮合 成交回报 App 显示「已成交」,持仓 +10 手 当日成交数据送清算 T+1 完成股份与资金交收 上半程通常在 1 秒内跑完;真正的所有权变更发生在次日的清算交收环节
撮合和交收是两件事。撮合确定了「谁和谁按什么价成交」,交收才真正把股份和资金在账户之间划转。A 股股份 T+1 交收,这正是下一章要讲的 T+1 制度的底层原因。

四个环节各司其职:App 只是输入界面;券商柜台做资金和权限校验,是链路上唯一会因为你自己的问题(余额不足、无权限)打回委托的地方;交易所只负责撮合,不碰钱也不碰股份;中国结算做清算交收,持股最终登记在它的账本上。

成交回报到你的手机通常在一秒之内,但所有权变更要到 T+1 才完成。理解了这一点,「今天买明天才能卖」就不是一条奇怪的限制,而是交收周期在交易层的直接映射。下一章会把它和涨跌停、税费一起,当成这套协议的规范文档来读。

2.10 这一章的可操作结论

动手玩 这一章讲的撮合引擎有一个可以玩的版本:模拟撮合市场——和 5 个 NPC 同场交易,亲手挂单、撤单、被大户打穿盘口,把本章 13 个概念一个个解锁。强烈建议现在就去打一局再读第 3 章。