2、TWAP核心原理:时间切片机制、均匀分配逻辑、订单拆分策略
好,咱们直接进入正题。
TWAP,全称 Time-Weighted Average Price,时间加权平均价格。名字听着挺唬人,但说白了,它的核心思想就一句话:把一个大订单,切成很多小份,然后均匀地丢到市场里去。
我最早接触 TWAP 是在做期货套利的时候。当时要建一个很大的头寸,一单下去市场直接打穿好几个价位。嗯,那感觉就像往平静的湖面扔了一块大石头。后来我才明白,真正专业的做法,是像下雨一样,细密而均匀。
2.1 时间切片机制:把时间切成豆腐块
时间切片,是 TWAP 最底层的逻辑。你想想看,如果给你 1 个小时,要买 100 万股。你会怎么做?
我个人的习惯是,先把这 1 小时切成 N 个等长的时间片。比如切成 60 片,每片 1 分钟。或者切成 120 片,每片 30 秒。这个切片的过程,就是时间切片机制。
时间片长度 = 总执行时间 / 切片数量
每个时间片的目标成交量 = 总订单量 / 切片数量
这里有个关键点:切片数量怎么定?
- 切片太少:比如只切 10 片,每片 6 分钟。那每片的订单量还是很大,依然会冲击市场。说白了,失去了拆单的意义。
- 切片太多:比如切 600 片,每片 6 秒。理论上更均匀,但实际中,每片可能只成交几股,频繁的撤单和挂单反而会增加交易成本。
我在项目中遇到过一种情况:某次做港股交易,流动性很差。我一开始切了 60 片,结果发现很多时间片根本成交不了。后来我改成 20 片,每片 3 分钟,反而效果更好。所以,切片数量要结合市场流动性来调整,没有绝对的标准。
2.2 均匀分配逻辑:别让市场猜到你的底牌
均匀分配,是 TWAP 的灵魂。它的目标很简单:让每一段时间内的交易量,都差不多。
为什么会这样?因为如果你在某一段时间内突然加大交易量,市场就会察觉到异常。做市商和算法交易系统会立刻捕捉到你的意图,然后反向操作,让你买在最高点,卖在最低点。
均匀分配的逻辑,通常有两种实现方式:
- 固定数量法:每个时间片分配完全相等的股数。比如总订单 100 万股,切 100 片,每片就是 1 万股。这是最朴素的做法。
- 固定比例法:根据历史成交量分布,调整每个时间片的分配比例。比如开盘和收盘时段流动性好,就多分配一些;午盘流动性差,就少分配一些。
这里有一个常见的误区:均匀分配 ≠ 机械执行。你想想看,如果市场突然出现一个巨大的卖单,价格瞬间砸下去 2%。这时候你还按原计划均匀买入吗?当然不。这时候应该暂停一下,或者加速买入。所以,真正的 TWAP 算法,会在均匀分配的基础上,加入一些动态调整的逻辑。
2.3 订单拆分策略:从大单到小单的艺术
订单拆分,是 TWAP 落地的最后一步。前面我们切好了时间片,算好了每片的量,现在要做的就是:把每片的订单,拆成更小的子订单,然后发到交易所。
拆分的策略,我总结为三种:
| 策略名称 | 做法 | 适用场景 |
|---|---|---|
| 单笔全量 | 每个时间片只发一笔订单,数量等于该片的目标量 | 流动性极好、市场深度足够的品种 |
| 多笔均分 | 每个时间片再拆成 3-5 笔,每笔数量相等 | 大多数主流股票、期货 |
| 随机拆分 | 每个时间片拆成多笔,每笔数量在一定范围内随机 | 需要隐藏交易意图、防止被识别的场景 |
我个人最常用的是多笔均分。为什么呢?因为单笔全量太容易被看穿,随机拆分又太复杂,不好控制。多笔均分,既分散了风险,又保持了逻辑的简洁。
另外,订单拆分时还要考虑一个细节:限价单 vs 市价单。TWAP 通常使用限价单,因为市价单的成本不可控。限价单的价格怎么设?一般是在当前买一价或卖一价的基础上,加一个偏移量。这个偏移量,我习惯设为 1-2 个 tick,既能保证成交概率,又不会吃太大的滑点。
2.4 核心逻辑流程图
下面这张图,是我自己画的一个 TWAP 核心逻辑流程图。你可以把它当作一个速查表,写代码的时候对照着看。
这张图看起来很简单,但每一个步骤背后都有很多细节。比如步骤1中,切片数量怎么定?步骤2中,均匀分配要不要考虑成交量分布?步骤3中,限价单的价格怎么设?这些我们在后面的章节中会逐一展开。
2.5 一个简单的代码示例
光说不练假把式。下面我写一个极简的 TWAP 核心逻辑,用 Python 实现。注意,这只是教学演示,生产环境要复杂得多。
class SimpleTWAP:
def __init__(self, total_qty, total_seconds, num_slices):
self.total_qty = total_qty # 总订单量
self.total_seconds = total_seconds # 总执行时间(秒)
self.num_slices = num_slices # 切片数量
self.slice_seconds = total_seconds / num_slices # 每片时长
self.slice_qty = total_qty / num_slices # 每片目标量
def generate_schedule(self):
"""生成执行计划"""
schedule = []
for i in range(self.num_slices):
start_time = i * self.slice_seconds
end_time = (i + 1) * self.slice_seconds
schedule.append({
'slice_id': i,
'start': start_time,
'end': end_time,
'target_qty': self.slice_qty
})
return schedule
def split_order(self, slice_qty, num_sub_orders=3):
"""将每片的订单拆成多笔"""
sub_qty = slice_qty / num_sub_orders
orders = []
for j in range(num_sub_orders):
orders.append({
'sub_id': j,
'qty': sub_qty,
'price': 'LIMIT' # 实际中需要计算具体价格
})
return orders
# 使用示例
twap = SimpleTWAP(total_qty=100000, total_seconds=3600, num_slices=60)
schedule = twap.generate_schedule()
print(f"共 {len(schedule)} 个时间片,每片目标量 {schedule[0]['target_qty']:.0f} 股")
# 输出:共 60 个时间片,每片目标量 1667 股
这段代码虽然简单,但已经包含了 TWAP 的三个核心要素:时间切片、均匀分配、订单拆分。你可以在它的基础上,加入动态调整、风控检查、日志记录等功能。
好了,这一章的内容就到这里。TWAP 的核心原理其实不复杂,难的是在真实市场中把它跑稳、跑好。下一章我们会聊到 TWAP 的实战参数调优,到时候我会分享一些具体的调参经验和踩坑记录。
公众号:蓝海资料掘金营,微信deep3321