4、订单路由基础:路由的概念、路由节点、路由路径、路由决策因子(价格、时间、成本)
订单路由,说白了就是你的订单该走哪条路去交易所。我刚开始接触暗池时,觉得这玩意儿不就是把单子扔过去嘛,有什么好研究的?后来被市场狠狠教育了一顿,才明白路由才是整个交易系统的命门。
你想想看,一个订单从你的交易终端出发,到最终成交,中间要经过多少道关卡?每个关卡怎么走,走哪条路,什么时候走,这些决策直接决定了你的成交质量。嗯,今天我们就来拆解一下这个基础但极其重要的环节。
路由的概念:不只是“发单”那么简单
路由,本质上是一个决策过程。它决定了你的订单应该被发送到哪个交易场所(交易所、暗池、ATS等),以及通过什么路径到达那里。
我习惯把路由比作导航。你输入目的地(交易标的),导航系统(路由引擎)会根据实时路况(市场状态)、你的偏好(成本、速度、隐蔽性)来规划最佳路线。不同的是,交易路由的决策时间窗口是以毫秒甚至微秒计算的。
核心要点:路由不是简单的“发单”,而是“在正确的时间,把正确的订单,送到正确的地方”。
我在项目中遇到过最典型的反例:有人把路由写成了一个固定的IP地址列表,轮询发送。结果某个交易所宕机了,订单还在往那里发,白白浪费了成交机会。这就是没理解路由的动态性。
路由节点:订单旅程中的驿站
一个订单从诞生到成交,会经过若干个节点。每个节点都可能影响订单的命运。
| 节点类型 | 作用 | 延迟影响 |
|---|---|---|
| 客户端节点 | 订单生成、本地校验 | 低(本地处理) |
| 路由引擎节点 | 决策目的地、路径选择 | 中(计算+网络) |
| 网关节点 | 协议转换、连接管理 | 中(协议解析) |
| 交易所节点 | 订单匹配、成交 | 高(排队+撮合) |
| 暗池节点 | 隐蔽匹配、大单处理 | 中(匹配逻辑) |
每个节点都有自己的“脾气”。比如网关节点,如果连接池配置不当,高峰期会直接拒绝新连接。我曾经因为没注意网关的并发限制,导致一批大单被拒,那叫一个惨。
路由路径:条条大路通罗马,但有的路是死胡同
路由路径就是订单从起点到终点的具体路线。常见的路径模式有几种:
- 直连路径:客户端直接连交易所。延迟最低,但灵活性差。
- 代理路径:通过中间节点转发。可以聚合流量、做协议转换,但多一跳就多一份延迟。
- 智能路径:根据实时条件动态选择。这是暗池路由的核心。
我建议在设计路径时,一定要考虑冗余。别只依赖一条路。我记得有一次,某交易所的专线光纤被施工队挖断了,幸好我们预留了公网备用路径,虽然慢了点,但至少没断单。
实战技巧:路径选择时,可以给每条路径打一个“健康分”。延迟、丢包率、历史成交率都可以作为评分因子。低于阈值的路径自动降权。
路由决策因子:价格、时间、成本
这是路由决策的三大支柱。说白了,就是你要在“成交价格”、“成交速度”和“交易成本”之间做权衡。
价格因子
价格因子不是指订单本身的报价,而是目标场所的预期成交价格。比如,A交易所的买一价是10.00,B暗池的买一价是10.01,那显然B暗池对卖方更友好。
但要注意,价格因子不能只看当前盘口。我习惯用预期滑点来评估。比如你的订单是100万股,A交易所盘口只有5万股,那你的大单进去肯定会把价格打穿。这时候暗池可能反而能给你更好的均价。
// 伪代码:价格因子评估
function evaluatePriceFactor(venue, orderSize) {
let currentPrice = venue.getBestBid();
let depth = venue.getOrderBookDepth();
let expectedSlippage = calculateSlippage(orderSize, depth);
let effectivePrice = currentPrice - expectedSlippage; // 卖方视角
return effectivePrice;
}
时间因子
时间因子,说白了就是成交概率和速度。有些场所流动性好,订单进去秒成交;有些场所虽然价格好,但半天没人接盘。
我建议把时间因子拆成两个维度:
- 预期等待时间:订单进入后,预计多久能成交。
- 成交概率:在给定时间内,订单成交的可能性。
举个例子,暗池的成交概率通常低于交易所,但一旦成交,价格冲击小。如果你的订单对时间敏感(比如套利单),那交易所可能是更好的选择。
避坑指南:我曾经为了追求低延迟,把所有订单都往同一个低延迟交易所发。结果那个交易所的流动性其实很差,订单挂在那里半天不成交,反而错过了其他场所的机会。时间因子不能只看延迟,还要看流动性。
成本因子
成本因子包括显性成本和隐性成本:
- 显性成本:手续费、交易所费用、清算费、数据费。
- 隐性成本:市场冲击、信息泄露风险、机会成本。
我习惯把成本因子做成一个综合成本模型。比如:
综合成本 = 手续费 + 预期滑点 + 信息泄露风险溢价
信息泄露风险溢价怎么算?嗯,这个比较主观。我一般根据订单规模和场所的透明度来估算。暗池的信息泄露风险低,所以溢价可以设为负值(即成本优势)。
决策因子的动态权重
这三个因子不是固定权重的。市场环境变了,权重也得变。
比如:
- 市场剧烈波动时,时间因子的权重应该提高。因为价格变化快,晚一秒可能就亏大了。
- 大单交易时,成本因子(尤其是市场冲击)的权重应该提高。这时候暗池可能比交易所更合适。
- 套利交易时,价格因子和时间因子并重,成本因子可以适当放宽。
我建议把权重做成可配置的,甚至可以根据历史数据自动调整。说白了,就是让系统自己学会在什么情况下该看重什么。
路由决策的完整流程
好了,我们把上面这些串起来,看看一个完整的路由决策流程是什么样的。
这个流程看起来简单,但每个环节都有坑。比如因子评估阶段,如果数据源延迟太高,你评估出来的价格可能已经是过时的了。我建议在评估前先做一次数据新鲜度检查。
实战中的路由策略示例
最后,我分享一个我在项目中用过的简单路由策略。它不复杂,但很实用。
class SimpleRouter {
constructor(venues) {
this.venues = venues; // 所有可用的交易场所
this.weights = {
price: 0.4,
time: 0.3,
cost: 0.3
};
}
route(order) {
let bestScore = -Infinity;
let bestVenue = null;
for (let venue of this.venues) {
let priceScore = this.evaluatePrice(venue, order);
let timeScore = this.evaluateTime(venue, order);
let costScore = this.evaluateCost(venue, order);
let totalScore =
this.weights.price * priceScore +
this.weights.time * timeScore +
this.weights.cost * costScore;
if (totalScore > bestScore) {
bestScore = totalScore;
bestVenue = venue;
}
}
return bestVenue;
}
evaluatePrice(venue, order) {
// 计算预期成交价格 vs 当前市场价格
let expectedPrice = venue.getExpectedFillPrice(order);
let marketPrice = this.getMarketPrice(order.symbol);
return (marketPrice - expectedPrice) / marketPrice; // 越高越好
}
evaluateTime(venue, order) {
// 基于历史数据估算成交时间
let avgFillTime = venue.getAverageFillTime(order.size);
return 1.0 / (1.0 + avgFillTime); // 时间越短分数越高
}
evaluateCost(venue, order) {
// 综合成本评估
let fee = venue.getFee(order);
let impact = venue.estimateMarketImpact(order);
let totalCost = fee + impact;
return 1.0 / (1.0 + totalCost);
}
}
这个策略虽然简单,但已经能处理大部分常规场景了。实际生产环境中,你还需要加入熔断机制、异常处理、动态权重调整等。嗯,这些我们后面会慢慢展开。
我的建议:刚开始做路由系统时,别追求完美。先跑通一个简单的版本,然后根据实际成交数据不断优化。纸上谈兵永远比不上实战数据来得真实。
好了,路由基础就讲到这里。记住,路由不是一成不变的,它需要根据市场的变化不断调整。你想想看,如果市场都变了,你的路由策略还停留在原地,那跟闭着眼睛开车有什么区别?
公众号:蓝海资料掘金营,微信deep3321