2. VWAP数据获取:从原始行情到可用序列
做量化交易,数据就是命根子。这话一点都不夸张。
我记得刚入行那会儿,有个策略回测表现特别好,实盘却一塌糊涂。查了三天,最后发现是数据对齐出了问题——分钟级行情里混进了几笔延迟成交的数据。嗯,从那以后,我对数据获取和清洗就格外较真。
今天咱们就聊聊VWAP策略的第一步:怎么拿到干净、对齐的分钟级数据,并算出日内VWAP序列。
2.1 分钟级行情数据的获取
说白了,VWAP计算需要两个核心字段:成交价和成交量。分钟级数据,就是每根K线里的开盘、最高、最低、收盘、成交量。
我个人习惯用Python的akshare或tushare来拉数据。不过要注意,免费接口的数据质量参差不齐,实盘前一定要做校验。
import pandas as pd
import akshare as ak
# 获取某只股票1分钟K线数据
def get_minute_data(symbol, date):
df = ak.stock_zh_a_minute(symbol=symbol, period='1', adjust='qfq')
# 筛选指定日期
df = df[df['日期'].str.contains(date)]
df.rename(columns={
'时间': 'time',
'开盘': 'open',
'最高': 'high',
'最低': 'low',
'收盘': 'close',
'成交量': 'volume'
}, inplace=True)
return df
2.2 数据清洗——别让脏数据毁了你的策略
你想想看,如果数据里混进一根成交量异常大的K线,VWAP曲线会瞬间跳变,策略可能就误判了。
我曾经遇到过一件事:某只股票在14:59突然出现一笔巨量成交,成交量是前一分钟的100倍。如果不处理,VWAP会被严重拉偏。
清洗步骤我一般分三步走:
- 缺失值处理: 检查时间戳是否连续,缺失的分钟用前值填充或插值
- 异常值检测: 成交量突变超过5倍标准差,标记为异常
- 价格合理性校验: 价格不能为负,不能超过涨跌停板
def clean_minute_data(df):
# 1. 检查时间连续性
df['time'] = pd.to_datetime(df['time'])
df.set_index('time', inplace=True)
full_index = pd.date_range(start=df.index[0], end=df.index[-1], freq='1min')
df = df.reindex(full_index)
# 2. 填充缺失值(用前向填充)
df.fillna(method='ffill', inplace=True)
# 3. 异常成交量检测
mean_vol = df['volume'].mean()
std_vol = df['volume'].std()
df.loc[df['volume'] > mean_vol + 5 * std_vol, 'volume'] = mean_vol
return df
2.3 数据对齐——不同数据源的时间同步
做量化的人都知道,不同交易所、不同数据源的时间戳可能差几毫秒。对于分钟级策略,这个误差可以忽略,但如果你做高频,这就是大问题。
我建议的做法是:统一以交易所的撮合时间戳为准。比如上交所的分钟K线,时间戳取该分钟最后一笔成交的时间。
| 数据源 | 时间戳格式 | 对齐方式 |
|---|---|---|
| 交易所原始行情 | YYYY-MM-DD HH:MM:SS.fff | 截断到分钟,取整 |
| 第三方数据商 | YYYY-MM-DD HH:MM:00 | 直接使用,校验连续性 |
| 回测平台数据 | 时间戳(毫秒) | 转换为datetime后对齐 |
2.4 计算日内VWAP序列
VWAP的计算公式其实很简单:
VWAP = Σ(价格 × 成交量) / Σ(成交量)
但日内VWAP序列是动态的——每过一分钟,就要把这一分钟的数据累加进去。说白了,就是滚动计算累计成交额除以累计成交量。
def calculate_vwap_series(df):
# 计算每分钟的成交额
df['turnover'] = df['close'] * df['volume']
# 累计成交额和累计成交量
df['cum_turnover'] = df['turnover'].cumsum()
df['cum_volume'] = df['volume'].cumsum()
# 计算VWAP
df['vwap'] = df['cum_turnover'] / df['cum_volume']
return df
2.5 数据存储与回放
数据存下来,是为了回测和复盘。我个人推荐用Parquet格式,压缩率高、读写快。CSV也行,但大文件加载慢。
# 存储为Parquet
df.to_parquet('vwap_data.parquet', index=False)
# 回放:模拟实时数据流
def replay_data(df):
for i in range(len(df)):
row = df.iloc[:i+1] # 模拟到当前分钟为止的数据
vwap = calculate_vwap_series(row)
yield vwap.iloc[-1]['vwap']
iloc[:i+1],而不是直接传整个df。否则就相当于用了未来数据,回测结果会虚高。我曾经犯过这个错,回测年化50%,实盘直接亏了三个月。
2.6 本章知识体系
下面这张图,把数据获取到VWAP计算的整个流程串起来了。你可以把它当作一个检查清单。
好了,数据获取这块就聊到这儿。记住一句话:数据质量决定策略上限。下一章咱们会基于这些数据,开始构建真正的VWAP交易信号。