一、订单类型:撮合引擎的“积木块”

做量化交易这些年,我接触过形形色色的订单类型。说白了,订单就是交易员发给市场的“指令”。你告诉系统:我想怎么买、怎么卖。不同的订单类型,对应着不同的交易策略和风险偏好。

我个人习惯把订单类型分成两大类:基础订单高级订单。基础订单是限价单和市价单,高级订单则是冰山订单、止损单这些“变形金刚”。

1.1 限价单(Limit Order)—— 最老实的订单

限价单,顾名思义,就是“限定价格”的订单。你告诉系统:我只愿意在某个价格或更好的价格成交。比如你想买比特币,当前市场价是 50000 USDT,但你只想在 49000 买。那你就挂一个限价买单,价格填 49000。

限价单有两个核心特点:

  • 价格可控:你说了算,市场波动再大,也不会以更差的价格成交。
  • 成交不确定:价格没到你的限价,订单就一直挂着,可能永远成交不了。

我在项目中遇到过一个问题:有人挂了一个超低价的限价买单,结果市场突然暴跌,瞬间成交了。他本来想捡便宜,结果接住了飞刀。嗯,这里要注意:限价单不是“保险单”,它只是控制价格上限或下限。

核心要点:限价单是撮合引擎的“基石”。大部分订单簿的深度,都是由限价单构成的。

1.2 市价单(Market Order)—— 最急切的订单

市价单就一个字:快。你不管价格是多少,只要立即成交就行。系统会以当前市场上最好的价格帮你吃掉对手盘。

市价单的特点:

  • 成交确定:只要市场上有对手盘,100% 成交。
  • 价格不确定:如果市场流动性差,你可能吃到很差的价位。

举个例子:你想买 100 个 ETH,但卖一价只有 10 个 ETH。市价单会先吃掉卖一的 10 个,然后继续吃卖二的、卖三的……直到买够 100 个。最终成交均价可能比你预期的贵不少。

避坑指南:我曾经见过一个新手,在流动性极差的币种上用了市价单,结果成交价滑了 5%。所以,大额交易慎用市价单。

1.3 冰山订单(Iceberg Order)—— 隐藏实力的订单

冰山订单,说白了就是“大单拆小单”。你明明想买 10000 个 BTC,但不想让市场知道你的真实意图。于是你只暴露一小部分,比如 100 个,剩下的 9900 个藏在“水下”。

冰山订单的参数:

  • 总数量:你真正想交易的数量。
  • 显示数量:每次暴露在订单簿上的数量。
  • 价格:限价价格。

系统会这样工作:先挂出 100 个限价单,成交后,再自动挂出新的 100 个,直到总数量全部成交。

我的经验:冰山订单在暗池交易中特别有用。因为暗池本身就是隐藏流动性的地方,冰山订单可以进一步降低市场冲击。

1.4 止损单(Stop Order)—— 带“保险丝”的订单

止损单,也叫“触发单”。它平时不干活,像个哨兵一样盯着市场价格。一旦市场价格触及你设定的“触发价”,止损单就变成市价单或限价单,立即执行。

止损单有两种常见变体:

  • 市价止损单:触发后变成市价单,保证成交,价格不确定。
  • 限价止损单:触发后变成限价单,价格可控,但可能成交不了。

为什么会这样?因为止损单的本质是“条件单”。条件满足前,它只是一个待命的指令;条件满足后,它才真正进入撮合流程。

注意:止损单不是“止损神器”。在极端行情下,市价止损单可能滑点严重,限价止损单可能无法成交。我见过有人设了止损,结果价格直接跳过触发价,止损单根本没激活。

二、订单状态机:从生到死的完整旅程

每个订单,从进入系统到最终离开,都会经历一系列状态变化。这就是订单状态机。我个人习惯把它想象成一个“流水线”:订单进来,经过几个工位,最后出去。

下面这张图,是我自己画的订单状态机流程图,你看一眼就明白了:

New Accepted Partial Filled Cancelled 校验通过 部分成交 全部成交 用户撤单 继续成交 剩余全成交 撤单 图例: New Accepted Partial Filled Cancelled

2.1 New(新订单)—— 出生

订单刚进入系统时,状态就是 New。这时候系统还没做任何处理,只是收到了你的指令。我习惯把 New 状态叫做“待检区”。

在 New 状态,系统会做几件事:

  • 校验订单参数(价格、数量、类型是否合法)
  • 检查账户余额或持仓是否足够
  • 分配一个唯一的订单 ID

如果校验失败,订单会直接进入 Rejected 状态(有些系统把 Rejected 归为 Cancelled 的一种)。

2.2 Accepted(已接受)—— 进入撮合队列

校验通过后,订单进入 Accepted 状态。这时候,订单已经进入订单簿,开始等待撮合。

Accepted 状态是订单的“活跃期”。它会一直待在订单簿里,直到发生以下三件事之一:

  • 被对手盘吃掉(全部成交 → Filled)
  • 被对手盘吃掉一部分(部分成交 → Partial)
  • 被用户撤销(Cancelled)
小技巧:在 Accepted 状态,系统可以做一些“预检查”。比如,如果订单簿上已经有可匹配的对手盘,可以直接尝试撮合,不需要等到下一轮。

2.3 Partial(部分成交)—— 吃了一半

Partial 状态,说白了就是“没吃完”。比如你挂了 100 个限价单,结果只成交了 30 个,剩下的 70 个还在订单簿上。这时候订单状态就是 Partial。

Partial 状态是 Accepted 的“子状态”。它本质上还是活跃的,只是已经有一部分成交了。系统会记录:

  • 已成交数量
  • 剩余数量
  • 成交均价

从 Partial 状态出发,订单可以走向:

  • Filled:剩余部分全部成交
  • Cancelled:用户撤销剩余部分
  • Partial 继续:又成交了一部分,但还没完

2.4 Filled(全部成交)—— 寿终正寝

Filled 是订单的“完美结局”。所有数量都成交了,订单生命周期结束。

Filled 状态意味着:

  • 订单从订单簿中移除
  • 生成成交记录(Trade)
  • 更新账户余额和持仓

嗯,这里要注意:Filled 状态是不可逆的。一旦进入 Filled,订单就彻底结束了,不能再做任何操作。

2.5 Cancelled(已撤销)—— 主动退出

Cancelled 状态,就是用户主动撤单。可能是用户改变了主意,也可能是系统触发了某些风控规则(比如价格超过涨跌幅限制)。

Cancelled 状态的特点:

  • 只有未成交的部分才能撤销
  • 已成交的部分不受影响
  • 撤销后,订单从订单簿中移除
避坑指南:我曾经遇到过一个 bug:用户撤单时,系统没有正确处理并发。结果订单在撤单的同时,又被撮合引擎匹配了。最后用户既撤了单,又成交了。所以,撤单操作一定要加锁,或者用乐观锁处理。

三、订单生命周期:一个完整的例子

光讲理论太枯燥。我举个例子,你跟着走一遍就明白了。

假设你挂了一个限价买单:

  • 价格:100 USDT
  • 数量:50 个 ETH

步骤 1:New
订单进入系统,状态为 New。系统校验:价格合法、数量合法、账户余额足够。校验通过。

步骤 2:Accepted
订单进入订单簿,状态变为 Accepted。系统开始寻找对手盘。当前卖一价是 101 USDT,比你的限价高,所以没有立即成交。

步骤 3:Partial
过了一会儿,市场价格跌到 100 USDT。卖一价变成了 100 USDT,有 20 个 ETH 在卖。你的订单立即吃掉这 20 个。状态变为 Partial,已成交 20,剩余 30。

步骤 4:Partial 继续
又过了几分钟,又有 10 个 ETH 以 100 USDT 卖出。你的订单再吃掉 10 个。状态还是 Partial,已成交 30,剩余 20。

步骤 5:Filled
最后,剩下的 20 个 ETH 也被吃掉了。状态变为 Filled。订单生命周期结束。

如果在这个过程中,你突然不想买了,可以随时撤销剩余部分。撤销后,状态变为 Cancelled,已成交的 30 个 ETH 不受影响。

总结一下:订单状态机是撮合引擎的“骨架”。每个订单从 New 开始,经过 Accepted,最终走向 Filled 或 Cancelled。Partial 是中间状态,表示“还没完”。

我个人习惯在代码里用枚举来表示这些状态:

enum OrderStatus {
    NEW,
    ACCEPTED,
    PARTIAL,
    FILLED,
    CANCELLED,
    REJECTED  // 有些系统会单独定义
};

状态转换的规则,我建议用状态机表来管理,清晰又不容易出错:

当前状态 触发事件 下一状态
New 校验通过 Accepted
New 校验失败 Rejected
Accepted 全部成交 Filled
Accepted 部分成交 Partial
Accepted 用户撤单 Cancelled
Partial 剩余全部成交 Filled
Partial 继续部分成交 Partial
Partial 用户撤单 Cancelled

好了,订单类型和生命周期就讲到这里。这些是撮合引擎最基础的知识,但也是最核心的。你想想看,无论多复杂的交易策略,最终都要落地到这些订单类型和状态转换上。

专注资料整理