第三章 订单路由层设计:智能路由算法
订单路由层,说白了就是你的交易系统里那个「派单员」。
我当年刚接触多品种交易系统时,觉得路由不就是把单子发出去吗?后来被现实狠狠教育了一顿。你想想看,一个订单发到交易所A,结果那边流动性不够,单子被拆得七零八落;或者发到交易所B,价格倒是好,但延迟高得离谱。嗯,这时候你就知道路由层有多重要了。
3.1 智能路由的核心算法
智能路由不是简单的「谁便宜找谁」。我个人习惯把它拆成三个维度:价格、时间、流动性。这三个维度缺一不可。
3.1.1 价格优先
价格优先是最基础的逻辑。说白了,哪个交易所的报价最优,就往哪发。
但这里有个坑——我曾经在实盘里遇到过,某个交易所的报价看起来便宜了0.1个tick,结果成交后发现滑点反而更大。为什么?因为那个报价是「影子报价」,根本吃不到量。
3.1.2 时间优先
时间优先,很多人理解成「谁先到谁先成交」。其实在路由层,时间优先指的是「路由决策的时效性」。
举个例子:你同时监控三个交易所的订单簿。交易所A的买一价是100.00,交易所B是100.01。如果你花200毫秒做路由决策,等单子发出去,价格可能已经变了。
我自己的做法是:给每个路由决策设定一个「时间预算」。比如50毫秒内必须做出决定,超时就走默认路由。这个默认路由,我建议选流动性最好的那个交易所。
3.1.3 流动性优先
流动性优先,这个是我最看重的。为什么?因为价格再好,吃不到量等于白搭。
我在项目中遇到过这样的情况:某个小交易所的报价比主流交易所便宜了0.2%,但它的订单簿深度只有100手。你一个500手的单子过去,直接就把价格打穿了。最后成交均价反而比主流交易所还贵。
3.2 订单拆分与聚合
订单拆分和聚合,是路由层的「手术刀」。拆得好,能降低冲击成本;拆不好,反而增加延迟。
3.2.1 订单拆分策略
我常用的拆分策略有三种:
- 按时间拆分: 把一个大单拆成多个小单,每隔一段时间发一个。适合流动性一般的品种。
- 按价格区间拆分: 根据订单簿的深度,把单子分配到不同的价格层级。适合流动性好的品种。
- 按交易所拆分: 把单子分到多个交易所,利用各所的流动性优势。适合跨所套利。
举个例子,一个1000手的买单:
// 伪代码示例
function splitOrder(order, orderBook) {
let splits = [];
let remaining = order.quantity; // 1000手
// 按价格区间拆分
for (let level of orderBook.levels) {
let take = Math.min(remaining, level.depth);
splits.push({
price: level.price,
quantity: take,
exchange: level.exchange
});
remaining -= take;
if (remaining <= 0) break;
}
return splits;
}
这个代码看起来简单,但实际要考虑的东西很多。比如每个交易所的最小交易单位、手续费结构、甚至交易所的故障率。我曾经因为没考虑交易所的故障率,把单子全部分到了同一个交易所,结果那个交易所宕机了...嗯,从那以后我就在拆分逻辑里加了一个「交易所健康度」的权重。
3.2.2 订单聚合策略
聚合和拆分是反过来的。当你有多个小单要发往同一个交易所时,把它们合并成一个单子发出去,能节省网络开销和手续费。
我建议的聚合规则:
- 相同方向(买/卖)的订单可以聚合
- 价格差异在0.1%以内的可以聚合
- 时间窗口在100毫秒内的可以聚合
3.3 路由表动态更新
路由表不是写死的。市场在变,交易所的状态在变,你的路由表也得跟着变。
3.3.1 路由表的结构
我习惯用一张表来管理路由信息:
| 交易所 | 价格权重 | 时间权重 | 流动性权重 | 健康度 | 延迟(ms) |
|---|---|---|---|---|---|
| 交易所A | 0.4 | 0.3 | 0.3 | 0.95 | 10 |
| 交易所B | 0.3 | 0.4 | 0.3 | 0.88 | 15 |
| 交易所C | 0.2 | 0.3 | 0.5 | 0.92 | 12 |
这张表里的权重不是固定的。我建议每5分钟重新计算一次,根据最近的市场表现动态调整。
3.3.2 动态更新的触发条件
路由表什么时候更新?我总结了三个触发条件:
- 定时更新: 每5分钟全量更新一次。这是兜底策略。
- 事件触发: 某个交易所的延迟突然飙升,或者健康度下降,立即更新。
- 异常回退: 如果某个交易所连续3次路由失败,自动降低它的权重,甚至暂时剔除。
这里有个细节——更新路由表的时候,不能中断正在进行的路由决策。我自己的做法是用「双缓冲」:一个活跃表,一个备用表。更新时先写备用表,更新完再切换。
3.3.3 路由表的可视化
为了让你更直观地理解路由层的整体逻辑,我画了一张流程图:
这张图展示了路由层的完整流程。注意那个反馈回路——路由决策的结果会反过来影响路由表的更新。这是一个闭环系统。
3.4 实战中的避坑指南
最后,分享几个我在实战中踩过的坑:
- 不要迷信「最优路由」: 我曾经花了很多精力去追求「理论上的最优路由」,结果发现市场变化太快,等你算出来最优方案,行情已经变了。后来我改用「足够好」策略——只要路由结果在可接受范围内,就立即执行。
- 注意交易所的「隐藏规则」: 有些交易所对高频交易有额外的限制,比如每秒最多发多少单。我建议在路由表里加上每个交易所的「限流参数」。
- 做好降级处理: 如果所有交易所都不可用,怎么办?我自己的做法是准备一个「备用路由表」,里面只有流动性最好的那个交易所。虽然可能不是最优,但至少能保证交易不中断。
嗯,这一章的内容就到这里。路由层设计好了,你的交易系统就成功了一半。剩下的,就是不断根据市场反馈去调优了。
公众号:蓝海资料掘金营,微信deep3321