订单生命周期:订单创建、路由、成交、撤销、过期处理
订单的生命周期,说白了就是一笔订单从“想法”到“结束”的全过程。我做了这么多年量化系统,见过太多人只关心策略信号,却忽略了订单本身的状态机。嗯,这里要敲黑板——订单生命周期管理,是交易系统稳定性的基石。
你想想看,一个订单从客户端发出,到最终被交易所确认,中间要经历多少个环节?每个环节都可能出问题。我个人习惯是把订单生命周期拆成五个核心阶段:创建、路由、成交、撤销、过期。下面我一个一个说。
1. 订单创建:一切从这里开始
订单创建,就是系统根据策略信号生成一个标准化的订单对象。我在项目中遇到过一个问题:策略端和交易端对订单字段的定义不一致,导致订单创建后直接被风控拦截。后来我强制要求所有订单必须经过一个统一的“订单工厂”来创建。
一个标准的订单对象,至少包含以下字段:
| 字段 | 说明 | 示例 |
|---|---|---|
| 订单ID | 全局唯一标识 | ORD-20231027-001 |
| 交易对 | 买卖标的 | BTC/USDT |
| 方向 | 买/卖 | BUY |
| 类型 | 限价/市价 | LIMIT |
| 价格 | 限价单的指定价格 | 35000.00 |
| 数量 | 委托数量 | 0.5 |
| 时间戳 | 创建时间(纳秒级) | 1698384000000000 |
2. 订单路由:找到最快的路
订单创建好了,接下来要把它送到交易所。但问题来了——如果你对接了多个交易所,或者同一个交易所的不同节点,该往哪送?
订单路由的核心逻辑就两点:
- 选所:根据流动性、手续费、延迟等因素,选择最优的交易所
- 选路:同一个交易所可能有多个接入点,选延迟最低的那个
我曾经踩过一个坑:某个交易所的API网关做了限流,我所有的订单都走同一个连接,结果高峰期被限流了。后来我改成了多连接池+健康检查,每个连接独立计数,超过阈值自动切换。
3. 订单成交:最激动人心的时刻
订单送到交易所后,就进入了撮合队列。成交有两种情况:
- 完全成交:订单全部被撮合,状态变为FILLED
- 部分成交:只成交了一部分,状态变为PARTIALLY_FILLED
这里有个容易被忽略的点:成交回报的顺序。交易所返回的成交回报,不一定和订单发送的顺序一致。我见过一个系统,因为没处理好成交回报的乱序问题,导致持仓计算错误。
我的做法是:在订单对象里维护一个“已成交数量”字段,每次收到成交回报就累加。同时记录一个“成交序列号”,用来判断是否漏掉了某笔成交。
// 伪代码:成交回报处理
class Order {
long orderId;
long filledQty; // 已成交数量
long lastSeqNum; // 上次处理的成交序号
void onFill(FillReport fill) {
if (fill.seqNum <= this.lastSeqNum) {
// 重复回报,直接丢弃
return;
}
this.filledQty += fill.qty;
this.lastSeqNum = fill.seqNum;
if (this.filledQty >= this.totalQty) {
this.status = OrderStatus.FILLED;
} else {
this.status = OrderStatus.PARTIALLY_FILLED;
}
}
}
4. 订单撤销:想撤就撤?没那么简单
撤销操作,看起来简单,其实坑很多。你发一个撤销指令,交易所不一定能成功撤销。比如:
- 订单已经成交了,撤销会失败
- 订单正在撮合中,撤销可能被延迟
- 网络超时,你不知道撤销到底成功了没有
我个人习惯的撤销流程:
- 发送撤销指令
- 等待交易所确认(超时时间设为500ms)
- 如果超时,立即查询订单状态
- 根据状态决定是否重试撤销
- 最多重试3次,超过则标记为“撤销待确认”
5. 过期处理:没人管的订单怎么办
有些订单设置了有效期,比如“当天有效”或“30秒有效”。过期后,系统需要自动处理。这里有两种策略:
| 策略 | 做法 | 适用场景 |
|---|---|---|
| 主动撤销 | 过期后立即发送撤销指令 | 高频交易,对时效性要求高 |
| 被动等待 | 过期后不操作,等交易所自动撤销 | 低频交易,减少网络开销 |
我建议用主动撤销。为什么?因为交易所的自动撤销机制不一定可靠。我遇到过某个交易所,订单过期后过了10秒才自动撤销,这期间价格已经变了,差点造成损失。
核心逻辑流程图
下面这张图,展示了订单从创建到结束的完整状态流转。我画这张图的时候,特意把“异常路径”也标出来了——因为实际生产中,异常路径才是你真正需要关注的。
从图上你能看到,订单的生命周期其实是一个有向图,不是简单的线性流程。每个状态之间都有多条路径。比如“待成交”状态,可以走向“部分成交”、“已撤销”或“已过期”。而“部分成交”之后,还可能回到“待成交”继续撮合。
嗯,这就是订单生命周期的全部内容。说白了,就是管理好订单的每一个状态转换,确保不丢单、不重复、不错乱。我在实战中吃过不少亏,希望你能从我的经验里少走些弯路。