3. 订单生命周期:订单状态机
做量化交易这些年,我见过太多人把订单系统想得太简单。
他们觉得,下单嘛,不就是发个指令过去,成交了就完事?
嗯,如果你只是拿模拟盘玩玩,确实可以这么理解。但真到了实盘环境,尤其是高频场景下,一个订单从诞生到消亡,中间的状态转换比你想象的要复杂得多。
我个人习惯把订单的生命周期看作一个状态机。说白了,就是一张状态流转图。每个订单在交易所内部,都会经历一系列确定的状态变化。搞懂这个,你才能知道你的钱到底处在什么阶段。
3.1 订单状态机:核心五态
一个标准的订单状态机,通常包含以下五个核心状态。我把它画成了流程图,你一看就明白。
你看,订单从「新单」出发,只有三条路可以走:
- 被拒绝:交易所校验没通过,直接打回。
- 被撤单:你主动取消,或者系统超时自动撤单。
- 进入撮合:这是最理想的情况,开始匹配对手盘。
一旦进入撮合,就会在「部分成交」和「完全成交」之间流转。注意,「部分成交」不是终态,它还可以继续成交,直到完全成交,或者被你手动撤掉。
3.2 各状态详解
3.2.1 新单 (New)
订单刚提交到交易所,还没进入撮合队列。这时候,交易所会做一系列校验:
- 合法性校验:股票代码是否存在?交易时间对不对?
- 资金/持仓校验:你账户里钱够不够?券够不够?
- 价格校验:是不是超过了涨跌停板?是不是不符合最小变动价位?
- 风控校验:自成交检查、频繁报撤单检查等。
全部通过,订单才会变成「新单」,进入撮合队列。否则,直接变成「拒绝」。
3.2.2 部分成交 (Partially Filled)
这是最磨人的状态。你下了1000手,结果只成交了300手,剩下700手还在队列里挂着。
为什么会这样?说白了,就是你的报价和对手盘的价格有重叠,但对手盘不够多,没法一口气吃完你的单子。
我记得有一次做ETF套利,下了个大单,结果在「部分成交」状态卡了将近2秒。那2秒里,我盯着盘口,心跳都加速了。后来我学乖了,对于大单,我会拆成小单,或者用冰山指令(Iceberg Order),避免暴露真实意图。
3.2.3 完全成交 (Filled)
这是所有交易员的终极目标。订单全部成交,状态进入终态。这时候,你的仓位和资金会立即更新。
注意,完全成交后,交易所会给你发一个成交回报(Execution Report),里面包含了成交价格、成交量、成交时间等关键信息。你的交易系统必须准确解析这个回报,并更新本地状态。
3.2.4 撤单 (Canceled)
主动撤单,或者被动撤单(比如交易所收盘后自动撤销未成交的订单)。
撤单也有风险。我曾经遇到过一种情况:我发了一个撤单指令,但交易所还没来得及处理,订单就已经成交了。结果我收到了一个「撤单失败」的回报,同时还有一个「成交回报」。这时候,你的系统必须能正确处理这种冲突,不能把已经成交的单子当成撤单处理。
3.2.5 拒绝 (Rejected)
订单被交易所打回。原因可能是资金不足、价格违规、风控限制等。
拒绝是终态,订单不会再进入撮合。你需要根据拒绝原因,修改订单参数后重新提交。
3.3 订单路由
如果你只在一个交易所交易,订单路由其实很简单——直接发给那个交易所就行。
但如果你做的是跨市场套利,或者使用智能路由系统,事情就复杂了。
订单路由,说白了就是:你的订单应该发给哪个交易所?
举个例子,你想买1000手某只股票,这只股票同时在A交易所和B交易所上市。A交易所流动性好,但手续费高;B交易所流动性差,但手续费低。你的路由系统需要根据实时数据,决定把订单发给谁。
常见的路由策略有:
- 价格优先:哪个交易所的卖价最低,就发给谁。
- 流动性优先:哪个交易所的盘口深度最好,就发给谁。
- 成本优先:哪个交易所的总成本(手续费+滑点)最低,就发给谁。
- 智能路由:综合多个因素,动态决策。
我个人习惯用智能路由。我会给每个交易所打一个「综合评分」,评分维度包括:
| 维度 | 权重 | 说明 |
|---|---|---|
| 盘口价差 | 40% | 买卖价差越小,评分越高 |
| 盘口深度 | 30% | 前5档挂单总量越大,评分越高 |
| 历史成交率 | 20% | 过去1分钟该交易所的订单成交比例 |
| 网络延迟 | 10% | 到该交易所的RTT延迟,越低越好 |
然后,根据综合评分,把订单路由到评分最高的交易所。如果评分最高的交易所突然出现异常(比如网络中断),系统会自动切换到第二优的交易所。
嗯,订单生命周期这块,核心就是状态机和路由。搞懂了这两个,你就能清楚地知道,你的每一笔订单,到底经历了什么。
公众号:蓝海资料掘金营,微信deep3321