永续合约系统设计(三):撮合引擎

1 评论 463 浏览 1 收藏 60 分钟

永续合约中的撮合引擎远不止简单的买卖匹配,它是整个系统风险管理的核心枢纽。从订单准入门禁到中央限价订单簿的L4队列,本文深度解析撮合引擎如何将交易意图转化为全系统公认的市场事实,以及为何永续合约需要比传统交易更严格的撮合边界设计。

前两篇文章分别讨论了永续合约的系统框架永续合约系统设计(一):综述,以及定价引擎如何管理“价格使用权”永续合约系统设计(二):定价引擎。这一篇继续往下看撮合引擎。觉得我的文章对你有帮助,别忘了点赞转发~

很多人会把撮合理解成:买单和卖单价格对上就成交,对不上就挂单。这个理解没错,但放在永续合约里还不够。

永续合约没有真实交割物,却要围绕合约价格持续交易;它允许高杠杆,也必须在极端行情下快速识别和转移风险。因此,每一笔成交都不只是订单结果,还会继续影响仓位、保证金、清算、做市、行情和风控系统。

所以,撮合引擎的核心职责不是“帮助用户成交”,而是把不同来源的交易意图,转化为全系统共同承认的市场事实。

这些交易意图可能来自普通用户、API、做市商、触发单、TWAP 子单,也可能来自清算过程中的减仓订单。来源不同,目的不同,但只要进入同一个订单簿,就必须接受同一套撮合规则。

如果说定价引擎回答的是“系统相信什么价格”,那么撮合引擎回答的就是:谁先成交,以什么价格成交,成交之后留下什么事实。

一、撮合引擎的系统边界:它生成市场事实,但不定义价格真相

讨论撮合引擎,第一件事是划清边界。

在永续合约系统里,“价格”不是一个概念。指数价、标记价、盘口成交价、最新成交价、强平参考价,都叫价格,但作用完全不同。

指数价代表外部市场共识,标记价用于计算未实现盈亏、保证金风险和清算触发,盘口成交价则来自订单簿,是买卖双方真实成交出来的价格。

撮合引擎处理的是成交价。

成交价不是系统对资产真实价值的判断,而是订单簿在某个瞬间的执行结果。它由主动订单和被动挂单共同决定,受盘口深度、价格档位、时间优先级、订单类型和剩余数量影响。

因此,不能把标记价理解为撮合价格,也不能把最新成交价理解为系统真相。

例如,某合约标记价是 100,最优卖价是 100.2。用户提交一笔买入 IOC,最高愿意以 100.5 成交。只要订单通过前置校验,撮合引擎只关心它能不能和当前卖盘成交。如果 100.2 的卖单数量不够,它会继续向 100.3、100.4 的卖盘扫过去。

撮合引擎不会因为标记价是 100,就强制订单以 100 成交。标记价可以参与价格限制、风险校验和清算判断,但它不是订单簿里的成交价格。

这就是撮合引擎最重要的边界:

定价引擎定义价格的使用权,撮合引擎生成交易的事实权。

这里的“事实权”,指的是全系统都要承认的交易结果。成交价、成交量、订单状态、Maker/Taker、费用和盘口变化一旦生成,就会继续传递给仓位、保证金、清算、行情、审计和资产系统。

因此,撮合引擎负责的是一条清晰链路:订单经过前置门禁,进入订单簿,按价格时间优先规则匹配;成交后,系统生成成交记录,更新订单状态和盘口深度,并把事件发布给下游系统。

相反,指数价、标记价、资金费率、保证金、清算触发、保险基金和 ADL,都不是撮合引擎直接解决的问题。它们可以影响订单能不能进场,但不能替代撮合规则。

例如,价格限制可以挡住明显偏离合理区间的订单,保证金检查可以阻止账户超额开仓,只减仓规则可以限制风险账户继续扩大仓位,OI 上限可以控制单个市场的总风险暴露。清算引擎也可以生成减仓订单,但这些都是撮合前后的约束,不是撮合规则本身。

一旦订单被允许进入同一个订单簿,撮合引擎就应该按照同一套规则处理它。

这点对永续合约尤其重要。用户看的是盘口和 K 线,风控系统看的是标记价和保证金率,做市商看的是库存、价差和对冲成本,清算系统看的是账户风险和可退出深度。如果边界不清,系统问题很容易被错误归因。

所以,撮合引擎生成市场事实,但不定义价格真相。它是订单簿规则的执行者,是成交记录的源头,但不是风险价格的设计者,也不是所有风险判断的终点。

二、一笔订单进入撮合前,要先通过哪些门禁

订单不是用户一点“买入”或“卖出”,就能直接进入撮合引擎。

成熟的永续合约系统里,撮合引擎应该只处理“已经被系统允许执行的订单”。在订单进入中央限价订单簿之前,系统会先经过一组前置门禁,把无效订单、异常订单、超出账户能力的订单、可能放大系统风险的订单挡在撮合之外。

这组门禁的作用,不是替代撮合规则,而是保护撮合规则。

如果没有前置门禁,很多本不该进入市场的订单都会被推给撮合引擎:价格异常、保证金不足、开放订单超限、市场暂停期间提交,或在 OI 触顶后继续增仓。它们一旦进入订单簿,就不再只是错误请求,而可能变成盘口噪声和风险传导的起点。它们一旦进入订单簿,就不再只是错误请求,而会变成盘口变化、成交冲击、行情噪声,甚至连锁风险的起点。

可以把订单进入撮合前的筛选简化为:

可撮合订单 = 合法账户 × 可交易市场 × 有效价格 × 账户容量 × 风险容量

第一道门:账户与订单动作是否合法

在 CEX 中,这一层主要检查账户权限、API 权限、子账户权限、风控标签和请求频率;在 DEX 或链上订单系统中,则更多表现为签名、nonce、地址权限和动作顺序校验。核心问题只有一个:这笔订单有没有资格改变市场状态。

这层校验不是为了证明用户能不能使用产品,而是为了证明这笔订单有没有资格改变市场状态。一旦订单进入撮合,它就可能改变盘口、影响成交、触发行情事件,甚至影响其他人的策略判断。

第二道门:市场状态

一个永续市场可能处于正常交易、暂停交易、恢复交易、下线、结算、只允许减仓等不同状态。当市场正常交易时,订单可以继续进入后续校验;当市场暂停或下线时,普通订单不应继续进入撮合;当市场只允许退出风险时,系统可能只接受减仓类动作,而不允许继续扩大敞口。

这道门禁回答的是:这个市场现在是否还允许新的交易意图进入?

第三道门:价格准入

价格准入不是定价引擎本身。定价引擎负责生成指数价、标记价、价格锚和风险参考;订单入口只是使用这些价格结果,判断用户提交的订单价格是否可以被系统接受。

价格准入通常看三类问题:

第一,价格格式是否有效,是否符合 tick size 和市场精度;

第二,价格是否过度偏离指数价、标记价或其他价格锚;

第三,订单语义是否成立,例如 Post Only 不能一提交就吃单,IOC 或市价语义订单必须落在可接受滑点范围内。

这也是订单入口和撮合引擎最容易被混淆的地方。标记价不是成交价,但它可以成为订单价格的保护边界。

例如,某合约标记价是 100,用户提交一笔买入限价单,价格是 500。撮合引擎从纯订单簿视角看,可能认为这笔订单愿意吃掉所有 500 以下的卖盘。但从永续系统视角看,这种订单可能是误操作、攻击、异常策略或薄盘口操纵的一部分,不能简单放进撮合。

第四道门:账户容量

很多人理解订单校验时,只会想到保证金够不够。但真实交易系统里,账户容量不只包括钱,还包括开放订单数量、订单槽位、动作额度和状态维护成本。

开放订单指的是还没有进入终态的订单,例如挂在订单簿里的 GTC 订单、等待触发的条件单、部分未成交的订单等。它和 API 请求限频不同:限频限制的是你能发多少动作,开放订单限制的是你能在系统里留下多少状态。

第五道门:风险容量

这包括保证金是否足够、订单是否会增加仓位、是否只允许减仓、市场未平仓量是否接近或达到上限。

  • 保证金检查要回答的是:如果这笔订单成交,账户是否有足够权益承担新的仓位和风险?
  • 只减仓规则要回答的是:这笔订单是否真的降低风险,而不是表面写着 reduce only,实际却可能扩大仓位或翻到另一侧?
  • OI 上限要回答的是:这个市场还能不能继续增加未平仓风险?

这几类规则背后的系统目标是一致的:不要让一笔订单在成交之前就已经注定会制造风险。

高级订单也必须在执行瞬间重新确认资格

触发单和 TWAP 也不能绕过门禁。触发单在创建时只是一个待执行意图,真正触发后仍要生成真实订单,并重新接受市场状态、价格限制、保证金、只减仓和 OI 上限校验。TWAP 也是如此:用户提交的是执行计划,但每个子单都必须在发出那一刻重新确认成交资格。

订单意图可以提前创建,但成交资格必须在执行瞬间重新确认。

前置门禁决定“能不能进场”,撮合规则决定“进场之后怎么成交”。两者不能混在一起。

三、中央限价订单簿:L2 深度和 L4 队列不是一回事

通过前置门禁之后,订单才真正进入撮合引擎的核心区域:中央限价订单簿。

很多人第一次看订单簿,会把它理解成交易页面上的买卖盘:买盘、卖盘、价格档、数量。价格越接近中间价,越容易成交;数量越厚,说明流动性越好。

这个理解适合看行情,但不是撮合引擎真正看到的订单簿。

1. 中央限价订单簿不是报价表,而是有序队列

交易页面上展示的盘口,通常是 L2 深度;撮合引擎真正执行的,是更细粒度的订单队列。两者有关联,但不是一回事。

中央限价订单簿的核心不是“显示价格”,而是把所有未成交的限价订单,按照确定性规则组织起来,等待后续订单来成交。

一个永续合约市场通常维护两侧订单簿:买盘和卖盘。买盘按照价格从高到低排列,因为买得越贵,成交意愿越强;卖盘按照价格从低到高排列,因为卖得越便宜,成交意愿越强。

但这只解决了不同价格之间谁优先的问题。同一个价格档内部,如果有多个订单,谁先成交?

答案是时间优先。

也就是说,同一个价格档内部,不是简单合并成一个数字,而是有一条按进入订单簿时间排序的队列。谁先进入这个价格档,谁就排在前面;后进入的订单,即使价格相同,也要排在后面。

所以,中央限价订单簿真正的结构是:

  • 买侧:高价优先,同价按时间排队。
  • 卖侧:低价优先,同价按时间排队。

2. L2 深度是聚合视图,不是撮合队列

用户在交易页面上看到的大多是 L2 深度。L2 会告诉你某个价格上一共有多少数量,可能还会告诉你这个价格档里有多少笔订单。

例如,卖盘上显示 100.2 这个价格档有 30 张合约,包含 3 笔订单。对普通交易者来说,这已经足够有用。用户可以看到最优卖价、价差、一定范围内的深度,以及大单扫过去大概会造成多少滑点。

但从撮合引擎视角看,“100.2 有 30 张”是不够的。

因为这 30 张背后可能是三笔订单:第一笔 10 张最早挂入,第二笔 5 张排在中间,第三笔 15 张最后挂入。如果此时有一笔买单以 100.2 的价格吃进来,数量是 12 张,撮合引擎不会按比例从三笔订单里各成交一部分,而是先吃第一笔 10 张,再吃第二笔 2 张。第三笔完全不动,第二笔剩余 3 张继续排在队列前部。

从 L2 视角看,结果只是 100.2 这个价格档从 30 张变成 18 张。

但从撮合视角看,发生的是第一笔挂单完全成交,第二笔挂单部分成交,第三笔挂单队列位置前移。

这就是 L2 和 L4 的根本区别。

L2 关注“这个价格档总共有多少量”;L4 关注“这个价格档里每一笔订单是谁先谁后、各自还剩多少”。

3. 专业交易者为什么不能只看 L2

对于普通用户,L2 足以支持基本判断;但对于做市商、套利策略、风控系统和清算观察系统,只看 L2 往往不够。同样是挂在最优买价,排在队首和排在队尾,成交概率完全不同。队首订单只要有卖方主动吃进来,就可能率先成交;队尾订单则要等前面的订单全部被吃掉,才轮到自己。

所以,高频做市和研究级回测会关心 L4 订单簿、原始订单变化、逐笔事件和本地订单簿重建。它们不是为了看得更细,而是为了把盘口从聚合深度还原成可执行的队列结构。

4. 永续合约为什么更需要区分 L2 和 L4

在永续合约中,这一点尤其重要。订单簿不只服务于普通交易,还服务于做市、库存退出、清算扫簿和风险监控。L2 告诉我们市场表面上有多少深度,L4 告诉我们这些深度在执行层如何排队。前者让市场可见,后者让成交可判定。

四、撮合规则:主动单消耗深度,被动单决定成交价格

理解了订单簿之后,下一步就是看撮合到底怎么发生。

真实的撮合规则要回答三个问题:什么情况下订单可以成交,和谁先成交,以什么价格成交。

在永续合约的中央限价订单簿里,最核心的规则仍然是价格时间优先。更直观地说:

主动单负责消耗订单簿深度,被动单决定成交价格。

4.1 价格交叉:什么情况下订单可以成交

这里的主动单和被动单,不是指用户主观上积极或保守,而是撮合引擎里的订单角色。已经挂在订单簿里、等待别人来成交的订单,叫被动单,也就是 Maker 订单。新进入系统、试图立即与订单簿里的对手盘成交的订单,叫主动单,也就是 Taker 订单。

当一笔订单进入撮合引擎后,系统首先判断它是否和对手盘价格交叉。

买单能否成交,取决于:买入限价 ≥ 当前最优卖价

卖单能否成交,取决于:卖出限价 ≤ 当前最优买价

如果买单价格低于最优卖价,说明买方出价还不够高,不能立即成交;如果卖单价格高于最优买价,说明卖方要价还不够低,也不能立即成交。此时,GTC 订单可能进入订单簿等待,IOC 订单则会取消未成交部分。

一旦价格交叉,撮合就开始了。

4.2 限价不是成交价,而是最差可接受价格

这里有一个常见误解:用户提交的限价,不一定等于成交价。

假设当前卖盘是:100.2 有 30 张,100.5 有 40 张,101.0 有 50 张。用户提交一笔买入限价单,价格是 101.0,数量是 60 张。很多新手会以为,既然挂的是 101.0,就会按 101.0 成交。

但在中央限价订单簿里,101.0 只是买方愿意接受的最高价格,不是系统必须执行的成交价格。

撮合引擎会先吃最便宜的卖盘。所以这笔买单会先以 100.2 成交 30 张,再以 100.5 成交 30 张。它不会跳过更便宜的卖单,直接按用户的最高限价成交。

买入限价是最高可接受价格,卖出限价是最低可接受价格。限价保护用户不以更差价格成交,但不阻止用户获得更好的成交价格。

这也是“被动单决定成交价格”的含义。主动买单跨过价差后,并不是按自己的买入限价成交,而是按订单簿上被吃掉的卖方挂单价格成交。主动卖单也是一样,它会按被吃掉的买方挂单价格成交。

4.3 扫簿与滑点:主动单如何逐档消耗深度

如果主动单数量小于最优价位的可成交数量,撮合只发生在一档内。如果主动单数量大于最优档深度,它就会继续向下一档扫。

这就是扫簿。

扫簿的本质,是主动单沿着订单簿逐档消耗被动流动性。数量越大,或者盘口越薄,主动单越容易穿透多个价格档,成交均价也越容易偏离最优价。

滑点不是系统额外收取的费用,也不是撮合引擎故意给差价,而是订单规模相对于盘口深度过大时,真实成交路径自然产生的价格冲击。

可以简单理解为:滑点 = 实际成交均价 – 下单前可见最优价

对于买单来说,越往上扫,成交均价越高;对于卖单来说,越往下打,成交均价越低。

4.4 成交数量:每一轮撮合都由双方剩余量决定

每一轮撮合里的成交数量也很简单:本轮成交数量 = min(主动单剩余数量,被动单剩余数量)

如果主动单剩余 100 张,被动单只有 30 张,本轮成交 30 张,被动单完全成交,主动单还剩 70 张,继续找下一笔被动挂单。如果主动单剩余 20 张,被动单有 50 张,本轮成交 20 张,主动单完全成交,被动单剩余 30 张,继续留在订单簿原来的位置。

4.5 订单和成交记录为什么不是一回事

这个规则带来一个重要结果:一笔订单可以对应多笔成交。

用户提交的是一笔订单,但如果它连续吃掉多个价格档、多个被动挂单,系统就会生成多条成交事实。前端为了展示体验,可能会把它聚合成一个平均成交价;但从撮合和对账视角看,每一笔 fill 都有自己的价格、数量、Maker/Taker 归因和费用结果。

因此,订单状态和成交记录不是一回事。订单状态回答“这笔订单最终是成交、部分成交、挂簿、取消,还是拒绝”;成交记录回答“它到底在哪些价格、和哪些被动流动性、成交了多少”。

4.6 撮合规则的价值,是让市场结果可解释

撮合规则的真正价值,不只是公平,而是确定性。成交事实一旦生成,就会继续进入仓位、保证金、费用、清算监控和风控分析。如果撮合顺序不可解释,后续所有系统都会失去可信基础。

五、订单类型:不是改变撮合规则,而是锁定执行语义

讲完撮合规则后,很容易产生一个误解:既然撮合引擎都按价格时间优先执行,为什么还需要这么多订单类型?

GTC、Post Only、IOC、Reduce Only、触发单、TWAP、市价单、止盈止损,听起来像一组复杂功能按钮。但从撮合引擎视角看,它们并不是在创造多套撮合规则,而是在表达不同的执行语义。

订单类型不是改变撮合物理规则,而是提前锁定订单进入撮合后的行为边界。

只要订单进入同一个中央限价订单簿,最终都要回到价格时间优先。订单类型真正约束的是三件事:能不能立即成交,剩余部分能不能留簿,以及这笔订单是否允许增加仓位。触发单和算法单只是把“什么时候进入撮合”这个问题单独拿出来管理。

1. GTC:能成交就成交,剩余可以继续挂簿

GTC 是最基础的限价语义。它表达的是:我愿意在这个价格或更好价格成交;如果现在不能全部成交,剩余部分可以留在订单簿里继续等待。

所以,GTC 既可能成为 Taker,也可能成为 Maker。如果一笔买入 GTC 的价格高于或等于最优卖价,它会先主动吃掉可成交卖盘;如果吃完后还有剩余,而且剩余价格不再与对手盘交叉,它就会挂在买盘队列里,成为被动订单。

2. IOC:立即成交,剩余不留簿

IOC 是 Immediate or Cancel,也就是立即成交或取消。它表达的是:我想现在成交,但不想把未成交部分留在订单簿里。IOC 会立即尝试与订单簿中的对手盘成交,能成交多少就成交多少;如果只成交一部分,剩余部分立刻取消;如果完全没有可成交流动性,则整笔订单取消或拒绝。

IOC 不是无限市价单。一个设计良好的 IOC 仍然应该有价格边界。买入 IOC 只吃不高于限价的卖单,卖出 IOC 只吃不低于限价的买单。超过限价边界的深度,即使存在,也不应该被吃掉。

3. Post Only / ALO:锁定 Maker 身份,但不提供撮合优先权

Post Only,也常被称为 ALO,即 Add Liquidity Only。它的语义是:我只想提供流动性,不想在提交瞬间消耗流动性。

如果一个 Post Only 订单提交时会立即与对手盘成交,系统就应该拒绝或取消,而不是让它变成 Taker。它锁定的是“提交瞬间不能成为 Taker”,不是保证未来一定赚钱。成功挂簿后,它仍然可能被主动单打到,形成被动成交和库存风险。

Post Only 也没有撮合优先权。它成功进入订单簿后,仍然和其他挂单一样,按价格时间优先排队。它不是特殊账户通道,也不是做市商插队机制。

4. Reduce Only:锁定风险方向,防止减仓单变成增仓单

Reduce Only,也就是只减仓,是永续合约里非常关键的一类订单语义。它表达的是:这笔订单只能降低已有仓位风险,不能增加仓位,也不能把仓位翻到另一侧。

现货里,卖出就是卖出资产;永续里,卖出既可能是平多,也可能是开空。买入也一样,既可能是平空,也可能是开多。如果没有 Reduce Only,用户想减仓时可能因为仓位变化、部分成交、并发订单或行情波动,意外建立反向仓位。

Reduce Only 是风险语义,不是撮合特权。它不会让订单优先成交,也不会改变成交价格。它只告诉系统:这笔订单即使价格交叉,也只有在降低仓位风险的范围内才允许执行。

5. 市价语义订单:即时成交也需要价格保护

市价语义订单也需要谨慎理解。对用户来说,市价单就是现在立刻买入或卖出。但在永续合约系统里,严肃的市价语义通常不应该理解成任何价格都可以成交。更合理的做法,是把它转换成带价格保护的即时执行订单。

也就是说,前端或系统会根据当前盘口、滑点保护、价格锚、最大可接受偏离等条件,为市价语义订单生成一个可执行边界,然后再进入撮合。它表现为尽快成交,但不能没有边界地扫穿订单簿。

6. 触发单与 TWAP:高级订单只是不同入场路径

触发单和 TWAP 看起来更高级,但它们也不是新撮合规则,而是不同入场路径。

触发单在触发前不进入普通订单簿,不参与排队,也不增加 L2 可见深度。只有当指定价格源达到条件后,它才被激活,转成市价语义订单或限价订单,再进入普通订单入口和撮合链路。

所以,触发价不是成交价。触发成功也不等于成交成功。Market TP/SL 优先追求执行,代价是滑点风险;Limit TP/SL 优先控制价格,代价是可能触发了但没有成交。

TWAP 则是执行计划,不是一笔更复杂的订单。用户提交总数量、方向、执行时长、是否只减仓、是否随机化等参数,系统按时间间隔生成子订单,让每个子订单进入普通订单簿执行链路。

TWAP 降低的是瞬时冲击,不是消灭执行风险。它把一次性大单拆成多个子单,让市场有时间补充流动性,但也引入了时间风险:价格可能持续朝不利方向移动,盘口可能越来越薄,子单也可能因为滑点保护或风控限制无法按计划成交。

订单类型的价值,是把用户模糊的交易意图翻译成系统可执行、可验证、可拒绝的规则语言。撮合引擎只认规则,不认意图;订单类型的作用,就是把意图翻译成规则。

六、撤单、改单与 Cancel Replace:订单簿深度不是静态承诺

订单生成之后,还有一类动作同样重要:撤单和改单。

从普通用户视角看,撤单和改单像是订单管理功能:价格挂错了就撤掉,数量不合适就改一下,行情变了就重新报价。但从撮合引擎视角看,撤单和改单会直接改变订单簿里的可成交深度、同价队列位置、最优买卖价,以及后续主动单看到的市场状态。

下单增加未来可成交深度,撤单移除未来可成交深度,改单重构未来可成交深度。

所以,订单簿不是一个静态承诺。用户看到的 L2 深度,只代表某个时刻订单簿里还有多少未成交挂单。下一秒,这些挂单可能被成交,也可能被撤掉,也可能被改到另一个价格。

1. 撤单:移除未来成交可能性

撤单不是反向交易,而是把仍处于开放状态的订单,从可成交集合中移除。它不会产生成交记录,不会改变仓位,不会产生 Maker/Taker 费用,也不会形成新的市场价格。它改变的是未来:这笔订单不再作为被动流动性等待别人来成交。

例如,卖盘上 100.2 有 30 张,其中 10 张来自某个用户的限价卖单。如果这 10 张被撤掉,L2 上 100.2 的聚合数量会从 30 张变成 20 张。若这一档原本只有这 10 张,撤单后该价格档会直接消失,最优卖价可能跳到下一档。

这意味着,撤单会改变后续主动买单的成交路径。一笔原本可以在 100.2 成交的买单,可能因为撤单先发生,只能去吃 100.5。

在做市场景里,撤单尤其重要。做市商挂在订单簿里的报价,并不是永远愿意成交的静态承诺。它们通常基于当前参考价格、库存状态、盘口深度、外部市场价格、资金成本和风险阈值生成。一旦参考价格变化、库存偏离、盘口失衡、价格源异常,原来的报价就可能变成旧报价。如果不及时撤单,做市商可能被更快的主动流吃掉,形成不利库存。

撤单本身不是坏事。没有撤单能力,做市商无法管理风险,也不敢提供密集报价。但撤单率过高会让表面深度不稳定。一个市场看起来有很多挂单,但这些挂单在价格稍有波动时迅速消失,那么它的真实承接能力就弱于 L2 上显示的数字。

2. 改单:旧订单退出,新参数重新进入

改单比撤单更复杂。

用户表面上只是把价格从 100.2 改成 100.5,但对撮合系统来说,这通常不能理解成在原订单上随便改一个字段。更合理的产品抽象是:

改单 = 定位旧订单 + 校验旧订单可修改 + 用新参数重新进入订单通道

只要改单影响价格、数量、订单类型、只减仓标记或触发参数,就可能影响成交优先级或风险结果,因此必须重新校验。新订单仍然要过市场状态、价格精度、保证金、只减仓、OI 上限、开放订单容量等门禁。它也可能因为新价格与对手盘交叉而立即成交,可能重新挂簿,可能因为 Post Only 会立即成交而被拒绝,也可能因为风控限制失败。

3. Cancel Replace:减少动作缝隙,但不是撮合特权

改单是用户表达的动作,Cancel Replace 是系统实现改单的一种方式。前者回答“用户想改什么”,后者回答“撮合系统如何处理这个修改”。

如果只是减少剩余数量,一些系统可能允许原地修改,并保留原来的队列位置;但如果修改价格、增加数量,或改变 Post Only、Reduce Only 等执行语义,系统通常会把它视为取消旧订单、提交新订单。此时旧订单退出原队列,新订单重新校验、重新排队,也可能立即成交或被拒绝。

所以,改单最关键的不是按钮叫不叫 Cancel Replace,而是这次修改是否影响成交优先级。

但 Cancel Replace 不是撮合特权。它的价值在于减少动作缝隙,用一次动作表达“我不想保留旧参数,我想换成新参数”。新参数能不能进入订单簿、会不会立即成交、是否失去队列位置、失败后旧单如何处理,都必须由系统规则明确。

4. 队列位置:改单最敏感的隐藏成本

在价格时间优先的订单簿里,时间优先本身就是一种资产。同一个价格档里,排在前面的订单更容易成交,排在后面的订单成交概率更低。因此,改单是否保留队列位置,是非常敏感的问题。

不同交易系统对改单后的队列位置处理并不完全一致。有的系统可能允许部分不影响优先级的修改保留原队列位置,有的系统则会把修改后的订单视为重新入队。对交易者来说,更重要的是理解一条原则:只要修改影响了成交优先级、可成交数量或风险语义,就不能默认保留原队列位置。

这对做市商意味着,频繁 Cancel Replace 会带来队列成本。它能让报价更贴近最新参考价格,但也可能让订单不断回到队尾。策略要在价格新鲜度和队列优先级之间做权衡。

七、成交之后:订单状态、成交记录和盘口变化如何共同构成系统事实

撮合成功不是流程终点……

一笔成交发生后,系统要同步更新三类结果:订单本身是否完成,成交明细如何记录,仓位、费用、盘口和行情如何变化。只有这些结果都被记录下来,成交才真正成为系统事实。

撮合引擎真正生成的不是一句“成交成功”,而是一组可以被下游系统消费的事实。

在永续合约系统中,成交事实至少会拆成六类结果:订单状态、成交明细、Maker/Taker 角色、手续费和返佣、仓位与盈亏更新,以及盘口和事件流变化。

1. 订单状态:回答委托走到哪一步

订单状态回答的是:这笔委托当前处于什么生命周期阶段。

一笔订单可能已提交但尚未成交,可能部分成交后继续挂簿,可能全部成交,可能部分成交后剩余取消,也可能被用户撤销、被系统拒绝、被风控取消,或者作为触发单仍在等待触发。

这里最容易混淆的是订单状态和成交明细。

一笔订单显示为全部成交,只说明它的委托数量已经被完全执行;但它不说明具体是在哪些价格、哪些时间、和哪些对手订单成交的。

例如,用户提交一笔买入 100 张的 IOC 订单,限价为 101。它可能分三次成交:30 张成交在 100.2,40 张成交在 100.5,30 张成交在 101.0。从订单状态看,这笔订单是全部成交;但从成交记录看,它对应三条成交明细。

如果只看订单状态,用户只能知道完成了;如果要计算真实成交均价、手续费、滑点和仓位变化,就必须回到成交记录。

2. 成交记录:回答交易到底如何发生

成交记录是系统视角的交易凭证。它通常包含合约标的、买卖方向、成交价格、成交数量、成交时间、订单 ID、成交 ID、Maker/Taker 角色、手续费或返佣、是否来自清算或算法订单等字段。

成交记录不只是给用户看的历史明细,它还是后续系统计算的原始输入。仓位系统用它更新持仓和均价,保证金系统用它重算权益和风险率,费用系统用它计算手续费,行情系统用它生成成交流和 K 线,风控和做市系统则用它判断冲击、库存和异常交易。

3. Maker / Taker:不是用户身份,而是流动性角色

Maker/Taker 也不是用户身份,而是每次成交中的流动性角色。

Taker 是主动进入订单簿、消耗已有深度的一方;Maker 是原本挂在订单簿上、提供可成交深度的一方。同一个用户,在一笔成交中可能是 Taker,在另一笔成交中可能是 Maker。甚至同一个交易策略,也可能根据市场状态在 Maker 和 Taker 之间切换。

这个角色归因会直接影响费用、返佣、流动性统计和做市策略评估。

4. 费用:手续费必须绑定成交事实

费用则必须绑定成交事实。成交价格由撮合规则决定,交易费用由费率系统决定。费用通常根据用户费率等级、Maker/Taker 角色、成交名义价值、返佣机制和计价资产计算。

简化来看:

手续费 = 成交价格 × 成交数量 × 合约乘数 × 费率

如果一笔订单分多次成交,每次成交价格不同、对手方不同、Maker/Taker 归因不同,那么费用也应该按成交明细逐笔计算。交易手续费和资金费率也不能混在一起:手续费是成交发生时产生的交易成本,资金费率是多空双方之间周期性支付的持仓成本。

5. 仓位:成交事实进入账户风险系统

仓位系统也要消费成交事实。永续合约里的成交不是简单资产交换,而是仓位变化。一笔买入成交,可能是开多,也可能是平空;一笔卖出成交,可能是开空,也可能是平多。具体是哪一种,取决于用户成交前的原有仓位。

例如,用户原来持有 50 张空单,现在买入成交 80 张。从撮合视角看,这只是买入 80 张;从仓位视角看,它包含两个动作:先买入 50 张平掉原有空单,再买入 30 张形成新的多单。这会同时影响已实现盈亏、开仓均价、保证金占用和后续风险率。

6. 盘口变化:成交会改变市场状态

最后,成交还会改变市场状态。当主动订单吃掉被动订单时,订单簿上的可成交深度会减少;如果某个价格档的挂单被完全吃掉,这个价格档会从 L2 深度中消失;如果最优买价或最优卖价被吃掉,BBO 就会变化;如果主动订单继续扫过多个价格档,市场会表现为连续成交和价格跳动。

所以,撮合之后最重要的不是展示成交,而是让成交成为全系统唯一可信的事实来源。

八、行情输出与本地订单簿:看见盘口不等于拥有真实订单簿

成交事实生成之后,系统还要解决另一个问题:外部系统如何看见撮合结果?

对普通用户来说,答案似乎很简单:看 K 线、看盘口、看成交记录。但对做市商、量化交易系统、风控系统和数据索引器来说,这个问题要复杂得多。

因为它们看到的不是撮合引擎内部的真实状态,而是撮合引擎向外输出后的结果。

1. 行情输出:让外部系统看见撮合结果

行情输出真正承担的是:把撮合引擎生成的市场事实,以可消费、可订阅、可重建、可校验的方式分发给外部系统。

常见的输出包括成交流、BBO、L2 深度、订单状态事件、用户成交事件和账户更新事件。

成交流回答的是:市场刚刚在哪个价格、以多大数量发生了交易。它是 K 线、成交明细、短期波动监控和冲击成本分析的基础。

BBO,也就是 Best Bid / Best Offer,回答的是:如果现在立刻买入或卖出,市场最靠近成交的一档价格在哪里。它很轻、很快,适合做价格触发、前端展示和快速报价判断,但信息量有限。

L2 深度回答的是:每个价格档当前有多少可见深度。它适合用户观察市场厚度,也适合外部系统估算滑点,但它仍然不是订单级队列。

订单事件和用户成交事件则回答的是:我的订单发生了什么,我自己的成交发生了什么。市场成交流只能告诉你市场发生了成交,不能告诉你这是不是你的订单成交。

2. 本地订单簿:外部系统对真实订单簿的近似重建

做市商和风控系统不能每次决策都等接口查询,因此通常需要在本地维护一份订单簿。这个本地订单簿依赖初始订单簿快照、后续 L2 或订单级增量、市场成交流、自己的订单事件、自己的成交回报,以及必要时的查询校准。

它的基本逻辑是:先拿一份官方快照,作为初始状态;再不断接收增量更新,把每次深度变化应用到本地;同时结合成交流和自己的订单事件,判断本地状态是否仍然可信;如果发现断线、乱序、缺失或状态异常,就重新拉取快照。

本地订单簿看起来像同步缓存,但在交易系统里,它的风险要高得多。因为它不是展示缓存,而是决策输入。做市商会根据它报价,风控系统会根据它估算可成交深度,量化策略会根据它判断短期买卖压力。

一旦本地订单簿失真,外部系统就可能基于错误市场下单。

3. 本地簿漂移:为什么外部系统不能只相信自己看到的盘口

本地订单簿漂移,常见原因包括消息延迟、消息丢失、消息乱序、快照和增量接不上、自己的订单状态没有同步。专业系统会持续监控本地簿健康度:

本地簿可信度 ≈ 序列连续性 + 延迟可控性 + 快照一致性 + 账户事件一致性

只要其中任何一项失效,本地订单簿就应该被降级处理。

4. 做市和风控:本地簿是决策输入,但不是最终事实

对做市商来说,本地簿失真会直接变成库存风险。如果它以为某个价格档还有深度,但真实订单簿已经被打穿,就可能低估滑点;如果它以为自己的订单还在,但其实已经成交,就可能继续错误报价;如果它以为撤单成功,但撤单前订单已经成交,就可能错误计算库存。

对风控系统来说,本地簿只能作为观察视角,不能替代系统事实。本地订单簿用于预测市场承接能力,撮合成交记录用于确认实际承接结果。

5. CEX 与 DEX:实现路径不同,事实同步问题相同

CEX 和 DEX 的实现路径可以不同。CEX 中,事实来源通常是内部撮合核心;DEX 或链上订单簿系统中,事实来源可能表现为排序器、链上状态或可验证执行结果。但原则相同:撮合事实必须有唯一来源,外部行情只是对这个事实的同步和重建。

行情让外部系统看见撮合结果,本地订单簿让外部系统近似重建市场状态,但真正的成交事实仍然来自撮合引擎。

九、极端压力场景:撮合能执行规则,但不能创造流动性

真正检验撮合引擎边界的,往往不是平稳行情,而是极端压力场景。

例如,某个合约价格剧烈波动,大量账户触发保证金不足,清算方向订单集中进入订单簿,做市商开始撤单或扩大价差,买盘或卖盘变得极度单边,L2 深度看起来还在,但真实可成交深度迅速消失,外部系统的本地订单簿开始滞后、漂移甚至失真。

这时,撮合引擎会变成整个永续系统压力传导的中心。但这里必须明确一个边界:

撮合引擎可以保证订单按规则排序和成交,但不能保证市场永远有足够流动性。

很多人看到清算穿仓、价格滑点、盘口被打穿,会直觉认为是撮合系统出了问题。但更准确的说法是:撮合系统把市场流动性不足、订单流失衡和风险传导结果真实暴露了出来。

撮合引擎负责执行规则,不负责创造深度;负责生成成交事实,不负责定义公允价格;负责接收清算方向订单,不负责决定谁该被清算;负责更新盘口,不负责保证盘口一定连续。

1. 清算流:不是新撮合规则,而是特殊订单来源

清算流进入订单簿,本质上不是新规则,而是一类特殊订单来源。

永续合约中,清算通常不是撮合引擎主动发起的,而是保证金和风控系统先判断某个账户风险过高,再生成强制平仓或减仓方向的订单,让它进入撮合链路。

清算流对撮合引擎来说,仍然是一类订单流。区别在于,它不是用户主动表达交易意图,而是系统为了降低账户风险而生成的被动处置指令。

如果买盘充足,清算卖单可以较低滑点成交;如果买盘很薄,它需要连续扫掉多个买价档;如果买盘快速撤单,它可能成交不足或滑点扩大;如果订单簿无法承接,风险会继续向清算、保险基金、ADL 等下游边界传导。

清算流的本质,是把保证金系统中的账户风险,转化为订单簿中的流动性需求。而撮合引擎要回答的问题是:当前订单簿能不能承接这股流动性需求。

2. 薄盘口:可见深度不等于稳定承接

极端行情下,薄盘口是最危险的触发条件之一。薄盘口不只是订单簿上挂单数量少,更准确地说,是当前可成交深度不足以承接即将进入市场的主动订单流。

L2 展示的是当下可见深度,不是未来一定可成交深度。挂单可以被撤掉,做市商可以扩大价差,同一价格档内部的排队结构外部看不见,大订单扫簿时后续价格档可能远比前几档稀疏。

所以,极端行情下最常见的现象不是订单簿突然归零,而是深度一边被吃,一边被撤。看起来是成交在推动价格,实际上是成交和撤单共同造成盘口塌缩。

可以用一个简化公式理解:

滑点压力 ≈ 主动订单规模 ÷ 可稳定承接深度

这里的主动订单规模包括普通用户追涨杀跌订单、止损触发订单、清算方向订单和算法子单;可稳定承接深度不是 L2 上看到的全部挂单,而是压力发生时仍然愿意留在簿上的有效深度。

当主动订单规模上升,而可稳定承接深度下降时,滑点会非线性放大。

3. 单边订单:主动流会把价格一档一档推穿

单边订单也会把价格一档一档推穿。市场快速下跌时,普通用户主动止损、触发单转为卖出、多头清算单继续卖出、做市商降低买盘报价、买方挂单被不断吃掉。撮合引擎会按照规则持续执行:卖单先打买一,买一数量不足再打买二,买二不足再打买三,直到订单完成、剩余取消,或触达价格限制和风控边界。

在这个过程中,价格不是被撮合引擎调低的,而是被主动卖单一档一档打下去的。

这也解释了为什么永续合约中的成交价格和标记价格必须分开。成交价格反映订单簿中真实发生的交易;标记价格用于风险计算和保证金判断,通常需要更稳健,不能被单一订单簿的短期扫簿完全绑架。

4. 撤单风暴:流动性不是被吃完,而是主动离场

撤单风暴则说明,流动性不一定是被成交吃完,也可能是主动离开订单簿。做市商在外部价格快速变化、本地盘口延迟、库存风险升高、成交价和标记价异常偏离、系统延迟上升时,可能集中撤单。从市场整体看,大量撤单会导致订单簿表面上还有价格,但每个价格档上的承接能力迅速下降。

撮合引擎在这里暴露的边界非常清楚:它能删除被撤销的订单,能更新订单簿深度,能把撤单事件输出给外部系统,但它不能强迫流动性继续留在簿上。

5. 本地簿失真:压力越大,外部视图越容易过期

极端行情下,本地订单簿也最容易失真。市场变化速度太快,事件量太大,外部系统可能同时遇到推送延迟、增量处理不过来、订单事件和成交事件到达顺序不一致、本地订单簿短暂交叉、官方快照和本地增量无法对齐等问题。

此时,专业系统不会只问行情有没有推送,而会问:本地订单簿现在还能不能用于决策。一旦不能用于决策,就应该进入降级状态,例如停止新增订单、扩大价差、撤掉非必要挂单、重新拉取快照、等待订单状态和成交记录校准完成。

6. 极端行情下,撮合系统必须坚持什么

极端压力下,撮合引擎必须坚持几个底层原则:顺序必须确定,规则必须一致,状态必须可追溯,事件必须可校验,边界必须清楚。

它不能消灭极端行情,但必须保证市场最混乱的时候,订单仍然按确定性规则处理,真实发生的成交、撤单、拒绝、盘口变化和事件状态仍然能够被记录、解释和复盘。

最后:撮合引擎不是风险兜底器,而是市场秩序的事实层

到这里,我们可以重新理解撮合引擎的位置。

它不是保险基金,不是 ADL,不是做市商,也不是定价引擎。它不能保证市场不失衡,不能保证每笔订单都低滑点成交,也不能凭空创造流动性。

它真正负责的,是在大量交易意图同时进入订单簿时,把订单流整理成有顺序、有记录、可复核的市场事实。

前置门禁决定订单能不能进场,订单簿决定订单如何排队,价格时间优先决定谁先成交,订单类型锁定执行语义,撤单和改单持续改变可成交深度。成交之后,成交记录成为系统事实,行情输出和本地订单簿让外部系统看见并重建这些事实。

如果第一篇《综述》讨论的是永续合约系统的整体秩序,第二篇《定价引擎》讨论的是系统如何定义价格使用权,那么这一篇关于撮合引擎的核心可以概括为一句话:

定价引擎定义系统相信什么价格,撮合引擎定义市场发生过什么交易。

它不定义价格真相,但生成成交事实;它不承担最终兜底,但承接风险进入市场的第一层压力;它不保证流动性永远存在,但必须保证订单流在失衡中仍然可排序、可解释、可追溯。

本文由 @Terry的思考笔记 原创发布于人人都是产品经理。未经作者许可,禁止转载

题图来自Unsplash,基于CC0协议

更多精彩内容,请关注人人都是产品经理微信公众号或下载App
评论
评论请登录
  1. 撮合引擎的核心不是匹配订单,而是把不同来源的交易意图转化成全系统公认的市场事实。先通过五道门禁过滤无效风险,再在L4队列里按价格时间优先逐笔撮合,主动单扫簿消耗深度,被动单决定成交价。整个设计都在强调一件事:撮合的确定性比成交本身更关键,因为后续的仓位、清算、风控都依赖这份事实。

    来自广东 回复