第 06 章 指令驱动市场与撮合规则
本章对应 Harris《Trading and Exchanges》第 6 章 Order-Driven Markets。世界上几乎所有重要交易所都是指令驱动市场,新建的电子交易系统也大多采用这种结构。它们外表千差万别,内核却只有两样东西:订单优先规则决定谁先成交,成交定价规则决定以什么价格成交。量化交易者每天写的回测撮合、挂单排队模型、开收盘竞价策略、暗池路由,都建立在这两套规则之上。本章最后给出一个小型撮合引擎,能逐笔复现原书的全部例题。
学习目标
- 说清指令驱动市场的共同骨架:订单优先规则(价格优先为首,时间、显示、规模、公众订单等为次级规则)与三种成交定价规则(统一、歧视、衍生)。
- 熟练执行“排序—匹配—定价”三步撮合流程,能手算集合竞价的出清价和连续竞价的逐笔成交。
- 会构造供需表 \(S(p)\)、\(D(p)\),理解出清价为什么同时使成交量 \(\min\{S,D\}\) 和总交易者剩余最大。
- 理解最小变动价位(tick)如何决定时间优先的价值,以及它对挂单规模和价格竞争的影响。
- 比较连续竞价与集合竞价:谁偏好哪种定价规则,为什么连续市场成交量更大而总剩余更小,即时性的价值体现在哪里。
- 认识交叉网络(暗池的前身)的运作方式和三个固有问题:价格所有权、陈旧价格下的逆向选择、价格操纵。
读前导读
这一章在解决什么问题。 第 05 章说 A 股、大多数期货市场都是“指令驱动市场”,这一章打开这台机器看里面的齿轮。所有指令驱动市场都只靠两套规则运转:谁先成交(优先规则)和按什么价成交(定价规则)。定价规则有三种:集合竞价的统一定价(所有人一个价)、连续竞价的歧视性定价(每笔按挂单价)、交叉网络的衍生定价(借用别处的价格)。不同规则对不同人有利:大额急单喜欢歧视性定价,挂单者喜欢统一定价,消息灵通者和操纵者喜欢衍生定价。
这一章也是本册第一次出现“可以证明的结论”:在估值等于限价的假设下,集合竞价的总交易者剩余最大;同一组订单,连续竞价的成交量不小于集合竞价。你在 CFA 经济学里学过消费者剩余和生产者剩余,这里只是把它们搬到了订单簿上。对 CPA/CFA 背景的读者,这两个证明是练习“读证明”的好材料:步骤少,每一步都有清楚的经济含义。
需要先想起来的数学。
- 带条件下标的求和:\(S(p)=\sum_{\text{卖单限价}\le p}q_i\) 读作“把所有限价不超过 \(p\) 的卖单数量加起来”。下标里写的是筛选条件,不是循环变量的范围。小例子:卖单 1@19.8、6@20.0、2@20.1,则 \(S(20.0)=1+6=7\)。
- 单调阶梯函数与交点:\(S(p)\) 随 \(p\) 上升不减,\(D(p)\) 随 \(p\) 上升不增,所以 \(D-S\) 从正变负,只穿过零一次;\(\min\{S,D\}\) 在穿越点附近最大。这和经济学里画供需曲线找均衡价格完全一样,只是曲线是一级一级的台阶。函数单调性见 第 00 册第 01 章 函数极限与连续。
- 两种证明手法:一是“交换论证”,如果某个安排里存在一对可以互换得更好的交易,它就不是最优的;二是“反证法”,假设结论不成立,推出与已知事实(如“连续市场收盘时订单簿不交叉”)矛盾。读法见 第 00 册第 08 章 读懂数学证明与符号。
- 正态分布记号:随机实验中的 \(N(20,0.3^2)\) 表示均值 20、标准差 0.3 的正态分布,第二个参数写的是方差。
怎么读这一章。 6.1–6.2 读懂价格优先、时间优先和 tick 的关系(“跳背游戏”侧栏值得细读)。6.3 的表 6-1 九张订单要贯穿全章,建议拿纸笔手算一遍排序和匹配。6.4 和 6.5 是核心,供需表、交易者剩余、两种定价规则的偏好都要掌握。6.6 的两个不等式证明第一次可以只看结论,第二遍再结合讲解框走一遍。6.7 交叉网络与第 02 章 POSIT 的故事对照读。量化实战的撮合引擎是回测的基础组件,建议运行一次并核对输出与表格是否一致。
6.1 共同骨架:优先规则加定价规则
指令驱动市场(order-driven market)不靠交易商报价,而是按事先公布的交易规则把买卖双方的订单配对。Harris 把它分成四种形式:
- 口头拍卖(oral auction):交易者在大厅里面对面喊价;
- 单一价格拍卖(single price auction):先收集订单,在某一时点按同一个价格一次性撮合,即集合竞价;
- 连续电子拍卖(continuous rule-based auction):订单一到就尝试撮合,未成交部分进入限价订单簿;
- 交叉网络(crossing network):用别处决定的价格撮合,自己不发现价格。
它们的共同点是:都用订单优先规则(order precedence rules)匹配买卖方,都用成交定价规则(trade pricing rule)给成交定价。规则上的细小差别会改变最优下单策略,一个市场里最好的策略,换到规则不同的市场可能很差。所以学习任何一个新市场,第一件事是读它的撮合规则。
本章先从读者容易想象的口头拍卖入手引出各条规则,再讨论电子化的规则撮合系统。
6.2 口头拍卖:从交易大厅理解规则
公开喊价
许多期货、期权和股票交易所曾采用连续双边口头拍卖。原书写作时最大的口头拍卖市场是 CBOT 的美国长期国债期货,常有 500 名场内交易者同时在场。交易者有的喊出买价或卖价(提供流动性),有的倾听并接受别人的报价(获取流动性)。买方接受卖价时喊 “take it”,卖方接受买价时喊 “sold”。
口头拍卖的第一条规则是公开喊价规则(open-outcry rule):所有出价、要价和接受都必须公开表达。这样做有两个目的:所有人都能平等参与(多数口头拍卖里第一个喊接受的人拿到成交);所有人都知道成交情况,经纪人也就无法私下安排交易让朋友而不是客户得利。
现状补充:期货市场的公开喊价已基本被电子撮合取代,CME 在 2015 年关闭了绝大多数期货交易池。NYSE 仍保留交易大厅,但成交绝大部分由电子系统完成。口头拍卖的规则仍值得学:电子撮合系统的优先规则正是从这里继承下来的。
价格优先:自我执行的规则
口头拍卖的首要优先规则永远是价格优先(price priority):出价最高的买方和要价最低的卖方优先,买方只能接受最低要价,卖方只能接受最高出价。
价格优先是自我执行的(self-enforcing)。诚实的交易者本来就会找最好的价格,交易所不需要专门的程序来执行它;保留这条规则主要是为了在经纪人违背客户利益时可以追究。多数口头拍卖还禁止在最优买价之下出价、在最优卖价之上要价,因为只有最优报价有人关心,其余报价只会制造噪音。
时间优先与“跳背游戏”
多数口头拍卖给予第一个改善当前最优价格的人以优先权,这叫时间优先(time precedence)。在他保持报价期间,别人不能在同一价位报价;他的报价被接受或撤回后,所有人在这个价位又回到平等地位。口头报价只在片刻有效,所谓“报价只在呼吸尚温时有效”,所以拥有优先权的人要不断重复报价来维持优先。
时间优先不是自我执行的。接受报价的一方并不在乎跟谁成交,只要价格一样就行,所以拥有优先权的人必须自己捍卫,在期货交易池里喊 “That's my bid” 或 “It's my market”。
时间优先的经济作用是鼓励改善价格。想排到优先者前面,就只能把价格改善至少一个最小变动价位(tick)。Harris 用一个侧栏说明这一点:
跳背游戏(Leapfrog):浓缩橙汁期货报价 103.10 买 / 103.25 卖(美分/磅),Guy 以 103.10 出价并拥有时间优先。你想以 103.10 买,只能排在 Guy 后面;想要优先,就得出价 103.15,这时你对 Guy 有价格优先,对之后所有 103.15 的出价有时间优先。Guy 想夺回优先,只能再出 103.20。时间优先促使交易者像玩跳背游戏一样相互越过。聪明的做法是预判:如果你愿意出到 103.20,并确信你出 103.15 后 Guy 会跟到 103.20,不如直接出 103.20。此时 Guy 若仍想先成交,只能接受 103.25 的卖价,而你仍在 103.20 保有优先。当然,如果你很急,最好的策略可能是直接接受 103.25。
tick 大小决定时间优先的价值
tick 是改善价格的最小幅度,也是在没有时间优先时用价格优先“插队”需要支付的代价。由此得到一个贯穿全书的结论:
- tick 太小:插队几乎免费,时间优先失去价值,先挂单的人得不到回报,价格竞争和挂单意愿都减弱;
- tick 太大:每次改善价格都很贵,交易者不愿改善,价差被人为撑大。
金融直觉:把 tick 想成“插队费”。排在队首的挂单者享有先成交的权利,这个权利有价值,因为第一个成交的人最可能和不知情的订单成交、拿到半个价差。别人想夺走这个权利,必须多付一个 tick。tick 大时插队费高,队首位置像一张受保护的“特许经营权”,大家愿意早早排队、挂大单;tick 小时插队费几乎为零,谁先挂单都可能被别人用 1 美分抢走,挂单者就只挂小单甚至不挂。这和 CFA 里讲的“进入壁垒决定超额利润能否持续”是同一个逻辑:tick 就是做市行业的进入壁垒。
美国股市 2001 年完成小数化,最小变动价位从 1/16 美元(6.25 美分)降到 1 美分。Harris 指出,最显著的后果是时间优先的价值下降,显示的挂单规模大幅缩小,许多分析人士认为 5 美分的 tick 会好得多。
侧栏:1997 年 Common Cents 股票定价法案。众议员 Mike Oxley 等人提案要求股市以元和分而非分数报价。法案没有通过,但交易所自行转向小数,Harris 认为这很可能部分是为了阻止该法案通过。值得注意的是国会试图微观管理交易规则,而提案者恰恰是以反对政府干预闻名的保守派。
现状补充:美国 SEC 在 2016–2018 年做过“tick size 试点”,对部分小盘股把 tick 提高到 5 美分,以检验更大 tick 能否改善小盘股的流动性。A 股的最小变动价位是 0.01 元,对低价股而言相对 tick(tick 除以股价)很大,排队现象明显;高价股则相反。
公众订单优先
一些股票交易所规定,会员不得在同一价位抢在愿意成交的公众订单前面交易,这叫公众订单优先(public order precedence)。会员在场内,能比公众更早看到价格变化、更快报价,没有这条规则,会员通常能先拿到新价位的时间优先。公众订单优先让公众即使在会员拥有时间优先时也排在前面,增强了投资者对交易所的信心。
小数化同样削弱了这条规则:会员只需改善 1 美分就能合法地排到公众前面。Harris 指出,小数化之后 NYSE 会员交易商的收入大幅上升。
口头拍卖的定价:歧视性定价
口头拍卖的成交定价规则很简单:每笔交易按被接受的那个报价成交。经济学家称之为歧视性定价规则(discriminatory pricing rule)。名称来自大额交易者的一种做法:把大单拆成几块,前几块以市场上最好的价格成交,随着流动性被消耗、市场察觉到真实规模,后面几块以逐渐变差的价格成交。这等于在“最愿意交易的对手”和“只愿以较差价格交易的对手”之间实施价格歧视。
例(价格歧视):Sally 要以市价卖 100 张大豆期货,没告诉任何人订单规模。Colin 愿以最高 602½ 美分/蒲式耳买 40 张,当前出价 602;Martin 愿以最高 601½ 买 75 张,但还没报价。Sally 先接受 Colin 的出价,以 602 卖 40 张;随后 Martin 出价 601½,Sally 以 601½ 卖出剩下 60 张。平均卖价
\[\frac{40\times602+60\times601.5}{100}=601.7\ \text{美分}.\]若 Colin 事先知道 Sally 要卖 100 张,他本可等到 601½ 再买。大豆合约每张 5,000 蒲式耳,Sally 通过价格歧视节省 \((601.7-601.5)\times5{,}000\times100=100{,}000\) 美分,即 1,000 美元。
(勘误:精读笔记显示原文合约规模写作 50,000 蒲式耳、节省额写作 10,000 美元。CBOT 大豆标准合约为 5,000 蒲式耳,本书按 5,000 蒲式耳计算。)
白话解释:“价格歧视”在经济学里指对同一商品向不同买家收不同价格,比如航空公司对商务客和休闲客定不同票价。这里方向反过来:大卖家 Sally 向不同的买家(对手方)卖出不同价格,最愿意出高价的 Colin 先被满足、付 602,愿意出价低的 Martin 后被满足、付 601½。Sally 能做到这一点,靠的是不暴露总规模:Colin 不知道后面还有 60 张,所以按当时最好的出价成交了。如果 Sally 一开始就喊“卖 100 张”,所有买家都会等到 601½,她就失去了这 1,000 美元。这就是为什么大单要拆、要藏。
口头拍卖的期货在**交易池(pit)交易,股票和期权在交易柱(post)**交易。交易所要求同一品种的全部交易都在指定地点进行,便于买卖双方找到彼此,也便于执行规则。
6.3 规则撮合系统:排序、匹配、定价
多数交易所和几乎所有 ECN 用规则撮合系统安排交易,交易者之间只能通过提交和撤销订单来“谈判”。多数系统只接受限价单,接受市价单的系统把市价单视为价格无限积极的限价单。集合竞价市场先收集订单,到点后撮合一次;连续市场每到一张新订单就尝试撮合一次。
所有规则撮合系统都按同样三步工作:
- 用订单优先规则把买单、卖单分别排序;
- 依次匹配,判断哪些匹配能成交(至少一个买单的条件能被至少一个卖单接受);
- 用成交定价规则给成交定价。
订单优先规则是分层的
先按首要规则排序,首要规则下平级的订单再按次级规则排序,逐条应用直到排完。
- 首要规则一律是价格优先:最高买价和最低卖价排在各自一侧最前面;市价单永远排第一。
- 次级规则(每个系统至少一条):
- 时间优先分两种。**场内时间优先(floor time precedence)**只给某价位第一个到达的订单优先,其余订单之间“平等(at parity)”,需要再用别的规则排序;严格时间优先(strict time precedence)把同价位所有订单按到达时间排序。只用价格优先和严格时间优先的系统叫纯价格—时间优先系统(pure price-time precedence system)。
- 显示优先(display precedence):同价位上显示订单优先于隐藏订单,以鼓励交易者暴露订单。冰山单通常拆成两部分处理,显示部分享有显示优先,隐藏部分排在同价所有显示订单之后。
- 规模优先(size precedence):有的市场大单优先,有的小单优先。平等订单无法全部成交时,有的市场采用比例分配(pro rata allocation):两张平等挂单分别买 10 张和 20 张,来了 18 张卖单,按比例各成交 \(18/30\),即 6 张和 12 张。
金融直觉:时间优先和比例分配会让交易者的行为截然不同,这和 IPO 超额认购时的配售规则很像。如果按认购量比例配售,投资者会虚报认购量,想要 1 万股就报 5 万股;同样,在比例分配的期货市场(如部分短期利率期货)里,挂单者会挂出远超真实意愿的数量,以多分一点成交,结果承担了“意外成交太多”的风险。在时间优先市场里,大家则拼速度、拼排队位置。量化实战第 2 节会再强调:同一个做市策略在两种规则下的最优挂单量完全不同。
- 数量限制单(全部成交或指定最小成交量)一般排在无限制订单之后,因为它们更难成交。大交易者使用它们,是为了避免大量零碎成交带来的固定结算成本。
原书例题:表 6-1 的九张订单
下面这组订单贯穿全章,请记住它们。
| 时间 | 交易者 | 方向 | 数量 | 价格 |
|---|---|---|---|---|
| 10:01 | Bea | 买 | 3 | 20.0 |
| 10:05 | Sam | 卖 | 2 | 20.1 |
| 10:08 | Ben | 买 | 2 | 20.0 |
| 10:09 | Sol | 卖 | 1 | 19.8 |
| 10:10 | Stu | 卖 | 5 | 20.2 |
| 10:15 | Bif | 买 | 4 | 市价 |
| 10:18 | Bob | 买 | 2 | 20.1 |
| 10:20 | Sue | 卖 | 6 | 20.0 |
| 10:29 | Bud | 买 | 7 | 19.8 |
按纯价格—时间优先排序(表 6-2):
- 卖方:Sol 1@19.8 → Sue 6@20.0 → Sam 2@20.1 → Stu 5@20.2
- 买方:Bif 4@市价 → Bob 2@20.1 → Bea 3@20.0 → Ben 2@20.0 → Bud 7@19.8
Bea 与 Ben 同价,Bea 先到,所以排在前面。
匹配程序(10:30 集合竞价)
先把两边排名最高的订单配对;买价不低于卖价就能成交;数量小的一方全部成交,大的一方剩余部分与对面下一张订单配对,如此继续:
- Sol 卖 1@19.8 与 Bif 市价买 4:Sol 全部成交,Bif 剩 3。
- Bif 剩 3 与 Sue 卖 6@20.0:Bif 全部成交,Sue 剩 3。
- Sue 剩 3 与 Bob 买 2@20.1:Bob 全部成交,Sue 剩 1。
- Sue 剩 1 与 Bea 买 3@20.0:只能在 20.0 成交,Sue 全部成交,Bea 剩 2。
- Bea 剩 2@20.0 与 Sam 卖 2@20.1:买价低于卖价,停止。
共成交 7 张。撮合后买卖订单不再交叉(表 6-4):卖方剩 Sam 2@20.1、Stu 5@20.2,买方剩 Bea 2@20.0、Ben 2@20.0、Bud 7@19.8。若此后开始连续交易,市场报价为 20.0 买 4 / 20.1 卖 2。连续市场的最优买价与最优卖价之间总有价差,否则它们早就成交了。
由于按价格优先从最积极往下匹配,最后一个能成交的配对常常是买卖价格相同的两张订单,下一个配对就因买价低于卖价而不能成交。
三种定价规则分别对应三类市场:**单一价格拍卖用统一定价规则,连续双边拍卖用歧视性定价规则,交叉网络用衍生定价规则。**下面逐一讨论。
6.4 单一价格拍卖与统一定价
单一价格拍卖非常常见:多数连续股票市场和电子期货市场用它开盘,停牌后也用它恢复交易;许多国家的财政部用它发行国债。
出清价由最后一个可成交配对决定
**统一定价规则(uniform pricing rule)下,所有成交都以同一个市场出清价(market-clearing price)**成交。出清价由最后一个可成交的配对决定:
- 若这一对的买卖价格相同,该价格就是出清价:再高不满足买方,再低不满足卖方。由于按价格优先匹配,前面所有配对的买方都愿意出更高(至少相等)的价,卖方都愿意以更低的价卖,所以它们在这个价格上都能成交。
- 若这一对的买价高于卖价,两者之间任何价格都可以出清,由交易所规则决定(这种情况较少)。
在上例中,最后一个可成交配对是 Bea 与 Sue,两人都在 20.0,所以出清价为 20.0。Sol 本愿以 19.8 卖、Bob 本愿以 20.1 买,他们都对 20.0 满意;Bif 下的是市价单,可以推定他也满意,否则他应该下限价单。
供给表、需求表与成交量最大化
限价订单簿里的订单定义了两张表:
供给表(supply schedule) \(S(p)\) 向上倾斜,需求表(demand schedule) \(D(p)\) 向下倾斜(市价单计入所有价格)。市场不能强迫任何人交易,所以价格 \(p\) 上能成交的量是两者中较小的一个:
出清价以下存在超额需求,成交量由供给决定,提价能多成交;出清价以上存在超额供给,成交量由需求决定,降价能多成交。所以把价格定在供需相交处使成交量最大。
推导拆解:为什么 \(\min\{S,D\}\) 的最大值在交点附近?
- 在交点左边(价格低),\(D(p)>S(p)\),所以 \(V(p)=S(p)\)。\(S\) 随价格上升不减,于是往右移动 \(V\) 不会变小。
- 在交点右边(价格高),\(S(p)>D(p)\),所以 \(V(p)=D(p)\)。\(D\) 随价格上升不增,于是往左移动 \(V\) 不会变小。
- 左边“往右走不吃亏”,右边“往左走不吃亏”,最大值只能在两者交界处,也就是 \(D-S\) 由正变负的地方。
用表 6-5 验证:19.8 处 \(D>S\),\(V=S=1\);20.0 处仍 \(D>S\),\(V=S=7\);到 20.1 变成 \(S>D\),\(V=D=6\)。交界在 20.0 和 20.1 之间,两边比较,20.0 的 7 更大。
构造方法:先汇总每个价位的量,供给表从低价向高价累加,需求表从高价向低价累加。上例(表 6-5):
| 价格 | 该价卖量 | 供给 \(S\) | 该价买量 | 需求 \(D\) | 超额需求 \(D-S\) | 成交量 \(\min\) |
|---|---|---|---|---|---|---|
| 19.8 | 1 | 1 | 7 | 18 | 17 | 1 |
| 20.0 | 6 | 7 | 5 | 11 | 4 | 7 |
| 20.1 | 2 | 9 | 2 | 6 | −3 | 6 |
| 20.2 | 5 | 14 | — | 4 | −10 | 4 |
价格离散时供需很少恰好相等。这里最接近的是 20.0 和 20.1,20.0 能成交 7 张,20.1 只能成交 6 张,所以出清价是 20.0。出清价上若有超额需求,该价位所有卖单成交,哪些买单成交由次级规则决定;超额供给时反之。按价格优先排序保证:出清价以上的买单和出清价以下的卖单一定全部成交。
A 股对照:A 股开盘集合竞价在 9:15–9:25 进行(9:20 之后不能撤单),沪深两市收盘也采用 14:57–15:00 的集合竞价。成交价的确定原则与本节一致:使成交量最大;高于该价格的买入申报和低于该价格的卖出申报全部成交;与该价格相同的买方或卖方至少一方全部成交。
交易者剩余
单一价格拍卖还使交易者从交易中得到的总收益最大。**交易者剩余(trader surplus)**定义为
一对买卖的剩余之和与成交价无关,只取决于两人估值之差;成交价只决定剩余如何分配。拍卖要做大“蛋糕”,就要让估值最高的买方与估值最低的卖方成交。
例:糖果商愿以每磅 28 美分买两车皮精制糖(每车 112,000 磅),若能以 23 美分买到,剩余为 \((0.28-0.23)\times112{,}000\times2=11{,}200\) 美元。
估值无法直接观察,只能从订单推断:理性买方的限价不高于估值,卖方的限价不低于估值;市价买方的估值应高于出清价,市价卖方应低于出清价。
为什么单一价格拍卖使总剩余最大? 出清价是一条分界线。成交者包括所有估值高于出清价的买方和所有估值低于出清价的卖方;被排除的是估值低于出清价的买方和估值高于出清价的卖方。同一个价格同时切分了买卖两边,所以没有任何成功买方的估值低于任何成功卖方的估值。在多价格成交的市场里,可能出现某笔交易的买方估值低于另一笔交易的卖方估值,这时让那个买方以中间价把东西卖回给那个卖方,总剩余还能增加,说明原安排不是最优的。
推导拆解:用一个具体的“交换论证”把这段话走一遍。
- 总剩余 \(=\sum(\text{成交买方估值})-\sum(\text{成交卖方估值})\),每笔按数量加权。价格在买卖之间转来转去,加总时抵消,所以总剩余与成交价无关。
- 要让它最大,就要让“进场的买方估值尽量高、进场的卖方估值尽量低”,并且只要还有买方估值高于卖方估值的配对就继续成交。
- 统一价格 \(p^*\) 恰好做到这一点:估值 \(>p^*\) 的买方都进、\(<p^*\) 的卖方都进,于是任何成交买方的估值都 \(\ge p^*\ge\) 任何成交卖方的估值。
- 反过来看连续竞价的例子:Stu(估值 20.2)作为卖方成交,Bea(估值 20.0)作为买方成交。卖方估值竟高于买方估值,说明这件东西从更看重它的人手里流到了不那么看重它的人手里。若让 Stu 少卖一张、Bea 少买一张,把原本卖给 Bea 的那张(Sue 的)改卖给 Bif,Bif 照样买到 4 张,而总剩余增加 \(20.2-20.0=0.2\)(每张)。6.6 节的表 6-9 会量化这一损失。
这就是 CFA 经济学里“竞争市场均衡使总剩余最大(无谓损失为零)”的订单簿版本。
真实报价对小交易者是最优的。 若每个人都把限价设为自己的估值,拍卖结果令所有人满意:没有成交者后悔(价格不劣于估值),也没有未成交者后悔(出清价比他的估值差)。小交易者的报价几乎不影响出清价,把限价报得比估值更“狠”只会增加未成交的风险。
例(缺乏经验的投标者):John 想买 100 万美元两年期美国国债。财政部以单一价格拍卖发行 60 亿美元,投标以收益率表示(收益率越高,价格越低)。John 可以接受 5.400% 的收益率,却误以为自己的报价会影响成交价,于是投 5.500%。出清收益率为 5.495%(每 100 美元面值 99.776 美元)。John 报得太“低价”而落标,可他本来愿意接受出清价。如果他按真实估值 5.400% 投标,他会中标,并且同样拿到 5.495% 的收益率。
金融直觉:美国财政部 1998 年起对所有国债拍卖采用这种统一价格(荷兰式)拍卖,取代了此前对部分品种使用的“按各自投标价成交”的多价格拍卖。理由正是本节的结论:多价格拍卖下,投标者要猜别人怎么报,报得太激进会多付钱(赢者诅咒),于是大家都压低报价,小投标者尤其吃亏;统一价格下,小投标者按真实估值报价就是最优,不需要策略。中国财政部的国债招标也有荷兰式、美国式和混合式三种,读者可以用本节的逻辑判断哪一种更有利于小机构。顺带一提,这里收益率越高价格越低,所以“收益率报高”等于“价格报低”。
表 6-7:集合竞价中的剩余(限价单估值取限价,市价买方 Bif 的估值假定为 20.3)
| 交易者 | 订单 | 成交量 | 成交价 | 假定估值 | 剩余 |
|---|---|---|---|---|---|
| Sol | 卖 1@19.8 | 1 | 20.0 | 19.8 | 0.2 |
| Sue | 卖 6@20.0 | 6 | 20.0 | 20.0 | 0.0 |
| Bea | 买 3@20.0 | 1 | 20.0 | 20.0 | 0.0 |
| Bif | 市价买 4 | 4 | 20.0 | 20.3 | 1.2 |
| Bob | 买 2@20.1 | 2 | 20.0 | 20.1 | 0.2 |
| 合计 | 7 | 1.6 |
决定出清价的是边际交易者 Bea 和 Sue,他们的剩余为零;剩余归于“超边际”的交易者。
6.5 连续双边拍卖与歧视性定价
连续撮合系统维护一个订单簿,买卖两边各自按优先级排好。新订单到达时,系统把它与对面优先级最高的挂单比较:买单至少愿付最优卖价、卖单至多要最优买价时才能成交,这种订单称为可立即成交订单(marketable order),包括市价单和定价积极的限价单。不能成交的订单按优先级进入订单簿;不想留在簿中的订单要附 IOC 或 FOK 指令。
歧视性定价规则下,每笔成交价等于挂单(standing order)的限价。 大单吃穿多档时,每一档按各自挂单的限价成交。
逐笔演示(同一组订单,订单簿初始为空)
- 10:01 Bea 买 3@20.0:入簿。报价 20.0 买 3,无卖价。
- 10:05 Sam 卖 2@20.1:不交叉,入簿。市场 “20.0–20.1,3 × 2”。
- 10:08 Ben 买 2@20.0:与 Bea 同价,排在 Bea 后面。市场 20.0–20.1,5 × 2。
- 10:09 Sol 卖 1@19.8:可立即成交,与 Bea 成交,成交价 20.0。Sol 本愿以 19.8 卖,却卖到了 20.0。
- 10:10 Stu 卖 5@20.2:排在 Sam 后面。市场仍为 20.0–20.1,4 × 2。
- 10:15 Bif 市价买 4:先与 Sam 成交 2@20.1,再与 Stu 成交 2@20.2。Bif 均价 20.15;若按统一定价,两笔都得付 20.2。Bif 从歧视性定价中受益。
- 10:18 Bob 买 2@20.1:不成交,但改善了买价。市场 20.1–20.2,2 × 3。
- 10:20 Sue 卖 6@20.0:依次与 Bob 成交 2@20.1、与 Bea 成交 2@20.0、与 Ben 成交 2@20.0,均价 20.033,高于统一定价下的 20.0。**Sue 也受益。**买方此时被清空。
- 10:29 Bud 买 7@19.8:入簿。市场 19.8–20.2,7 × 3。
表 6-8 汇总:共 6 笔、11 张,价格在 20.0–20.2 之间波动。同一组订单,集合竞价只成交 7 张且全部在 20.0;连续竞价成交 11 张,价格路径还取决于订单到达顺序。
谁偏好哪种定价规则
给定一组挂单,大额、不耐心的交易者偏好歧视性定价:订单前面的部分能拿到更好的价格;统一定价下整单只有一个价格,而且恰好是歧视性定价下他们会拿到的最差价格。反之,挂限价单的交易者偏好统一定价:他们不希望大交易者在他们之间实施歧视。
这个结论有个前提:两种规则下交易者提交相同的订单。现实中并非如此。统一定价下限价单常以优于自身限价的价格成交(Sol 卖在 20.0 而不是 19.8),所以交易者在统一定价下会报得更积极。比较两种规则下真实提交的订单时,大交易者从价格歧视中获得的好处,以及限价单提供者受到的损害,都比上面的静态计算要小。
连续市场为何不能直接改用统一定价
既然统一定价鼓励积极报价,连续市场为什么不采用?因为它无法强制执行。想实施价格歧视的大交易者可以把大单拆成一串小单依次提交,前面的拿好价格,后面的拿差价格,最终对整单实现了歧视性定价。Harris 的概括是:歧视性定价下由市场替交易者拆单;统一定价下交易者自己在提交前拆单。
白话解释:设想连续市场强行规定“每张订单的所有部分按同一价格成交”。Bif 要买 4 张,订单簿上 20.1 有 2 张、20.2 有 2 张,统一价就是 20.2,他付 \(4\times20.2\)。但他可以先下一张 2 张的单,在 20.1 成交;再下一张 2 张的单,在 20.2 成交。每张单内部都是统一价,整体上他仍然拿到了歧视性定价的均价 20.15。只要订单可以连续提交,交易所就无法阻止这种拆分,“统一定价”在连续市场里形同虚设。这也说明了为什么 TWAP、VWAP 这些拆单算法在连续市场里天然存在。
连续市场要想有效切换到统一定价,只能停止连续交易。有些市场设有**交易暂停(trading halt)**规则:大额订单失衡会让价格移动过远或过快时暂停交易,过一段时间后以集合竞价恢复。暂停相当于从歧视性定价切换到统一定价。大交易者仍可拆单,但拆单会延迟成交,延迟够长就能抑制拆单。暂停还可能降低波动:它提醒其他人有异常的流动性需求,若有人进场提供流动性,价格变动会小于立即处理失衡时的变动。
6.6 连续市场与集合竞价:剩余、成交量与即时性
第 05 章说过,集合竞价把所有人的注意力集中在同一时刻,买卖双方更容易找到彼此,总剩余应当更高。用同一组订单计算连续竞价的剩余(表 6-9),估值仍取限价、Bif 取 20.3:
| 交易者 | 订单 | 成交量 | 均价 | 假定估值 | 剩余 |
|---|---|---|---|---|---|
| Sol | 卖 1@19.8 | 1 | 20.00 | 19.8 | 0.2 |
| Bea | 买 3@20.0 | 3 | 20.00 | 20.0 | 0.0 |
| Sam | 卖 2@20.1 | 2 | 20.10 | 20.1 | 0.0 |
| Bif | 市价买 4 | 4 | 20.15 | 20.3 | 0.6 |
| Stu | 卖 5@20.2 | 2 | 20.20 | 20.2 | 0.0 |
| Sue | 卖 6@20.0 | 6 | 20.03 | 20.0 | 0.2 |
| Bob | 买 2@20.1 | 2 | 20.10 | 20.1 | 0.0 |
| Ben | 买 2@20.0 | 2 | 20.00 | 20.0 | 0.0 |
| 合计 | 11 | 1.0 |
连续竞价总剩余 1.0,低于集合竞价的 1.6。原因在于 Sam 和 Stu:他们估值 20.1、20.2,高于 Bea、Ben 的 20.0,本应是买方,却在连续市场里卖给了 Bif,按自身估值成交,没有贡献剩余,还让 Bif 付了高价。
交易商视角。 如果 Sam 和 Stu 在 Sue 的卖单到达时于 20.0 买回(代替 Bea 和 Ben),他们的剩余为 \((20.1-20.0)\times2+(20.2-20.0)\times2=0.6\),连续市场的总剩余就回到 1.6。这时 Sam 和 Stu 实际上在做交易商:把 10:15 到达的买方 Bif 和 10:20 到达的卖方 Sue 跨时间撮合起来,往返利润正是他们促成有效配置的报酬。
即时性的价值不在剩余里。 连续市场的总剩余较小,但它让人在想交易的时候就能交易。Bif 若知道 Sue 会在 10:20 以 20.0 卖出,也许愿意等;他实际上是向 Sam、Stu 付钱买了“立即成交”。这种**即时性(immediacy)**的价值没有计入上面的剩余。
成交量不是市场质量的好指标。 对同一订单流,连续竞价的成交量不低于集合竞价,但总剩余不高于集合竞价。交易所若一味追求成交量,可以专门撮合“买方估值与卖方估值之差最小”的配对,这恰恰使总剩余最小。
这两个不等式对任意订单流都成立(假设没有撤单),证明不难,值得自己走一遍:
- 剩余:在估值等于限价的假设下,单一价格拍卖的成交集合恰好是“所有估值高于出清价的买方和所有估值低于出清价的卖方”,这是使 \(\sum v_B-\sum v_S\) 最大的分配;连续竞价只是另一种可行分配,总剩余不可能更大。
- 成交量:设集合竞价出清价为 \(p^*\),成交量 \(V^*=\min\{S(p^*),D(p^*)\}\)。连续交易结束时订单簿不交叉,所以不可能同时剩下一张限价 \(\ge p^*\) 的买单和一张限价 \(\le p^*\) 的卖单。于是要么所有限价 \(\ge p^*\) 的买单都已成交,连续成交量 \(\ge D(p^*)\ge V^*\);要么所有限价 \(\le p^*\) 的卖单都已成交,连续成交量 \(\ge S(p^*)\ge V^*\)。
推导拆解:成交量证明用的是“反证 + 二选一”,把每一步写开。
- 已知事实:连续交易中,任何一张订单到达时,只要能和对面成交就会立即成交。所以结束时订单簿上剩下的买单最高价一定低于剩下的卖单最低价,即“不交叉”。
- 反证:假设结束时既剩下一张限价 \(\ge p^*\) 的买单(未完全成交),又剩下一张限价 \(\le p^*\) 的卖单。那么买价 \(\ge p^*\ge\) 卖价,两者交叉,与第 1 步矛盾。所以这两类“剩单”不可能同时存在。
- 二选一:要么限价 \(\ge p^*\) 的买单全部成交了,它们的总量就是 \(D(p^*)\),每成交一张就计一张成交量,所以连续成交量 \(\ge D(p^*)\);要么限价 \(\le p^*\) 的卖单全部成交了,同理成交量 \(\ge S(p^*)\)。
- 收尾:\(V^*=\min\{S(p^*),D(p^*)\}\) 不超过两者中的任何一个,所以两种情况下连续成交量都 \(\ge V^*\)。
一个细节值得注意:第 1 步要求“没成交的订单都留在簿上”。本章引擎里市价单的未成交部分会被丢弃(不入簿),这相当于一次撤单,可能破坏上述论证。例如一张市价买单在订单簿为空时到达被丢弃,之后才来一张卖单,集合竞价能成交而连续竞价成交为 0。原文“假设没有撤单”的前提应理解为也包括这种情形;随机实验里只有限价单,所以不受影响。
6.7 交叉网络与衍生定价
交叉网络(crossing network)是唯一不属于拍卖的指令驱动市场:所有成交都以别处决定的价格进行,这叫衍生定价规则(derivative pricing rule)。它不发现价格,只发现“在这个价格上谁愿意买卖”。
原书写作时美国的主要股票交叉网络有三个:
- ITG 的 POSIT(经纪商运营):常规交易时段每天交叉 8 次,交叉价取撮合后 7 分钟内随机某一时刻主市场买卖报价的中点。交易者用它是为了以中间价成交且没有价格冲击。
- Instinet 的 Global Instinet Crossing:盘后交叉,用下午 4 点收盘价。
- NYSE 盘后交易时段 I:盘后交叉,用 NYSE 收盘价。
它们都是集合式的:先收订单,到点后按优先规则配对,凡能在交叉价成交的都成交。因为交叉价不是出清价,几乎总有一边超额,多数一方按规则配给。例如 POSIT 采用比例分配:某次交叉收到 3,000 股卖单和 5,000 股、10,000 股两张买单,卖量是买量的 20%,卖单全部成交,两张买单各成交 20%,即 1,000 股和 2,000 股。
交叉网络只能成交提交量的很小一部分(不到 10%),未成交部分再送往其他市场。人们仍然使用它,因为佣金低(每股 1–2 美分)、没有即时的市场冲击。三大网络都完全保密匿名,不展示订单,也不公布交叉后的失衡,因为交易者不希望别人知道自己的意图;若展示订单,交易者只会提交部分订单,而网络靠成交量赚钱,希望交易者提交完整订单。
现状补充:今天的“暗池(dark pool)”大多就是交叉网络,许多以 NBBO 中点为成交价、连续运行。POSIT 随 ITG 于 2019 年并入 Virtu。美国股市的收盘竞价(如 NYSE、Nasdaq 的 closing cross)已成为全天成交最集中的时点之一。
价格所有权之争
交叉网络只有在交易者信任交叉价格时才有效,所以必须取价于能产生可信价格的主市场。主市场认为这不公平:交叉网络“撇走订单流的奶油”(最容易成交的订单)却不为价格付费。交叉网络的客户反驳说,不参与价格发现就不该为价格发现付费;同时在主市场下单的交易者还主张,价格是他们的订单生产的,应当归他们所有。
问题一:陈旧价格与逆向选择
在一个预先约定的价格上成交,决定价格时公平的价格,到成交时可能已不公平。知道价值已变化的交易者只在对自己有利时才会在陈旧价格(stale price)上成交:价值上涨时热切买入、拒绝卖出,下跌时相反。轻信价格仍公平的交易者会发现,容易成交的时候往往事后后悔,成交不了的时候又希望当初成交了。这就是逆向选择(adverse selection),Harris 称之为影响交易的最重要力量之一。
例:美国主要市场 4 点收盘后,股票价值仍在变化,区域交易所交易到 4:30、ECN 盘后交易、芝加哥股指期货交易到美东 4:15。消息灵通者在向用 4 点收盘价交叉的系统提交订单时会利用这些信息:盘后价格上涨、出了利好、或收盘价落在买价而非卖价上时,这些网络收到的买单多于卖单。为部分缓解,两个网络对盘后有重大新闻的股票不做交叉。
金融直觉:CFA 道德准则案例里的 2003 年美国共同基金丑闻是同一个机制。共同基金按当日 4 点的净值(NAV)申购赎回,而持有的亚洲股票收盘价是十几个小时前的“陈旧价格”。美国白天如果大涨,第二天亚洲股票大概率高开,择时交易者当天按陈旧 NAV 申购、次日赎回,几乎无风险套利,损失由长期持有人承担。监管的对策是“公允价值定价”(fair value pricing),用期货、ADR 等信息调整陈旧价格,这正是本节所说“衍生定价有利于信息灵通者”的现实例子。
问题二:价格操纵
只要双方约定以将来在别处决定的价格成交,就有人有动机操纵那个价格:买方希望它低,卖方希望它高。
例:Bob 按约定以下午 1:30 前 NYSE 最后一笔 IBM 成交价从 Sally 处买 50 万股。若他在 1:29:30 提交 1,000 股市价卖单把价格压低 3 美分,在 50 万股上节省 15,000 美元,成本只有约 30 美元。
金融直觉:这个例子的关键是杠杆比:用 1,000 股的成本撬动 50 万股的结算价,收益与成本之比约 500 倍。所有“以某个时点的价格作为结算基准”的合约都面临同样的诱惑:LIBOR 操纵案、伦敦 4 点外汇定盘价(WM/Reuters fix)操纵案、期权到期日“砸盘/拉盘”,都是这个结构。防范手段也大同小异:拉长定价窗口(用 VWAP 或一段时间的平均价)、随机化定价时点(POSIT 的做法)、用集合竞价产生基准价(收盘竞价),目的都是提高操纵所需的成本。
侧栏:Jesse Livermore 操纵对赌行。对赌行(bucket shop)表面像经纪商,实际不把订单送往交易所,而是按报价带上的下一笔成交价与客户对赌。Livermore 同时在 5 家对赌行各下 100 股某只流动性差股票的买单,同时通过正规经纪商在交易所下 100 股紧急卖单,把成交价砸低,于是在对赌行以低价买入;然后反向操作。他在交易所的 100 股上亏钱,在对赌行的 500 股上赚得更多。
POSIT 的防操纵设计有两条:在撮合后 7 分钟内随机选取定价时刻,操纵者必须在整整 7 分钟里持续压价,成本更高也更容易被发现;所有订单保密,事后才报告结果,交易者事前不知道能否成交、成交多少。现金结算的期货和期权在到期时也面临同样的操纵问题,部分合约规定市场价格明显失真时交易所可以另定公允的最终结算价。
三种定价规则的利弊
Harris 在本章总结中这样概括:连续竞价的歧视性定价有利于大额流动性需求者、不利于小额流动性提供者;单一价格竞价的统一定价有利于小额流动性提供者、不利于大额交易者;交叉网络的衍生定价有利于信息灵通者(相对于无信息者)和操纵者(相对于诚实的小交易者)。价格优先是自我执行的,次级规则不是,而且次级规则只有在 tick 足够大时才有经济意义。
量化实战
1. 回测与模拟需要一个“合规”的撮合引擎
很多回测框架把成交简化为“按收盘价或下一根 K 线开盘价全部成交”,这在本章的语言里相当于假设了一个衍生定价、无限流动性、没有逆向选择的交叉网络。对低频大容量策略这也许够用,对日内策略、做市策略和大资金执行则会严重失真。一个最小的订单簿撮合引擎至少要做到:
- 价格优先 + 时间优先(或交易所实际使用的 pro rata / 混合规则);
- 连续竞价按挂单价成交(歧视性定价),集合竞价按统一出清价成交;
- 市价单视为价格无限积极的限价单,未成交部分按指令(IOC/FOK/入簿)处理。
下面的代码实现了这三点,并用原书表 6-1 作为单元测试:集合竞价应出清在 20.0、成交 7 张、总剩余 1.6;连续竞价应成交 11 张、总剩余 1.0。
import math
import numpy as np
import pandas as pd
INF = math.inf
def key(o):
"""价格优先 + 严格时间优先的排序键;市价单视为价格无穷积极的限价单。"""
p = o["price"]
if o["side"] == "B":
return (-(INF if p is None else p), o["seq"])
return ((-INF if p is None else p), o["seq"])
def crosses(buy, sell):
bp = INF if buy["price"] is None else buy["price"]
sp = -INF if sell["price"] is None else sell["price"]
return bp >= sp
# ---------- 1. 连续双边拍卖:歧视性定价(按挂单价格成交) ----------
def continuous_auction(orders):
bids, asks, trades = [], [], []
for seq, o in enumerate(orders):
o = dict(o, seq=seq, left=o["qty"])
book_same, book_opp = (bids, asks) if o["side"] == "B" else (asks, bids)
while o["left"] > 0 and book_opp:
best = book_opp[0]
buy, sell = (o, best) if o["side"] == "B" else (best, o)
if not crosses(buy, sell):
break
q = min(o["left"], best["left"])
trades.append(dict(time=o["t"], seller=sell["who"], buyer=buy["who"],
price=best["price"], qty=q)) # 挂单限价定价
o["left"] -= q; best["left"] -= q
if best["left"] == 0:
book_opp.pop(0)
if o["left"] > 0 and o["price"] is not None: # 市价单剩余不入簿
book_same.append(o); book_same.sort(key=key)
return pd.DataFrame(trades), bids, asks
# ---------- 2. 单一价格集合竞价:统一定价 ----------
def call_auction(orders):
od = [dict(o, seq=i, left=o["qty"]) for i, o in enumerate(orders)]
B = sorted([o for o in od if o["side"] == "B"], key=key)
S = sorted([o for o in od if o["side"] == "S"], key=key)
i = j = 0; matches = []
while i < len(B) and j < len(S) and crosses(B[i], S[j]):
q = min(B[i]["left"], S[j]["left"])
matches.append((S[j], B[i], q))
B[i]["left"] -= q; S[j]["left"] -= q
if B[i]["left"] == 0: i += 1
if S[j]["left"] == 0: j += 1
s_last, b_last, _ = matches[-1]
# 出清价区间:不低于最后成交卖单与未成交最优买单,不高于最后成交买单与未成交最优卖单
rest_b = [o["price"] for o in B if o["left"] > 0 and o["price"] is not None]
rest_s = [o["price"] for o in S if o["left"] > 0 and o["price"] is not None]
lo = max([p for p in [s_last["price"]] + rest_b[:1] if p is not None])
hi = min([p for p in [b_last["price"]] + rest_s[:1] if p is not None])
price = lo if lo == hi else round((lo + hi) / 2, 2) # 区间非单点时由交易所规则决定,此处取中点
trades = pd.DataFrame([dict(seller=s["who"], buyer=b["who"], price=price, qty=q)
for s, b, q in matches])
return trades, price
def schedule(orders, grid):
"""供需表:S(p)=限价<=p 的卖量,D(p)=限价>=p 的买量(市价单计入所有价格)。"""
rows = []
for p in grid:
S = sum(o["qty"] for o in orders if o["side"] == "S" and (o["price"] is None or o["price"] <= p))
D = sum(o["qty"] for o in orders if o["side"] == "B" and (o["price"] is None or o["price"] >= p))
rows.append(dict(price=p, supply=S, demand=D, excess_demand=D - S, volume=min(S, D)))
return pd.DataFrame(rows)
def surplus(trades, value):
s = 0.0
for r in trades.itertuples():
s += (value[r.buyer] - r.price) * r.qty + (r.price - value[r.seller]) * r.qty
return round(s, 4)
def pro_rata(fill, sizes):
"""比例分配:最大余数法取整。"""
raw = np.array(sizes) * fill / sum(sizes)
base = np.floor(raw).astype(int)
for k in np.argsort(-(raw - base))[: fill - base.sum()]:
base[k] += 1
return base
if __name__ == "__main__":
# 原书表 6-1
orders = [
dict(t="10:01", who="Bea", side="B", qty=3, price=20.0),
dict(t="10:05", who="Sam", side="S", qty=2, price=20.1),
dict(t="10:08", who="Ben", side="B", qty=2, price=20.0),
dict(t="10:09", who="Sol", side="S", qty=1, price=19.8),
dict(t="10:10", who="Stu", side="S", qty=5, price=20.2),
dict(t="10:15", who="Bif", side="B", qty=4, price=None),
dict(t="10:18", who="Bob", side="B", qty=2, price=20.1),
dict(t="10:20", who="Sue", side="S", qty=6, price=20.0),
dict(t="10:29", who="Bud", side="B", qty=7, price=19.8),
]
value = {o["who"]: o["price"] for o in orders}; value["Bif"] = 20.3 # 原书假定
print("== 供需表(表 6-5)==")
print(schedule(orders, [19.8, 20.0, 20.1, 20.2]).to_string(index=False))
ct, p = call_auction(orders)
print(f"\n== 集合竞价:出清价 {p},成交 {ct.qty.sum()} 张,总剩余 {surplus(ct, value)} ==")
print(ct.to_string(index=False))
kt, bids, asks = continuous_auction(orders)
print(f"\n== 连续竞价:成交 {kt.qty.sum()} 张,总剩余 {surplus(kt, value)} ==")
print(kt.to_string(index=False))
print("收盘订单簿 买:", [(o['who'], o['left'], o['price']) for o in bids],
" 卖:", [(o['who'], o['left'], o['price']) for o in asks])
print("\n比例分配:18 张卖单对 10 张与 20 张平等买单 ->", pro_rata(18, [10, 20]))
关键输出:
== 供需表(表 6-5)==
price supply demand excess_demand volume
19.8 1 18 17 1
20.0 7 11 4 7
20.1 9 6 -3 6
20.2 14 4 -10 4
== 集合竞价:出清价 20.0,成交 7 张,总剩余 1.6 ==
seller buyer price qty
Sol Bif 20.0 1
Sue Bif 20.0 3
Sue Bob 20.0 2
Sue Bea 20.0 1
== 连续竞价:成交 11 张,总剩余 1.0 ==
time seller buyer price qty
10:09 Sol Bea 20.0 1
10:15 Sam Bif 20.1 2
10:15 Stu Bif 20.2 2
10:20 Sue Bob 20.1 2
10:20 Sue Bea 20.0 2
10:20 Sue Ben 20.0 2
收盘订单簿 买: [('Bud', 7, 19.8)] 卖: [('Stu', 3, 20.2)]
比例分配:18 张卖单对 10 张与 20 张平等买单 -> [ 6 12]
全部数字与原书表 6-3、6-5、6-7、6-8、6-9 一致。把上面第一段代码完整保存为 c6_engine.py(其中的例题检验放在 if __name__ == "__main__": 下,导入时不会执行),并与下面的脚本放在同一目录,就可以拿它做随机实验。下面每次生成 30 张随机订单(估值服从 \(N(20,0.3^2)\),限价等于估值),比较两种机制,重复 2000 次:
import numpy as np, pandas as pd
from c6_engine import call_auction, continuous_auction, surplus
rng = np.random.default_rng(7)
rows = []
for k in range(2000):
n = 30
side = rng.choice(["B", "S"], n)
val = np.round(20 + rng.normal(0, 0.3, n), 2) # 私人估值,按估值报限价
qty = rng.integers(1, 6, n)
orders = [dict(t=i, who=f"T{i}", side=side[i], qty=int(qty[i]), price=float(val[i]))
for i in range(n)]
value = {o["who"]: o["price"] for o in orders}
try:
ct, p = call_auction(orders)
except IndexError: # 没有可成交的配对
continue
kt, _, _ = continuous_auction(orders)
rows.append(dict(vol_call=ct.qty.sum(), vol_cont=kt.qty.sum(),
sur_call=surplus(ct, value), sur_cont=surplus(kt, value),
px_std_cont=kt.price.std()))
df = pd.DataFrame(rows)
print(df.mean().round(3).to_string())
print("连续竞价成交量 >= 集合竞价的比例:", (df.vol_cont >= df.vol_call).mean())
print("集合竞价总剩余 >= 连续竞价的比例:", (df.sur_call >= df.sur_cont - 1e-9).mean())
输出:
vol_call 21.893
vol_cont 29.026
sur_call 10.190
sur_cont 8.168
px_std_cont 0.180
连续竞价成交量 >= 集合竞价的比例: 1.0
集合竞价总剩余 >= 连续竞价的比例: 1.0
2000 次全部满足 6.6 节证明的两个不等式:连续竞价平均多成交约 33%,总剩余却少约 20%。这正是“成交量不等于市场质量”的数值版本。
2. 把规则翻译成策略问题
- 排队位置建模:在价格—时间优先市场里,被动挂单能否成交取决于它前面排了多少量。tick 相对股价越大(A 股低价股、美股低价股),排队越长,“抢先排队”越值钱,挂单成交概率模型(queue position model)是做市和被动执行算法的核心部件。在 pro rata 市场里则应挂大单,因为分到的量与挂单量成正比;同一个策略在两种规则下的最优参数完全不同。
- 冰山单与显示优先:隐藏部分排在同价所有显示单之后。隐藏一部分订单可以减少信息泄露,代价是降低成交概率,这个权衡要用本市场的显示优先规则来量化。
- 参与集合竞价:开盘、收盘竞价采用统一定价,大单在竞价中成交可以避免逐档吃单。预测竞价出清价就是在估计本章的 \(S(p)\) 和 \(D(p)\);许多交易所会在竞价期间发布参考价和未匹配量,它们直接来自供需表。
- 拆单算法的制度根源:连续市场里大单拆分(TWAP、VWAP、实施缺口算法)是“自己对流动性提供者实施价格歧视”,同时尽量不让对手察觉总规模。
- 暗池路由与收盘价假设:中点撮合暗池的成交率低,而且成交本身就带有逆向选择,成交了往往说明对面消息更灵通。回测里“以收盘价成交”等同于衍生定价,若信号用到了收盘后才知道的信息,就会产生前视偏差。
本章小结
指令驱动市场由两套规则构成:订单优先规则决定谁先成交,成交定价规则决定以什么价成交。价格优先是所有市场的首要规则,而且自我执行;时间、显示、规模、公众订单等次级规则需要监督执行,并且只有在 tick 足够大时才有经济意义。规则撮合系统按“排序—匹配—定价”三步工作。单一价格拍卖以统一价格出清,在估值等于限价时同时使成交量 \(\min\{S,D\}\) 和总交易者剩余最大,对小交易者而言真实报价最优;连续双边拍卖按挂单价格成交,对同一订单流成交量更多、剩余更少,但提供了即时性,交易商通过跨时间中介收回部分剩余。大额不耐心交易者偏好歧视性定价,挂单者偏好统一定价,交易者会根据规则调整报价的积极程度和拆单方式。交叉网络用别处的价格撮合,佣金低、零冲击,但成交率低,并面临价格所有权、陈旧价格逆向选择和价格操纵三个问题。
| 概念 | 要点 |
|---|---|
| 价格优先 | 首要规则;市价单排第一;自我执行 |
| 时间优先 | 场内时间优先 / 严格时间优先;鼓励改善价格;不自我执行 |
| tick 与时间优先 | tick 太小:优先不值钱、挂单变少;tick 太大:不愿改价 |
| 显示优先、比例分配 | 显示单先于隐藏单;平等订单按 \(q_i/\sum q\) 分配 |
| 供需表 | \(S(p)=\sum_{\text{卖限价}\le p}q\),\(D(p)=\sum_{\text{买限价}\ge p}q\) |
| 成交量 | \(V(p)=\min\{S(p),D(p)\}\),出清价使其最大 |
| 交易者剩余 | 买方 \(v_B-p\),卖方 \(p-v_S\),一对之和 \(v_B-v_S\) 与价格无关 |
| 统一定价 | 集合竞价;剩余最大;挂单者偏好 |
| 歧视性定价 | 连续竞价按挂单价成交;大额不耐心者偏好;可被拆单复制 |
| 衍生定价 | 交叉网络;陈旧价格逆向选择;操纵风险;随机定价时刻防操纵 |
| 两个不等式 | 同一订单流:连续成交量 \(\ge\) 集合成交量;集合剩余 \(\ge\) 连续剩余 |
练习
基础
- 用表 6-1 的订单,在“场内时间优先 + 比例分配”规则下重做 10:30 集合竞价,Bea 和 Ben 各成交多少? 提示:出清价仍为 20.0。20.0 价位上 Bea(3 张)先到,享有场内时间优先,先成交;本例 20.0 价位买方只需成交 1 张,全部给 Bea,Ben 为 0。若两人平等,则 1 张按 3:2 比例分配,需要取整规则。
- 某连续市场订单簿为空,全天只来了一张限价 20 的买单和一张限价 19 的卖单。买单先到时成交价是多少?卖单先到呢?“先提供流动性的人拿到最差价格”合理吗?(原书第 6 章第 7 题) 提示:买单先到成交于 20,卖单先到成交于 19,挂单者把全部剩余让给了后来的吃单者。这是极不活跃市场的特殊情形:挂单者没有得到流动性补偿,在这种市场里应慎重挂出接近对方保留价的限价。
- 给出一组订单,使集合竞价中最后一个可成交配对的买价严格高于卖价,并讨论出清价如何确定。 提示:例如买 5@20.3、卖 5@20.0,无其他订单,出清区间为 [20.0, 20.3];交易所可以取中点、取最接近前收盘价的价格,或取使未成交量最小的价格。
- 解释为什么价格优先是自我执行的,而时间优先不是。 答案要点:接受报价的一方自然会找最好的价格,所以违反价格优先会直接损害接受者;同价位上接受谁的报价对接受者没有差别,只有拥有时间优先的人受损,所以需要他自己或交易所来捍卫。
- 在国债单一价格拍卖中,为什么小投标者应当按真实估值报价? 答案要点:小订单几乎不影响出清价,报价只决定是否中标;报得比估值保守只会增加“本可接受却落标”的风险,不会改善成交价。
进阶
- 证明:对任意订单流(无撤单),连续竞价的总成交量不小于单一价格拍卖的成交量。 提示:见 6.6 节,利用连续交易结束时订单簿不交叉。
- 修改量化实战中的引擎,加入“显示优先”:每张订单增加
hidden字段,同价位上显示单优先于隐藏单。构造一个例子,说明冰山单隐藏部分的成交顺序发生了变化。 - 设一只股票价格 3 元、tick 0.01 元,另一只价格 300 元、tick 相同。分别计算以 bp 表示的相对 tick,并讨论哪一只的排队位置更值钱、哪一只更可能出现大量挂单。 答案要点:约 33 bp 与 0.33 bp。前者插队成本高,时间优先价值大,买一卖一挂单量大、排队长;后者插队几乎免费,挂单量小、报价更新频繁。
- 讨论:连续市场若要强制统一定价,必须防止拆单或对已成交交易重新定价。在电子环境中能设计什么机制?为什么市场不会采用?(原书第 6 章第 2 题) 提示:例如把连续交易改为高频的周期性集合竞价,或事后按区间统一价重新结算;前者牺牲即时性,后者让成交价格不确定,交易者不会接受。
- 以收盘价交叉的系统里,消息灵通者如何伤害无信息的交易者?这对“以收盘价成交”的回测假设有何启示?(原书第 6 章第 5 题) 提示:利好出现时消息灵通者只买不卖,无信息的卖方被成交、买方成交不了,成交本身就是坏消息。回测若默认以收盘价成交,又用到收盘后的信息,就同时犯了前视偏差和忽略逆向选择两个错误。
原书推荐习题:第 6 章思考题第 1 题(tick 与次级优先规则)、第 2 题(电子环境下统一定价的机制设计)、第 3 题(计算机交易者与人类交易者的优先权)、第 4 题(价格所有权)、第 5 题(收盘价交叉中的逆向选择)、第 7 题(极不活跃市场谁提供流动性)。
原书对照
| 本章小节 | 原书章节 | PDF 页码 | 书内页码 |
|---|---|---|---|
| 6.1 共同骨架 | 第 6 章开篇 | p.125 | p.112 |
| 6.2 口头拍卖 | 6.1 Oral Auctions(含 Leapfrog、Common Cents、Price Discrimination 侧栏) | p.125–129 | p.112–116 |
| 6.3 规则撮合系统 | 6.2 Rule-based Order-matching Systems(表 6-1 至 6-4) | p.129–133 | p.116–120 |
| 6.4 单一价格拍卖与统一定价 | 6.3 The Uniform Pricing Rule and Single Price Auctions(表 6-5 至 6-7) | p.133–138 | p.120–125 |
| 6.5 连续双边拍卖 | 6.4 The Discriminatory Pricing Rule and Continuous Two-sided Auctions(表 6-8) | p.139–143 | p.126–130 |
| 6.6 连续与集合竞价比较 | 6.4.3(表 6-9) | p.143–145 | p.130–132 |
| 6.7 交叉网络 | 6.5 The Derivative Pricing Rule and Crossing Networks(表 6-10) | p.145–150 | p.132–137 |
| 小结与习题 | 6.6–6.8 | p.150–151 | p.137–138 |
(书内页码 ≈ PDF 页码 − 13。)