halo 的技术博客

返回

你以为的「买入 20 万股」不是一笔交易,而是一道执行题。如果把 20 万股一次性砸进一个场所,你的单子会瞬间吃掉好几层限价簿,把价格一路推高——你买得越多,成交价越差,这个「越买越贵、越卖越便宜」的代价就是市场冲击(market impact)。更麻烦的是,今天的市场是碎片化的:同一只股票在十几个场所挂牌,有的流动性深、有的价差窄、有的费用贵。把全部量灌进一个场所,等于放弃了对流动性的全局寻优。

本文聊智能订单路由(Smart Order Router, SOR):把一笔父单拆成许多小切片(child order),在多个交易场所之间动态分配,目标是最小化总执行成本(实现短缺,implementation shortfall)。核心直觉一句话:执行不是在「哪个场所买」上做一次性决定,而是在「每一刻、每个场所还剩多少便宜流动性」上做在线优化

我们用 5 个场所的合成流动性面板验证:父单 20 万股、拆 25 期、每期切片 8,000 股。等权拆分(naive)实现短缺 17.0 bps;静态成本分配(用期初深度算一次就照旧)均值 16.7 bps、但标准差高达 13.3 bps(碰到流动性枯竭就崩);智能自适应 SOR 逐期用当前深度重解优化,实现短缺 7.8 bps、标准差仅 2.8 bps——成本降 54%,稳定性还高一个数量级。

一、执行成本长什么样:临时冲击是凸的#

一笔切片(child order)在某场所的执行成本,相对「到达时的中间价」可以拆成三块:

  • 半价差(half-spread):你本来就想买在中间价,但成交要付价差,至少吃半口;
  • taker 费用(fee):吃单要交给场所/做市商的费用;
  • 临时冲击(temporary impact):你这片子占用了该场所当期的可用深度,把价格推歪,这部分和你切片大小非线性相关。

我们建模成:

def slice_cost(q, Dv, v):
    """单笔切片在某场所的执行成本(bps,相对到达中间价)。

    q   : 该场所切片股数
    Dv  : 该场所当期可用深度(股)
    v   : 场所编号
    成本 = 半价差 + taker费用 + 临时冲击
    临时冲击 ∝ (切片/深度)^2 * 10000   —— 二次凸,占深度比例越大贵得越快
    """
    q = max(q, 0.0)
    impact = GAM[v] * (q / Dv) ** 2 * 10000.0
    return SH[v] + FEE[v] + impact
python

关键在临时冲击项 GAM[v] * (q/Dv)^2成本随「切片占深度的比例」平方上升。这意味着「把一个大切片塞进浅场所」比「把同样总量均摊到深场所」贵得多——而且是非线性的,不是简单翻倍。

五个场所的单切片成本全景:场所 D(贵且浅)成本 13.1 bps,远高于场所 A(深流动性)的 1.8 bps

在等权参考切片(每场所 1,600 股)下,5 个场所单切片成本差异巨大:场所 A(深流动性)只有 1.8 bps,场所 C(极窄价差但浅)7.6 bps,场所 D(贵且浅)高达 13.1 bps。等权拆分完全无视这个差异——这正是它浪费成本的根源。

二、凸性:为什么不能简单按比例分#

把单个场所的成本曲线画出来,凸性一目了然:

临时冲击的凸性:单场所成本随切片非线性上升,深度越浅(γ 越大)曲线越陡

曲线向上弯(凸)。凸函数有个重要性质:把总量从「贵的场所」挪到「便宜的场所」能降本,但凸性意味着「边际成本相等」才是最优解——而不是把量塞到单价最低的那个(那样它在那个场所自己就变贵了)。这正是优化问题的核心:在 Σ q_v = S(每期总切片)、0 ≤ q_v ≤ D_v(不超过当期深度)约束下,求 Σ slice_cost(q_v) 最小。

最优解满足边际成本相等(KKT 条件):

∂cost/∂q_v = 2·GAM_v·10000 / D_v² · q_v  = 常数(对所有被选中的场所)
plaintext

解得 q_v ∝ D_v² / GAM_v——深度越深、冲击系数越小,分到的量越多。这就是下面 water-filling 的闭式直觉。

三、路由算法:从等权到 water-filling#

三种路由策略:

  • 等权拆分(naive):每期把 8,000 股硬均分 5 份,1,600 股砸进每个场所,不管谁贵谁便宜、谁深谁浅
  • 静态成本分配(semi-smart):用 t=0 的深度做一次 water-filling,算出一套「最优比例」后每期照旧——比 naive 聪明,但假设未来流动性永不变
  • 智能自适应 SOR(smart)每一期都用「当前」各场所深度重解 water-filling,流动性变了就立刻重配。

四、动态流动性:为什么静态会翻车#

真实市场的深度不是静止的。我们让各场所深度逐期对数正态波动,并随机触发「流动性枯竭」事件(某场所深度骤降 3 期):

def depth_path(rng):
    Dmat = np.zeros((T, N)); mult = np.ones(N)
    for t in range(T):
        mult = np.clip(mult * rng.lognormal(0, 0.18, N), 0.35, 3.0)
        if rng.random() < 0.08:        # 8% 概率触发枯竭事件
            mult[rng.integers(N)] *= 0.25
        Dmat[t] = DEPTH0 * mult
    return Dmat
python

这两条代表性路径的路由占比,热力图说得最清楚:

智能 SOR(上)vs 等权(下):SOR 在流动性枯竭的期次把量从浅场所转移走

上图(SOR)能明显看到:在流动性枯竭的期次(某场所占比骤降),SOR 把切片实时转移到还深着的场所;下图(等权)则纹丝不动——枯竭的场所照塞 20%,硬吃高冲击。

五、蒙特卡洛:SOR 把成本整体左移#

300 次模拟,比较三种路由的实现短缺(数量加权平均的单切片成本,单位 bps,越低越好):

实现短缺分布:SOR 把成本整体左移,且方差远小于静态与等权

路由策略均值 (bps)中位数 (bps)标准差 (bps)
等权拆分 (naive)17.0016.206.50
静态成本分配16.7313.3213.26
智能自适应 SOR7.797.282.83

结论很硬:

  • SOR vs 等权:成本降 54.2%(17.0 → 7.8 bps)。这 9 个多 bps 对一笔大单就是真金白银——20 万股、股价 100 元,名义 2,000 万,9 bps ≈ 1.8 万元;
  • SOR vs 静态:成本降 53.4%(16.7 → 7.8 bps),而且方差从 13.3 砍到 2.8——静态看似均值不差,但一碰枯竭事件就崩,尾部风险极高;
  • 静态相对等权只省 1.6%——因为它「算过一次」却死守过期比例,枯竭一来反而比等权还糟(等权好歹每场所只占 20%,静态可能把更多量压在恰好枯竭的那个)。

六、六类真实陷阱#

  1. 冲击模型是整件事的地基:我们用 (q/D)² 的二次临时冲击,真实冲击通常是「√q 永久 + q 临时」或更复杂的 Almgren-Chriss 形式,且永久冲击不可逆(你买的量会永久抬高价格,路由救不回)。模型错,路由比例就错——落地必须用真实成交回测校准 γ,而不是拍脑袋。
  2. 深度是预测值,不是观测值:实盘每期「可用深度」是估计的(你只看得到档位快照,看不到隐藏流动性/冰山单)。把估计当真值喂进 water-filling,会高估浅场所的承载力、把量塞爆。要加保守折让(q_v ≤ 0.3·D_v 之类)。
  3. 静态 vs 自适应的分水岭是「流动性时变强度」:我们的合成里枯竭事件频发,所以自适应碾压静态;若你交易的是超大盘、深度几乎不动,静态和自适应差别很小,反而不值得为自适应多付工程复杂度。先量市场的流动性波动,再决定要不要做自适应
  4. 机会成本与信息泄漏:把大单摊太多期(25 期变 250 期),虽然每期冲击小,但拖太久会暴露意图、承担价量漂移的 gamma/vega 风险。拆单期数本身是个优化变量,不是越大越好——最优在「冲击成本」和「等待风险」的交点。
  5. 费用与返佣的博弈:场所 C(极窄价差)费率为 0,但深度浅;纯按冲击优化可能过度依赖它。真实市场还有 maker-taker 返佣、阶梯费率,目标函数要把净成本(fee 含返佣)放进 slice_cost,否则会算出「便宜但被费率反噬」的路由。
  6. 合成数据局限:本面板是 5 场所、二次冲击、对数正态深度的自洽合成,只为干净演示「自适应重配」的降本与稳压。真实碎片化市场有上百场所、异步撮合、跨场所套利者、延迟差异——这些会让「最优解」带约束(如「同价优先主场」),工程上要加路由规则层而非纯优化。

七、结语#

智能订单路由的本质,是把「在哪个场所买」从一次性拍板变成逐期的在线凸优化

  • 执行成本里临时冲击是凸的(q/D)²),所以最优分配满足「边际成本相等」——q_v ∝ D_v²/γ_v,深的、冲击小的场所多分;
  • 静态算一次就够用,前提是流动性不变;一旦市场时变、枯竭频发,逐期重解的 SOR 把成本从 17.0 砍到 7.8 bps,且把尾部风险压下一个数量级;
  • 和之前聊的 Almgren-Chriss 最优执行放一起看:Almgren-Chriss 管「时间维度怎么拆」(快 vs 慢),SOR 管「空间维度怎么分」(这个场所 vs 那个)——两者是同一道执行题的纵横两刀,合起来才是完整的最优执行。

注:本文流动性面板为自洽合成数据(二次冲击、对数正态深度、随机枯竭事件),用于演示自适应 SOR 的降本与稳压;真实落地需真实成交校准冲击系数、保守估算深度、并把费率/返佣纳入成本函数。

智能订单路由(SOR):在多个交易场所之间把大单拆成最优流
https://blog.halo26812.eu.org/blog/smart-order-routing-venues
Author halo
Published at 2026年7月14日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨