2. VWAP数据获取:从原始行情到可用序列

做量化交易,数据就是命根子。这话一点都不夸张。

我记得刚入行那会儿,有个策略回测表现特别好,实盘却一塌糊涂。查了三天,最后发现是数据对齐出了问题——分钟级行情里混进了几笔延迟成交的数据。嗯,从那以后,我对数据获取和清洗就格外较真。

今天咱们就聊聊VWAP策略的第一步:怎么拿到干净、对齐的分钟级数据,并算出日内VWAP序列。

2.1 分钟级行情数据的获取

说白了,VWAP计算需要两个核心字段:成交价和成交量。分钟级数据,就是每根K线里的开盘、最高、最低、收盘、成交量。

我个人习惯用Python的aksharetushare来拉数据。不过要注意,免费接口的数据质量参差不齐,实盘前一定要做校验。

核心要点: 分钟级数据必须包含时间戳、开盘价、最高价、最低价、收盘价、成交量。缺一不可。
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
我的小技巧: 拉数据时多拉一天,用来做前一天的VWAP参考线。很多策略需要对比当日VWAP和昨日VWAP的偏离度。

2.2 数据清洗——别让脏数据毁了你的策略

你想想看,如果数据里混进一根成交量异常大的K线,VWAP曲线会瞬间跳变,策略可能就误判了。

我曾经遇到过一件事:某只股票在14:59突然出现一笔巨量成交,成交量是前一分钟的100倍。如果不处理,VWAP会被严重拉偏。

清洗步骤我一般分三步走:

  1. 缺失值处理: 检查时间戳是否连续,缺失的分钟用前值填充或插值
  2. 异常值检测: 成交量突变超过5倍标准差,标记为异常
  3. 价格合理性校验: 价格不能为负,不能超过涨跌停板
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
注意: 不要直接删除异常数据!我曾经删掉一根异常K线,结果导致时间序列不连续,后续计算全部错位。建议用均值或中位数替换。

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
关键点: VWAP是从开盘开始累加的。如果你在盘中接入数据,需要从当天第一分钟开始重新计算,不能直接用历史VWAP值。

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数据获取与处理流程 步骤1:数据获取 分钟级行情API 步骤2:数据清洗 缺失值·异常值 步骤3:数据对齐 时间戳统一 步骤4 VWAP计算 数据存储 Parquet / CSV 数据回放 模拟实时流 日内VWAP序列 用于策略信号生成 数据质量决定策略上限,清洗对齐是基本功 获取 清洗 对齐 计算 存储 回放

好了,数据获取这块就聊到这儿。记住一句话:数据质量决定策略上限。下一章咱们会基于这些数据,开始构建真正的VWAP交易信号。

专注资料整理