第二章 TWAP算法数学原理:时间加权平均价格公式推导、切片逻辑与执行周期设计
好,咱们直接进入正题。
TWAP,全称 Time-Weighted Average Price,时间加权平均价格。名字听着挺唬人,但说白了,它的核心思想就一句话:把一个大单子,均匀地拆成小单子,在固定的时间窗口内分批执行。目标是什么?让我们的成交均价,尽量贴近这段时间的市场平均价。
我刚开始做量化交易那会儿,觉得这玩意儿太简单了,不就是平均分嘛。后来在实盘里吃过亏,才发现里面的门道比想象中深得多。今天我就把公式推导、切片逻辑和执行周期设计,掰开了揉碎了讲给你听。
2.1 时间加权平均价格的数学本质
先看公式。TWAP 的数学定义其实很朴素:
TWAP = (P₁ + P₂ + ... + Pₙ) / N
其中 P₁ 到 Pₙ 是每个时间点的价格,N 是时间点的总数。
你想想看,这个公式意味着什么?它假设我们在每个时间点都买入(或卖出)相同数量的股票。所以最终价格就是这些时间点价格的算术平均。
但这里有个坑——真实市场里,我们不可能在每个时间点都精确成交。我曾在一次 ETF 套利中,因为忽略了这一点,导致实际成交价和理论 TWAP 差了 3 个基点。嗯,3 个基点听起来不多,但资金量大的时候,够你心疼好一阵子的。
所以,更实用的公式是:
目标成交价 ≈ (∑ 每笔成交价 × 每笔成交量) / 总成交量
我们要做的,就是让这个实际成交均价,尽可能接近理论 TWAP。
核心要点:TWAP 不关心成交量分布,只关心时间分布。它假设市场在每个时间点都有足够的流动性来吃掉你的单子。
2.2 切片逻辑:把大象装进冰箱分几步?
切片,就是把总订单拆成若干个子订单。我习惯把切片逻辑分为三个层次:
- 时间切片:把总执行时间分成 N 个等长的时间段
- 数量切片:把总数量分成 N 等份
- 执行切片:在每个时间段内,把对应的数量发出去
举个例子。假设我们要买入 100 万股 ETF,执行时间 1 小时(3600 秒),切片数 N=12(每 5 分钟一个切片):
总数量 = 1,000,000 股
切片数 = 12
每片数量 = 1,000,000 / 12 ≈ 83,333 股
每片时长 = 3600 / 12 = 300 秒
代码实现起来也很直接:
def twap_slice(total_qty, total_seconds, num_slices):
slice_qty = total_qty / num_slices
slice_duration = total_seconds / num_slices
schedule = []
for i in range(num_slices):
start_time = i * slice_duration
end_time = (i + 1) * slice_duration
schedule.append({
'slice_id': i + 1,
'start': start_time,
'end': end_time,
'qty': slice_qty
})
return schedule
# 调用示例
schedule = twap_slice(1000000, 3600, 12)
for s in schedule:
print(f"切片{s['slice_id']}: {s['start']:.0f}s - {s['end']:.0f}s, 数量{s['qty']:.0f}股")
输出结果:
切片1: 0s - 300s, 数量83333股
切片2: 300s - 600s, 数量83333股
...
切片12: 3300s - 3600s, 数量83333股
个人经验:切片数 N 不是越大越好。我曾经把 N 设到 60(每 1 分钟一个切片),结果因为频繁发单,反而增加了冲击成本。后来我总结出一个经验:对于流动性好的 ETF,N 取 10-20 比较合适;流动性差的,N 取 5-10 就够了。
2.3 执行周期设计:从理论到实战的最后一公里
切片逻辑搞定了,接下来就是执行周期设计。这里我要重点讲三个东西:
2.3.1 周期类型
我一般把执行周期分为两种:
- 固定周期:每个切片的时间长度完全相等。简单、好理解,但遇到市场剧烈波动时容易吃亏。
- 动态周期:根据市场状态调整切片时长。比如波动率大的时候缩短切片,波动小的时候拉长切片。
我个人更倾向于动态周期。为什么?因为市场不是均匀的。你想想看,如果开盘前 5 分钟波动特别大,你还按固定周期慢慢发单,那不是等着被收割吗?
2.3.2 执行时机
每个切片内部,什么时候发单?这里有三种常见策略:
| 策略 | 说明 | 优缺点 |
|---|---|---|
| 切片开始时立即发单 | 一到时间点就发 | 简单,但容易造成价格冲击 |
| 切片中间点发单 | 在切片中间时刻发 | 能平滑一些,但时机不好把握 |
| 随机时间发单 | 在切片内随机选一个时间点发 | 能避免被对手盘识别,我比较推荐 |
我记得有一次做 ETF 套利,对手盘明显在盯着我的 TWAP 策略。我每次都在切片开始时发单,结果对方提前挂单等着吃我的货。后来改成随机时间发单,情况就好多了。
2.3.3 避坑指南
我曾经踩过的坑:
- 切片数设太多,导致每片数量太小,被市场手续费吃掉利润
- 没有考虑 ETF 的申赎机制,导致切片逻辑和申赎时间不匹配
- 忽略了市场开盘和收盘的特殊时段,这两个时段波动大、流动性差
2.4 核心逻辑流程图
下面这张图,是我自己画的一个 TWAP 执行流程。你看一眼就能明白整个逻辑链条:
2.5 实战中的几个关键点
最后,我再说几个实战中容易忽略的地方:
- ETF 的最小交易单位:ETF 是 100 股一手,切片数量必须是 100 的整数倍。我见过有人直接除完就发单,结果被交易所拒单。
- 市场冲击成本:切片数量太大,会推高价格;太小,又会被手续费吃掉。这个平衡点需要根据 ETF 的日均成交量来调整。
- 时间同步:如果你的交易系统和交易所的时间不同步,切片逻辑就会乱套。我建议用 NTP 协议做时间同步,误差控制在 10 毫秒以内。
一句话总结:TWAP 的核心不是数学公式有多复杂,而是怎么把理论上的均匀分布,在真实市场里执行得既隐蔽又高效。切片逻辑是骨架,执行周期是血肉,两者缺一不可。
好了,这一章的内容就到这里。公式推导、切片逻辑、执行周期设计,这三个东西你吃透了,TWAP 就算入门了。下一章我们会聊更进阶的东西——怎么在 TWAP 里加入成交量权重,做成 VWAP。不过那是后话了,先把今天的内容消化掉。