4、执行算法入门:TWAP、VWAP、POV 算法原理与实现
各位同学,欢迎来到《交易执行策略优化实战》的第一章。我是你们的老朋友,一个在量化交易和金融科技领域摸爬滚打多年的工程师。今天咱们聊点实在的——执行算法。
你想想看,策略信号出来了,怎么把它变成真实的成交?直接一把梭?那市场冲击成本会让你哭出来。所以,我们需要一些“聪明”的算法来帮我们拆单、择时。今天要讲的 TWAP、VWAP 和 POV,就是最经典的三个入门算法。
我个人习惯把这三兄弟称为“执行算法的三原色”。理解了它们,后面再学更复杂的策略就轻松多了。
4.1 TWAP:时间加权平均价格算法
原理
TWAP 的核心思想很简单:把一个大订单,均匀地切成 N 份,然后在固定的时间间隔里,一份一份地扔到市场里。它的目标,就是让我们的成交均价,尽量贴近这段时间内的市场平均价格。
说白了,就是“时间切片”。比如你有一个 100 万股的订单,要在 1 小时内完成。TWAP 会把它切成 60 份,每分钟只交易 1.67 万股左右。不管市场怎么波动,我就按这个节奏走。
为什么用 TWAP?
我在项目中遇到过一种情况:某个股票流动性一般,但日内波动不大。这时候用 TWAP 就特别合适。它不预测方向,只是机械地执行,能有效避免因为“等一个好价格”而错过交易窗口。
实现代码
import pandas as pd
import numpy as np
def twap_schedule(total_qty, total_seconds, interval_seconds=60):
"""
生成 TWAP 执行计划
:param total_qty: 总交易量
:param total_seconds: 总执行时间(秒)
:param interval_seconds: 每个时间间隔(秒)
:return: 每个时间点的目标交易量
"""
num_slices = total_seconds // interval_seconds
qty_per_slice = total_qty / num_slices
schedule = []
for i in range(num_slices):
schedule.append({
'time': (i + 1) * interval_seconds,
'target_qty': qty_per_slice
})
return schedule
# 示例:1小时内交易10万股,每5分钟交易一次
schedule = twap_schedule(100000, 3600, 300)
print(schedule[:3]) # 打印前3个切片
4.2 VWAP:成交量加权平均价格算法
原理
VWAP 比 TWAP 聪明一点。它不按时间均匀分配,而是按市场的成交量分布来分配。简单说:市场成交量大的时候,我多交易;成交量小的时候,我少交易。
你想想看,如果市场在开盘后 30 分钟成交量最大,那 VWAP 就会把更多的订单安排在这个时段。这样,我们的成交均价会更贴近市场的真实成交价。
为什么用 VWAP?
我记得有一次做 ETF 套利,需要快速建仓。如果用 TWAP,可能会在流动性枯竭的时候硬吃卖单,导致成本飙升。换成 VWAP 后,算法自动把订单集中在流动性好的时段,效果立竿见影。
实现代码
def vwap_schedule(total_qty, volume_profile):
"""
生成 VWAP 执行计划
:param total_qty: 总交易量
:param volume_profile: 历史成交量分布(列表,每个元素代表一个时间段的成交量)
:return: 每个时间点的目标交易量
"""
total_volume = sum(volume_profile)
schedule = []
for vol in volume_profile:
weight = vol / total_volume
schedule.append({
'target_qty': total_qty * weight
})
return schedule
# 示例:假设一天有 13 个半小时的成交量分布
volume_profile = [1000, 1500, 2000, 1800, 1200, 800, 600, 900, 1100, 1300, 1400, 1600, 1000]
schedule = vwap_schedule(100000, volume_profile)
print(f"第一个半小时交易量: {schedule[0]['target_qty']:.0f} 股")
4.3 POV:成交量百分比算法
原理
POV 的思路更直接:我不管时间,也不管历史分布,我就盯着当前市场的实时成交量。我设定一个百分比,比如 10%,然后我的交易量始终占市场成交量的 10%。
市场成交快,我就交易快;市场成交慢,我就交易慢。这是一种“自适应”的算法。
为什么用 POV?
嗯,这里要注意。POV 特别适合那些流动性变化剧烈的场景。比如小盘股,有时候 10 分钟没成交,突然来一笔大单。如果用 TWAP 或 VWAP,你可能会在没流动性的时候硬扛。POV 就不会,它会跟着市场节奏走。
实现代码
class POVExecutor:
def __init__(self, total_qty, pov_rate=0.1):
self.remaining_qty = total_qty
self.pov_rate = pov_rate
self.executed_qty = 0
def on_market_trade(self, market_volume):
"""
每次市场有成交时调用
:param market_volume: 当前周期的市场成交量
:return: 本次应交易的量
"""
if self.remaining_qty <= 0:
return 0
target = market_volume * self.pov_rate
actual = min(target, self.remaining_qty)
self.executed_qty += actual
self.remaining_qty -= actual
return actual
# 模拟使用
executor = POVExecutor(100000, pov_rate=0.05)
market_volumes = [2000, 1500, 3000, 2500, 1800] # 模拟市场成交量
for vol in market_volumes:
trade_qty = executor.on_market_trade(vol)
print(f"市场成交 {vol} 股,我交易 {trade_qty} 股,剩余 {executor.remaining_qty} 股")
| 算法 | 核心变量 | 适用场景 | 风险点 |
|---|---|---|---|
| TWAP | 时间 | 流动性稳定、波动小 | 流动性枯竭时硬吃 |
| VWAP | 历史成交量分布 | 有规律的大盘股 | 市场结构突变失效 |
| POV | 实时成交量 | 流动性变化剧烈 | 需要实时数据,延迟敏感 |
4.4 三者的核心逻辑关系
为了让你更直观地理解这三者的关系,我画了一张图。你可以看到,TWAP 是“时间驱动”,VWAP 是“历史数据驱动”,POV 是“实时数据驱动”。它们从不同维度解决了同一个问题:如何优雅地完成大额交易。
好了,这就是执行算法的第一课。TWAP、VWAP、POV 这三个算法,虽然简单,但它们是所有高级执行策略的基石。我建议你先把这三段代码跑通,感受一下它们的区别。下一章,我们会深入讨论如何在实际系统中选择和使用这些算法。