VWAP 与 TWAP 执行:把大单切成时间与成交量加权的碎片
执行算法的入门双雄:TWAP 把母单按时间等分,VWAP 按日内成交量剖面切片。48 桶 U 型剖面模拟实测:500 天蒙特卡洛里 VWAP(历史剖面)滑点均值 43.97bp vs TWAP 45.90bp,但真正的差距在方差——σ 1.25bp vs 6.32bp,差 5 倍;VWAP 的本质不是更便宜而是更贴基准。上帝视角(当日真实剖面)与历史剖面预测只差 0.3bp,说明成交量剖面的日间稳定性是 VWAP 可行的全部前提。规模扫描:母单从日成交量 1% 到 100%,两者滑点差保持约 2-4bp,参与率的平方根冲击才是成本主体——切片方式省小钱,订单规模定大钱。诚实边界:VWAP 追平的是『市场均价』不是『决策价』,动量日里 VWAP 完美达标仍可能巨亏 Implementation Shortfall;剖面突变日(新闻、指数调仓)历史剖面失效;两者都是被动日程,不响应价格。
协方差专题写完之后,换一个战场:执行。前面所有组合构建文章的输出都是一列目标权重,但从「目标权重」到「实际持仓」中间隔着一条鸿沟——你要在市场里真金白银地把单子成交掉。100 万股的母单直接砸进订单簿,价格会立刻跳开;这就是执行算法存在的理由。
今天从最基础的双雄开始:TWAP 和 VWAP。它们是几乎所有券商算法交易柜台的默认选项,也是理解后面 Almgren-Chriss、Implementation Shortfall 这些高级框架的前置知识。
一、问题:大单不能一口吃#
设你要在今天之内买入 股。两个极端都不行:
- 一次性市价单:吃穿订单簿多档深度,冲击成本随规模超线性增长;
- 无限拖延:价格漂移风险随时间累积,你等到的价格可能更差。
执行算法做的事就是把母单切成子单序列,在冲击成本与时机风险之间找折中。TWAP 和 VWAP 是两种最朴素的切法:
- TWAP(Time-Weighted Average Price):把交易时段切成 个桶,每桶交易 ——时间等分;
- VWAP(Volume-Weighted Average Price):按预期成交量剖面 分配,每桶交易 ——成交量等比。
VWAP 的直觉:市场成交量大的时候,你的子单占比小、冲击小;成交量小的时候少交易。跟着市场的流动性节奏走,而不是跟着钟表走。
二、日内成交量的 U 型剖面#
VWAP 之所以可行,全靠一个稳定的经验事实:日内成交量呈 U 型——开盘和收盘放量、午盘清淡。模拟里我用 48 个 5 分钟桶构造这个剖面:
import numpy as np
n_bins = 48
t = np.linspace(0, 1, n_bins)
def u_shape_volume(t, rng, noise=0.15):
base = 1.8 * (t - 0.5) ** 2 + 0.55 # U 型主体
base[:2] *= 1.6 # 开盘冲高
base[-3:] *= np.array([1.3, 1.6, 2.2]) # 尾盘拉升
v = base * np.exp(rng.normal(0, noise, len(t)))
return v / v.sum() # 归一化为占比python对数正态噪声让每天的剖面有随机扰动,但 U 型骨架不变——这正是真实市场的样子:剖面的形状日间高度稳定,幅度每天不同。
两种切片方式的对比一目了然:

TWAP 是一条平线:午盘市场每桶只有约 1% 的成交量,你却硬塞和开盘一样多的量,参与率被动飙升。VWAP 的子单曲线和市场剖面完全同形——尾盘市场放量到 4%+,你也放量。
三、执行模拟:冲击成本模型#
子单进入市场后的成交价,用参与率驱动的平方根冲击近似:
def exec_day(slices, vol_prof, price, Q_total):
mkt_vol = vol_prof * 20_000_000 # 市场日总量 2000 万股
part = slices / (mkt_vol + slices) # 每桶参与率
exec_px = price * (1 + 0.02 * np.sqrt(part)) # 平方根冲击
return np.sum(exec_px * slices) / Q_total # 成交均价python平方根形式来自市场冲击的经验定律(后续专文展开):冲击 。凹函数意味着把量摊薄有超线性的好处——这正是 VWAP 优于 TWAP 的数学根源:TWAP 在低量桶里参与率尖峰,平方根的凹性惩罚这种不均匀。
单日示例(母单 100 万股 = 日成交量 5%):

两种策略的成交均价都高于市场 VWAP(买单必然付冲击),但 VWAP 策略更贴近基准。
四、500 天蒙特卡洛:均值差一点,方差差五倍#
单日说明不了问题,跑 500 天。VWAP 策略分两个版本:上帝视角(用当日真实剖面切片,实盘不可得)和现实版(用前 60 天历史平均剖面预测今天):
hist_prof = np.mean([sim_day(d)[0] for d in range(60)], axis=0) # 历史剖面
# 每天:TWAP、VWAP-历史剖面、VWAP-真实剖面 三种执行
# 滑点 = (成交均价 / 市场VWAP - 1) × 1e4 (bp)python
500 天的结果值得逐项读:
| 策略 | 滑点均值 (bp) | 滑点标准差 (bp) |
|---|---|---|
| TWAP | 45.90 | 6.32 |
| VWAP(历史剖面) | 43.97 | 1.25 |
| VWAP(真实剖面) | 43.64 | 0.00 |
三个观察:
- 均值差距不大(约 2bp),VWAP 并没有便宜多少——省钱不是它的主卖点;
- 方差差 5 倍是真正的分水岭。TWAP 对市场 VWAP 的滑点随当天剖面形状波动(今天尾盘放量多,TWAP 就多吃亏);VWAP 策略与基准同步呼吸,滑点几乎恒定。对于以 VWAP 为业绩基准的机构交易台(这是买方最普遍的考核方式),低跟踪方差就是低职业风险;
- 历史剖面 vs 真实剖面只差 0.33bp。剖面的日间稳定性极高,用 60 天平均预测今天已经足够好——这是 VWAP 在实务中如此普及的根本原因:它对预测精度的要求低到近乎免费。
五、订单规模扫描:切法省小钱,规模定大钱#
母单从日成交量的 1% 扫到 100%:

两条曲线都按平方根规律爬升(对数横轴下的凹形),VWAP 全程低于 TWAP 但差距只有 2-4bp。对比一下量级:母单从 5% 加到 50% 日成交量,滑点从 ~45bp 涨到 ~120bp。**决定执行成本的第一要素是你的订单规模相对流动性的比例,切片算法只在第二位。**这个次序在实盘里经常被搞反——花大力气优化算法参数,却不肯把一天的单子拆成三天。
六、诚实边界#
**VWAP 达标 ≠ 交易做得好。**VWAP 追平的是「市场均价」,不是你的「决策价」。设想动量日:你早上决定买入,价格全天单边上涨 3%,VWAP 算法匀速买了一天、完美贴住市场 VWAP——但市场 VWAP 本身比你的决策价高了 1.5%。以 Implementation Shortfall(决策价口径)衡量你亏了 150bp,而 VWAP 口径显示你是满分。基准的选择本身就是立场:VWAP 基准隐含「时机风险不算我的错」,这对被动跟踪基准的机构合理,对有 alpha 时效性的策略是自欺。
**剖面突变日失效。**历史剖面的前提是今天像昨天。指数调仓日(尾盘天量)、重大新闻日(盘中脉冲)、节假日前后,剖面形状剧变,VWAP 的切片计划系统性错位。成熟的实现会叠加动态剖面修正(用盘中已实现成交量更新剩余桶的预测),但那已经是另一层工程。
两者都是纯被动日程,对价格信号零响应:价格暴跌时买单不会加速(错过便宜货),价格急涨时也不会暂停(追高照单全收)。把价格弹性引入执行日程,就进入了 Almgren-Chriss 均值-方差执行和自适应算法的领地——那是这个系列后面的故事。
模拟本身的局限也要交代:冲击系数拍脑袋(真实系数因股票、市场状态而异,需从自家成交数据回归);没有建模永久冲击与冲击衰减(Propagator 模型的主题);市场成交量与我方订单独立的假设在大单场景不成立——你的买入本身会吸引跟风量。
七、实盘落地清单#
把模拟里的结论翻译成可操作的规则:
- 先定基准再选算法。考核口径是 VWAP 就用 VWAP 算法,考核口径是决策价(Implementation Shortfall)就不要用 VWAP——用错基准的算法等于优化错误的目标函数;
- 剖面估计用 20-60 天滚动中位数而非均值,避免个别天量日(指数调仓)污染剖面。周内效应明显的市场(如期货换月周)应按星期几分层估计;
- 设置参与率上限(如单桶不超过市场量的 20%)作为保险丝:当天成交量意外萎缩时,宁可延到明天也不要在枯水期硬灌;
- 盘中动态修正:用已实现成交量与历史剖面的比值缩放剩余桶的计划量,简单一行代码就能把剖面突变日的错位吃掉一半;
- 子单层面随机化:桶内下单时间加抖动、单量加噪声,避免被高频对手识别出规律性日程后抢跑(TWAP 的等间隔特征是最容易被逆向工程的模式之一)。
八、总结#
TWAP 是「按钟表交易」,VWAP 是「按市场节奏交易」。500 天模拟给出的画像很清晰:VWAP 的价值不在省钱(均值只差 2bp)而在贴基准(方差差 5 倍);历史剖面几乎免费地逼近上帝视角(差 0.3bp),因为成交量剖面的 U 型骨架日间极稳定。但真正决定成本的是订单规模与流动性之比,以及你选的基准是否匹配你的交易动机——算法只是执行意图的翻译器,翻译得再流畅,也救不了错误的意图。