halo 的技术博客

返回

两个人在同一秒、同一个价位、挂同样大小的买单。一个十秒内成交了,另一个挂到价格跳走都没动。

价格一样,标的一样,数量一样。差在哪?差在队列位置——你前面还压着多少手别人的单子。这是回测里几乎从不建模、实盘里却决定生死的一个变量。

结论先放这:在本文的事件驱动仿真中,排在队首成交概率 84.0%、中位等待 0.75 秒;前方压 20 手时掉到 55.1%、3.48 秒;前方 150 手时只剩 4.2%;前方 300 手基本归零(0.4%)。同一个挂单价格,成交概率的跨度是 83.7 个百分点。你的回测假设”挂在最优价就能成交”,实际上是在假设你永远排第一。所有图表均由下文 Python 真实计算,固定种子可复现,非占位图。

队列位置决定成交:排第 1 成交率 84%、中位等待 0.75 秒,排到 300 手后只剩 0.4%

一、为什么”挂在买一价”根本不是一个完整的描述#

绝大多数回测的成交逻辑长这样:

# 典型的、错误的回测成交假设
if limit_price >= bar_low:      # 价格触及我的挂单价
    filled = True               # 就算成交
python

这行代码隐含了一个极强的假设:只要价格碰到我的价位,我一定成交。但真实的限价单簿是 FIFO(价格优先、时间优先) 的:同一个价位上,先到的排前面,市价单来了从队首开始吃。

所以”我挂在买一价 10.00”这句话是不完整的。完整的描述是”我挂在买一价 10.00,前面还有 23 手”。这两者的成交概率可以差出一个数量级。

要量化这件事,得建一个事件驱动的队列模型。我这一档挂单的命运,由四类事件决定:

事件强度对我的影响
市价卖单到达λ=1.0 次/秒从队首开始吃,吃穿我前面才轮到我
同价位新增挂单λ=3.0 次/秒排我后面,对我毫无帮助
同价位撤单λ=2.2 次/秒若撤的是我前面的,我前进一位
价格跳走λ=0.15 次/秒我这一档被抛在后面,等于作废

注意第二行——新增挂单只会排在你后面,永远不会帮你前进。队列只有两条前进途径:前面的人成交,或者前面的人撤单。

二、成交概率随队列位置的塌缩#

对每个队列位置跑 4000 次独立仿真:

前方手数成交概率中位等待(秒)因价格跳走作废
0(队首)84.0%0.7516.0%
279.1%1.0320.9%
573.9%1.4526.2%
1066.1%2.0933.9%
2055.1%3.4844.9%
4038.0%5.9862.0%
8017.5%10.6182.5%
1504.2%18.7795.8%
3000.4%34.8599.7%

这不是线性衰减,是塌缩。 从队首到前方 20 手,成交概率掉了 29 个百分点;到 80 手时已经腰斩两次;到 150 手基本可以认为挂了个寂寞。

机制在最后一列:价格跳走的概率随等待时间单调上升。排得越靠后,需要等的时间越长,等的时间越长,价格在你成交前跑掉的可能性就越大。队列位置差,本质上是在跟”价格保持不动”这件事赌时间,而时间站在价格那一边。

这条曲线直接否定了一类常见的策略假设:“我用限价单挂在最优价,所以我的成交成本是负的半个价差。” 前提是你能成交。前方 80 手时,你有 82.5% 的概率根本没成交,而市场已经跑掉了。

三、延迟的代价,翻译成队列位置#

低延迟到底值多少钱?这个问题通常被答成”快 300 毫秒”,但 300 毫秒本身不是钱。它变成钱的唯一路径,是队列位置。

设定一个具体场景:某个价位刚被刷新,所有人都在抢着挂单。低延迟的一方排到 q=3,慢 300 毫秒的一方排到 q=25(这 300 毫秒里,前面又插进来 22 手)。

延迟的真实代价:快手 q=3 成交率 77.2%,慢手 q=25 只有 49.1%,作废率从 22.8% 翻到 50.9%

快手 q=3慢手 q=25差距
成交概率77.2%49.1%28.1 个百分点
中位等待1.18 秒4.12 秒3.5 倍
因价格跳走作废22.8%50.9%翻倍

慢 300 毫秒,成交概率少 28 个百分点,超过一半的单子最终作废。 这就是主机托管、内核旁路、FPGA 那些投入的真实回报来源——它们买的不是”快”,是队列前排的位置。

反过来说,如果你的策略在前方 25 手的位置上仍然赚钱,那它就不吃延迟饭,你不需要为速度付钱。先算清楚自己的策略对队列位置的敏感度,再决定要不要买速度。

四、最反直觉的一点:成交了,可能是坏消息#

到这里为止,逻辑都是”排前面好”。但成交质量这一维完全不是这么回事。

逆向选择(adverse selection):你的限价买单被成交,意味着有人愿意在这个价位把货砸给你。对方为什么砸?很多时候因为他知道价格还要往下走。你的成交,是被知情交易者选中的结果。

我在仿真里记录了”成交后价格继续向不利方向移动”的比例:

逆向选择率各档位稳定在 60.5%~64.3%,被动挂单相对追价的优势随队列位置从 0.28 tick 衰减到 0.15 tick

前方手数02080150300
逆向选择率60.5%61.4%61.4%63.9%64.3%

几乎是一条平线(60.5%~64.3%)。 排在队首成交得更快,但成交的”质量”一点都不更好——因为成交这个事件本身就携带了坏消息,跟你排第几无关。

这推出一个实务上很重要的结论:队列位置改善的是成交率,不是成交质量。 想降低逆向选择成本,得靠别的手段(选择价位、控制挂单时机、检测大单流),抢队列位置对此毫无帮助。

把两者合起来算净收益。以 tick 为单位:被动成交省下半个价差(+0.5 tick),逆向选择时平均吃亏 1.15 tick,没成交则要事后追价(-0.35 tick):

净收益=f(0.5a1.15)(1f)0.35\text{净收益} = f\cdot(0.5 - a\cdot 1.15) - (1-f)\cdot 0.35

前方手数02080300
被动挂单净收益(tick)-0.221-0.271-0.325-0.350
相对追价的优势(tick)+0.279+0.229+0.175+0.150

两个诚实的读数:

1. 被动挂单在这套参数下净值为负(-0.22 到 -0.35 tick)。 因为 61% 的逆向选择率太高,省下的半个价差覆盖不了被选中的成本。这不是仿真的 bug,而是做市这门生意的真实困难——光靠”挂单省价差”是不赚钱的,必须叠加库存管理、方向判断或返佣

2. 但被动挂单始终优于主动追价(-0.50 tick)。 优势从队首的 +0.279 衰减到深队列的 +0.150,几乎腰斩。队列位置吃掉的是相对优势,不是绝对收益。

五、四项对抗式检验#

对抗式检验:关掉队列机制后位置影响塌缩、独立解析式相关 0.979、流量翻倍救不回深队列

检验一:关掉队列机制的对照组。 如果我的结论真的来自 FIFO 排队,那么把队列机制拆掉(成交与位置无关),位置的影响就该消失。结果:成交概率在各档位之间只在 86.0%~87.5% 之间波动,跨度 1.6 个百分点,而含队列机制时跨度是 83.7 个百分点。差 53 倍——效应确实来自队列,不是别的地方漏进来的。

检验二:独立解析式交叉验证。 抛开仿真,纯用排队论近似:需要消耗 q+1q+1 手,市价单流量 λmktsˉ=4\lambda_{mkt}\cdot \bar{s} = 4 手/秒,那么在价格跳走前完成的概率约为 exp(λmove(q+1)/4)\exp(-\lambda_{move}\cdot(q+1)/4)。这个完全独立推导的公式与仿真结果相关系数 0.979。两条独立路径给出同一个形状,说明仿真代码没有实现层面的 bug。

检验三:种子稳健性。 固定 q=20,换 12 个随机种子各跑 1500 次:成交率均值 53.1%,标准差 0.009。结论不是某一个种子的运气。

检验四:参数敏感性——流量翻倍能救回深队列吗? 把市价单流量减半、翻倍再跑:

前方手数02080150
流量 ×0.570.9%39.9%8.8%1.7%
基准82.7%55.0%18.6%5.1%
流量 ×291.3%68.9%33.2%15.2%

即使成交流量翻倍,前方 150 手的位置也只有 15.2% 的成交率。 结论对参数不敏感:深队列位置是结构性劣势,靠”今天成交活跃”补不回来。

六、这对回测意味着什么#

1. 限价单回测必须建模队列位置,否则系统性高估收益。 最低配的修正:给每个限价单一个成交概率折扣,按前方挂单量估计。用 bar_low <= limit_price 就算成交,等于假设自己永远排第一。

2. 成交率和成交质量是两个独立的维度,别混为一谈。 队列位置只影响前者(84.0%→0.4%),对后者几乎无影响(60.5%→64.3%)。改善这两件事需要完全不同的手段。

3. 先测策略对队列位置的敏感度,再决定要不要投资低延迟。 如果策略在 q=25 依然为正,你不需要买速度;如果只在 q<5 才成立,那这个策略的真实门槛是基础设施而不是信号。

4. 挂单量大的价位不是”支撑强”,而是”你排更后面”。 很多人看到买一档堆了 500 手就觉得安全,从执行角度看这恰恰是最差的位置——前面 500 手要先被消化。

5. 被动挂单不等于零成本。 本文参数下净值 -0.22 到 -0.35 tick。只有当逆向选择率被压到 a<0.5/1.1543.5%a < 0.5/1.15 \approx 43.5\% 时,纯被动挂单才可能转正。做市商靠的从来不是价差本身,是返佣、库存周转和信息优势。

结语#

同样的价格,同样的时间,同样的数量——成交概率可以从 84.0% 一路塌到 0.4%,唯一的差别是你前面站了多少人。这就是队列位置,一个在回测里几乎不存在、在实盘里决定一切的变量。

它同时解释了两件事:为什么低延迟值钱(慢 300 毫秒,成交率少 28 个百分点,一半订单作废),以及为什么低延迟不是万能的(逆向选择率在各档位都稳定在 61% 上下,排第一也躲不掉被知情交易者砸货)。

下次你的限价单策略回测出漂亮曲线,先问一句:这些成交,假设我排在第几位? 如果答案是”没想过”,那这条曲线大概率是队列位置这个变量替你付的钱。

限价单排队位置:同样的价格,为什么你总是最后成交
https://blog.halo26812.eu.org/blog/queue-position-limit-order
Author halo
Published at 2026年8月1日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨