3. 建仓成本核心算法:VWAP、TWAP 与成本区间估算
好,咱们直接进入正题。建仓成本分析,说白了就是回答一个问题:主力到底是在什么价位买的?
这个问题看着简单,但实际操作起来坑不少。我刚开始做量化那会儿,以为算个均价就完事了,结果回测怎么都对不上真实走势。后来才明白,不同场景要用不同的算法。
今天我把最常用的三种方法拆开讲:VWAP、TWAP 和 成本区间估算。每种方法我都会给出代码实现,并告诉你什么时候该用、什么时候别用。
3.1 成交量加权平均价格(VWAP)
VWAP 是机构交易中最常用的基准。它的逻辑很简单:用成交量做权重,算一个加权平均价。
公式长这样:
VWAP = Σ(价格 × 成交量) / Σ(成交量)
嗯,看着确实简单。但实际计算时有个细节——你得用逐笔成交数据,而不是分钟线或 tick 数据。为什么?因为逐笔数据能捕捉到每一笔真实的成交,而分钟线已经把细节抹平了。
来看代码实现:
import pandas as pd
import numpy as np
def calc_vwap(trade_data):
"""
计算逐笔成交的 VWAP
trade_data: DataFrame,必须包含 'price' 和 'volume' 列
"""
# 计算每笔的成交额
trade_data['turnover'] = trade_data['price'] * trade_data['volume']
# 累计成交额和累计成交量
cum_turnover = trade_data['turnover'].cumsum()
cum_volume = trade_data['volume'].cumsum()
# VWAP = 累计成交额 / 累计成交量
vwap = cum_turnover / cum_volume
return vwap
# 示例用法
df = pd.DataFrame({
'price': [10.0, 10.1, 10.05, 10.2, 10.15],
'volume': [100, 200, 150, 300, 250]
})
df['vwap'] = calc_vwap(df)
print(df)
关键点:VWAP 是累计值,不是瞬时值。每一笔的 VWAP 代表从开盘到当前时刻的加权平均成本。
我在项目中遇到过一个问题:有些行情数据会把大单拆成多笔小单,导致 VWAP 失真。解决办法是——先做大单合并,把同一时间戳、同一价格的连续成交合并成一笔。这个后面章节会细讲。
3.2 时间加权平均价格(TWAP)
TWAP 是另一种思路。它不考虑成交量,只考虑时间。说白了就是:把交易时段等分成 N 个区间,每个区间取一个价格,然后算平均。
公式:
TWAP = (P1 + P2 + ... + Pn) / n
其中 Pi 是第 i 个时间区间的价格(通常用收盘价或中间价)。
你可能会问:既然 VWAP 已经能算成本了,为什么还要 TWAP?
原因很简单——当成交量数据不可靠时。比如某些品种的逐笔成交数据缺失严重,或者交易所只提供分钟线。这时候 VWAP 算出来就是错的,TWAP 反而更稳定。
代码实现:
def calc_twap(trade_data, interval='1min'):
"""
计算时间加权平均价格
trade_data: DataFrame,必须包含 'price' 和 'time' 列
interval: 时间区间,默认1分钟
"""
# 按时间区间分组,取每个区间的收盘价
twap_series = trade_data.resample(interval, on='time')['price'].last()
# 去掉空值
twap_series = twap_series.dropna()
# 计算平均值
twap = twap_series.mean()
return twap
# 示例用法
df['time'] = pd.date_range('2024-01-01 09:30:00', periods=5, freq='1min')
twap_value = calc_twap(df)
print(f'TWAP: {twap_value:.4f}')
个人经验:TWAP 适合用在流动性差的品种上。比如某些小盘股,一天就成交几十笔,VWAP 算出来波动极大。这时候用 TWAP 反而能反映真实的市场成本。
3.3 成本区间估算
VWAP 和 TWAP 给的都是一个点。但主力的建仓成本往往是一个区间,而不是一个精确的数值。
为什么?因为主力不会在一个价位上把所有货都买完。他们会分批建仓,在不同价位上买入不同数量。所以我们需要估算一个成本区间,比如「主力成本在 10.2 到 10.8 之间」。
常用的方法有两种:
- 分位数法:取成交量的分位数,比如 20% 分位和 80% 分位对应的价格。
- 聚类法:用 K-Means 或 DBSCAN 把成交价格聚类,找出主要的成交价格带。
先看分位数法的实现:
def cost_interval_quantile(trade_data, lower=0.2, upper=0.8):
"""
基于成交量分位数的成本区间估算
trade_data: DataFrame,包含 'price' 和 'volume'
lower: 下分位数,默认0.2
upper: 上分位数,默认0.8
"""
# 按价格排序
sorted_data = trade_data.sort_values('price')
# 计算累计成交量占比
sorted_data['cum_vol_pct'] = sorted_data['volume'].cumsum() / sorted_data['volume'].sum()
# 找到分位数对应的价格
lower_price = sorted_data[sorted_data['cum_vol_pct'] >= lower]['price'].iloc[0]
upper_price = sorted_data[sorted_data['cum_vol_pct'] >= upper]['price'].iloc[0]
return lower_price, upper_price
# 示例
lower, upper = cost_interval_quantile(df)
print(f'成本区间: [{lower:.2f}, {upper:.2f}]')
聚类法稍微复杂一点,但效果更好。它能自动识别出多个成本密集区:
from sklearn.cluster import KMeans
def cost_interval_cluster(trade_data, n_clusters=3):
"""
基于聚类的成本区间估算
trade_data: DataFrame,包含 'price' 和 'volume'
n_clusters: 聚类数量
"""
# 准备数据:用价格和成交量作为特征
X = trade_data[['price', 'volume']].values
# K-Means 聚类
kmeans = KMeans(n_clusters=n_clusters, random_state=42)
trade_data['cluster'] = kmeans.fit_predict(X)
# 计算每个聚类的加权平均价格
clusters = []
for i in range(n_clusters):
cluster_data = trade_data[trade_data['cluster'] == i]
vwap = (cluster_data['price'] * cluster_data['volume']).sum() / cluster_data['volume'].sum()
clusters.append(vwap)
# 返回排序后的聚类中心价格
return sorted(clusters)
# 示例
clusters = cost_interval_cluster(df)
print(f'成本密集区: {[f"{c:.2f}" for c in clusters]}')
避坑指南:我曾经在分析一只庄股时,直接用分位数法算成本区间,结果发现区间特别窄。后来一查,原来是主力用对倒单制造了虚假成交量。所以记住——任何算法都要先做数据清洗,把对倒单、自成交这些垃圾数据去掉。
3.4 三种方法的对比与选择
我把这三种方法的特点整理成了一张表,方便你对照:
| 方法 | 核心逻辑 | 适用场景 | 局限性 |
|---|---|---|---|
| VWAP | 成交量加权 | 逐笔数据完整、流动性好 | 受大单影响大 |
| TWAP | 时间加权 | 数据缺失、流动性差 | 忽略成交量信息 |
| 成本区间 | 分位数/聚类 | 需要成本范围而非单点 | 参数选择影响结果 |
我个人习惯是:先用 VWAP 算基准,再用成本区间做验证。如果两者差距很大,说明数据可能有问题,或者市场结构发生了异常变化。
你想想看,如果 VWAP 是 10.5,但成本区间显示 80% 的成交量集中在 10.2-10.4,那说明什么?说明有大量成交在低价区,VWAP 被高价单拉高了。这时候我会更相信成本区间给出的结论。
3.5 知识体系总览
下面这张图把本章的核心逻辑串起来了。你可以看到三种方法之间的关系,以及在实际分析中如何组合使用:
这张图的核心思想是:不要依赖单一算法。VWAP 和 TWAP 给出的是「点」,成本区间给出的是「面」。把点和面结合起来,才能更准确地判断主力的真实建仓成本。
嗯,以上就是建仓成本核心算法的全部内容。代码可以直接拿去用,但记得根据你的数据格式做适当调整。下一章我们会聊如何把这些算法应用到实战中,识别主力的建仓痕迹。
公众号:蓝海资料掘金营,微信deep3321