执行落差归因:把 Implementation Shortfall 拆成延迟、冲击与择时
TCA 报表把执行落差拆成「延迟成本」和「交易成本」两个桶,然后拿后者考核交易台。4000 笔母单的受控模拟(每一个 bp 的真实成因都已知)给出决定性读数:报告的 15.57 bp 交易成本里,真实市场脚印只有 7.09 bp,54.5% 是本来就会发生的 alpha 漂移。零冲击安慰剂最硬--把自身冲击彻底关掉(真值精确为 0),报表照样开出 9.51 bp 账单,一个毫无市场足迹的交易台被凭空罚款。反过来关掉 alpha,交易桶立刻诚实(误差 1.67 bp),证明污染源就是 alpha 而非模型缺陷。三个基准在同一批成交上给出 23.48 / 15.57 / 7.09 bp 三个故事,跨度 16.39 bp;只把「到达时间戳」往后挪 12 根 bar、不改任何一笔成交,交易台成本从 15.6 bp 降到 -1.4 bp,17.0 bp 的纯文书改善。最刺眼的是考核后果:三个交易台按报告成本排名是 A<B<C,按真实脚印排名精确反转成 C<B<A,被表扬的正是footprint最大的那个。八项对抗式检验全过,含分解恒等式残差 0.00e+00、零延迟对照精确 0.00 bp、12 个宇宙 CV 0.106。样本量红线:单笔标准差 63.98 bp、35.9% 的单子成本为负,要 30 笔才够 t=2(高阶)
问题:那份 TCA 报表在考核谁#
买方的交易成本分析(TCA)报表长得都差不多。一笔母单从 PM 按下按钮到最后一股成交,中间的价格损耗叫执行落差(Implementation Shortfall,IS),然后被拆成两块:
- 延迟成本:决策价 → 到达交易台时的价格。这段归”流程”。
- 交易成本:到达价 → 实际成交均价。这段归交易台。
第二个数字被印在交易员的季度考核表上。
这个拆法源自 Perold 1988,逻辑无懈可击:交易台只能对它拿到单子之后的事负责。问题在于,“到达之后发生的价格变化”和”交易台造成的价格变化”根本不是一回事。
单子到达之后,价格会动的原因至少有四个:
- 你自己的买盘把价格推高了(这才是交易台的责任)
- 当初让 PM 下单的那个 alpha 正在兑现(不交易也会发生)
- 随机波动
- 别人的单子
标准归因把这四样东西打包塞进一个桶,贴上”交易成本”的标签,然后拿去发奖金。
本文用一个真值已知的受控模拟量化这个混淆到底有多贵。
实验设计:让每一个 bp 都可追溯#
要判断归因准不准,得先有个”准”的定义。真实市场里你永远不知道那 20 个 bp 里有多少是自己推的—所以我造一个知道的世界。
价格路径由四个独立生成、单独记账的分量叠加:
BAR_VOL = 0.0016 # 每 bar 噪声 sigma(1 bar = 5 分钟)
ALPHA_HL = 26.0 # alpha 半衰期(bar)
GAMMA = 0.00030 # 永久冲击系数
ETA = 0.00055 # 临时冲击系数
T_REF = 200 # alpha 归一化的固定参考窗python- alpha 漂移:前重后轻、指数衰减。这是当初下单的理由,也是延迟为什么贵的原因。
- 噪声:零均值随机游走。
- 永久冲击:自己的脚印,不会回来。
- 临时冲击:自己的脚印,停手后按 3 bar 半衰期衰减。
一笔母单的生命周期:t=0 PM 决策 → t=L 到达交易台 → t=L..L+H 逐 bar 均匀成交 → 结束。
这里有个必须踩对的坑。alpha 的归一化窗口不能用订单自己的时长 T,必须用一个固定的参考窗 T_REF:
t_grid = np.arange(T)
ref = np.exp(-lam * np.arange(T_REF))
incr = np.exp(-lam * t_grid) / ref.sum() * (alpha_bp / BP)
alpha_path = np.cumsum(incr) * sidepython如果按每笔订单自己的 T 归一化,短单子就等于活在一个”alpha 衰减更快”的宇宙里—参与率扫描会得到完全错误的最优点。这个 bug 我在第一版里犯了,扫描结果把最优参与率从 12% 错报成 5%,改掉之后 U 形曲线才对上。
因为每个分量是分开生成的,成交均价里各自贡献了多少 bp 可以精确算出来:
def avg_component(arr):
return float(np.mean(arr[exec_bars]) - arr[0])python这就是标准归因要被拿去对照的真值。
结果一:交易成本桶里,一半以上不是交易台的锅#
4000 笔母单,参数随机(alpha 均值 45 bp、延迟泊松均值 8 bar、时长均值 24 bar、参与率均值 12%),买卖各半:

| 口径 | 数值 |
|---|---|
| 总执行落差 | 23.48 bp |
| 报告的「延迟成本」 | 7.91 bp |
| 报告的「交易成本」 | 15.57 bp |
| 真实 alpha 漂移 | 17.18 bp |
| 真实自身冲击(永久+临时) | 7.09 bp |
| ├ 永久 | 4.44 bp |
| └ 临时 | 2.65 bp |
| 噪声(应≈0) | -0.78 bp |
交易台被记账 15.57 bp,真实市场脚印只有 7.09 bp。54.5% 的账单不是它造成的。
差额去哪了?在执行的那 24 根 bar 里,alpha 还在继续兑现。价格朝着 PM 预期的方向走,而交易台正好在这段时间买入—于是 alpha 的兑现被记成了交易台的成本。
单笔订单的解剖看得更清楚:

黑线是交易台唯一能看到的东西。红色虚线(alpha)和绿色虚线(自身冲击)在真实世界里不可分离—但它们的斜率完全不同:alpha 在整个窗口持续推高价格,自身冲击只在执行期间累积。
结果二:把冲击彻底关掉,账单还在#
上面那个 54.5% 也许是我模型参数没调好?做个安慰剂:把 gamma 和 eta 都设成 0。这个世界里,交易台在物理上不可能对价格产生任何影响。

真实自身冲击 : 0.0000 bp ← 构造上精确为零
报告的「交易成本」 : 9.51 bp ← 纯粹的幽灵plaintext一个毫无市场足迹的交易台,被开出 9.51 bp 的账单。 这不是估计误差,是归因框架的结构性产物。
反方向的安慰剂同样重要—把 alpha 设成 0,冲击照常开:
报告的「延迟成本」 : 1.90 bp ← 塌回接近零(本该如此,没有 alpha 就没有延迟代价)
报告的「交易成本」 : 5.36 bp
真实自身冲击 : 7.03 bp ← 误差只剩 1.67 bpplaintextalpha 一关,交易桶立刻变诚实。这条对照锁死了污染源:不是模型有 bug,就是 alpha 本身。
结果三:同一批成交,三个基准三个故事#
换个基准,同一批一模一样的成交能讲出完全不同的故事:

| 基准 | 成本 | 谁爱用 |
|---|---|---|
| 决策价 | 23.48 bp | PM |
| 到达价 | 15.57 bp | 交易台 |
| 区间 VWAP | 7.09 bp | 经纪商 |
跨度 16.39 bp,成交记录一个字没改。
有意思的是区间 VWAP 那行—它给出的 7.09 bp 恰好精确等于真实自身冲击。这不是巧合:区间 VWAP 剔除了执行窗口内的市场整体漂移,剩下的正好是你自己推出来的那部分。如果你只想考核交易台的市场脚印,VWAP 反而是三者中最诚实的(代价是它对”该不该慢慢做”这个问题完全失明)。
更难看的是时间戳。不改任何一笔成交,只把”到达时间”往后登记:
| 到达时间戳后移 | 交易台被记账成本 |
|---|---|
| +0 bar | 15.57 bp |
| +3 bar | 9.95 bp |
| +6 bar | 5.24 bp |
| +9 bar | 1.33 bp |
| +12 bar | -1.42 bp |
17.0 bp 的纯文书改善。 挪一小时的时间戳,交易台从”成本 15.6 bp”变成”给公司赚了 1.4 bp”。任何把到达时间戳交给被考核方自己填的 TCA 系统,考核的都是填表能力。
结果四:最优参与率是个 U 形,两头都贵#
既然延迟贵是因为 alpha 跑掉,那全速买不就行了?扫一遍参与率(参与率越高、执行窗口越短):

| 参与率 | 执行窗口 | 总 IS | alpha 漂移 | 自身冲击 |
|---|---|---|---|---|
| 3% | 96 bar | 35.73 bp | 30.96 | 5.13 |
| 5% | 58 bar | 28.68 bp | 25.54 | 5.67 |
| 8% | 36 bar | 25.56 bp | 20.81 | 6.34 |
| 12% | 24 bar | 22.51 bp | 17.15 | 7.19 |
| 18% | 16 bar | 23.06 bp | 14.65 | 8.26 |
| 25% | 12 bar | 23.40 bp | 13.24 | 9.54 |
| 50% | 6 bar | 24.59 bp | 10.80 | 12.17 |
两条曲线方向相反:慢了 alpha 跑掉,快了自己踩自己。最优在 12%,最差角落 35.73 bp—13.23 bp 是纯粹可避免的成本。
注意这个最优点完全取决于 alpha 半衰期。对照 A3 的扫描:
| alpha 半衰期 | 延迟成本 |
|---|---|
| 8 bar | 20.32 bp |
| 26 bar | 8.13 bp |
| 120 bar | 2.62 bp |
信号衰减越快,拖延越致命。一个日内反转信号和一个季度价值信号,不该用同一套执行算法—这是本文唯一可以直接落地的结论。
结果五:你的 TCA 报表可能在读噪声#
单笔执行落差的分布:

- 均值 23.48 bp,标准差 63.98 bp
- 35.9% 的单子成本为负(价格朝你有利的方向动了)
信噪比低到什么程度?要让 t 统计量达到 2,需要 30 笔订单:
R["n_for_t2"] = (2.0 * per_order_std / per_order_mean) ** 2python| 样本笔数 | 90% 置信区间 |
|---|---|
| 5 | [-19.62, 70.92] bp |
| 25 | [2.14, 44.05] bp |
| 100 | [13.22, 33.92] bp |
| 1000 | [20.22, 26.68] bp |
30 笔是总体均值的门槛。要比较两个交易台、或者比较两个算法,方差翻倍,门槛还要往上抬。而现实中,一个中型基金某个交易台某个策略某个月的样本量,经常就是十几笔。
在这个样本量下讨论”A 算法比 B 算法好 3 bp”,是在给随机数排名。
结果六:被动挂单看起来更便宜,只要你不数漏掉的单#
TCA 报表最常见的漏洞是只统计已成交部分:

| 策略 | 只算已成交 | 加上机会成本 |
|---|---|---|
| 市价单 100% 成交 | 24.22 bp | 24.22 bp |
| 被动 85% 成交 | 19.69 bp | 24.66 bp |
| 更被动 65% 成交 | 14.14 bp | 24.96 bp |
| 极被动 45% 成交 | 9.15 bp | 24.95 bp |
按”已成交成本”排名,极被动策略以 9.15 bp 完胜—成本砍掉六成。按总落差排名,它是最差的之一。
这个陷阱特别阴险,因为它不留伤口。没成交的单子不会出现在成交回报里、不会进 P&L、不会有人投诉。它只是让某些本该发生的交易从未发生,而这部分损失从不出现在任何报表上。
结果七:考核排名会精确反转#
把前面的东西合起来,看真实后果。三个交易台,风格不同:

| 交易台 | 报告的「交易成本」 | 真实市场脚印 |
|---|---|---|
| A 台(激进,流程快) | 11.49 bp | 9.50 bp |
| B 台(温和,流程慢) | 14.08 bp | 6.81 bp |
| C 台(被动,流程中) | 21.67 bp | 5.67 bp |
按报告成本排名:A < B < C(A 最好) 按真实脚印排名:C < B < A(C 最好)
精确反转。 被表扬的 A 台恰恰是市场足迹最大的那个—它做得快,所以逃过了 alpha 漂移的记账,但它对市场的实际冲击是 C 台的 1.7 倍。而 C 台因为慢慢做、承受了更多 alpha 漂移,被记了最高的账单。
如果奖金挂钩报告数字,理性的交易员会学会:做快、抢流动性、把 alpha 兑现的时间压缩到记账窗口之外。这恰好是冲击成本最高的做法。
对抗式检验#
八项,全过:
| # | 检验 | 结果 |
|---|---|---|
| A1 | 买卖对称性 | 买 23.37 / 卖 23.59 bp,差 0.22 bp,符号约定无误 |
| A2 | 分解恒等式 | 残差 0.00e+00 bp,三个桶严格加总到总数 |
| A3 | alpha 半衰期扫描 | 8→120 bar,延迟成本 20.32→2.62 bp 单调下降 |
| A4 | 12 个宇宙种子稳定性 | 均值 23.43 bp,标准差 2.48 bp,CV 0.106 |
| A5 | 零延迟对照 | delay=0 时延迟成本 精确 0.00 bp |
| A6 | 考核排名反转 | 报告 A<B<C,真值 C<B<A,完全反转 |
| A7 | 零冲击安慰剂 | 真值 0,报表仍开出 9.51 bp |
| A8 | 零 alpha 安慰剂 | 交易桶误差降到 1.67 bp,锁定污染源 |
A2 值得单说:残差精确为 0 说明这个分解在算术上是严丝合缝的。这正是它危险的地方—一个恒等式永远成立,但它成立不代表每个桶的标签是对的。很多人看到”分解能对上”就以为验证过了,其实什么都没验证。
实操建议#
- 不要用「到达价 → 成交均价」考核交易台。 它系统性地把 alpha 漂移记在交易台头上,且高 alpha 策略的交易台受罚最重。
- 同时报三个基准。 决策价看 PM 的决策质量+流程效率,区间 VWAP 看交易台的市场脚印,到达价看两者的混合。单报一个必然误导。
- 到达时间戳必须由系统自动打,不能由被考核方填。 17 bp 的操纵空间。
- 机会成本必须入表。 否则被动算法会在报表上无限占优。
- 样本量低于 30 笔的 TCA 结论,直接扔掉。
- 按 alpha 半衰期分组考核。 快信号和慢信号的最优参与率不是一个数量级的问题,是方向相反的问题。
局限#
- 模拟是线性冲击模型(冲击 ∝ 参与率)。真实市场普遍认为是平方根律,这会让高参与率区间的成本被本文低估,最优参与率的真实位置应该比 12% 更靠左。
- 假设匀速执行。真实算法会择时、会跟随成交量曲线,这本身就是”择时”那一块,本文没有单独拆出来。
- 没有建模流动性枯竭和信息泄漏。大单被察觉之后的抢跑,在这个框架里完全不存在。
- alpha 路径是确定性衰减的,真实 alpha 有相当大的不确定性,这会进一步压低单笔的信噪比—也就是说,那个”30 笔”的门槛在现实中只会更高。
最后一点值得强调:本文所有结论都建立在”alpha 存在且会兑现”这个前提上。如果一个策略的 alpha 是假的,那么”延迟成本”这个桶测到的东西就只是噪声,整套归因讨论的前提本身就不成立。