🚀 AI 一键生成 qmt 策略代码

QMT 策略编程:如何在策略中计算并绘制日内实时 VWAP 均线?

qmt | 发布时间: 2025/12/31
以下内容由 EasyQuant 生成。

问题描述

怎么在 QMT 策略里计算实时的 VWAP 指标?

解决方案

在 QMT(Quantitative Market Trading)策略中计算实时 VWAP(成交量加权平均价),最准确且高效的方法是利用Tick 数据中的累计成交额和累计成交量进行计算。

核心逻辑

VWAP 的定义是:
$$ \text{VWAP} = \frac{\text{当日累计成交额 (Total Amount)}}{\text{当日累计成交量 (Total Volume)}} $$

在 QMT 的 ContextInfo.get_full_tick() 接口返回的数据中,交易所直接提供了截止到当前时刻的累计成交额累计成交量。因此,我们不需要自己去累加每一个 Tick 的数据,直接相除即可得到最精确的实时 VWAP。

代码实现

以下是一个完整的策略代码示例。该策略会在图表上实时计算并绘制 VWAP 曲线,同时在日志中打印数值。

# -*- coding: gbk -*-
import pandas as pd

def init(ContextInfo):
    # 设置要操作的股票,这里以浦发银行为例
    ContextInfo.stock = '600000.SH'
    # 设置股票池
    ContextInfo.set_universe([ContextInfo.stock])
    # 设置运行周期,建议在分笔(Tick)或1分钟周期下运行以观察实时效果
    ContextInfo.period = '1m'

def handlebar(ContextInfo):
    # 获取当前主图或设置的股票代码
    stock_code = ContextInfo.stock
    
    # 1. 获取最新的 Tick 数据
    # get_full_tick 返回的是一个字典,key是股票代码,value是数据字典
    tick_data = ContextInfo.get_full_tick([stock_code])
    
    # 检查是否成功获取数据
    if not tick_data or stock_code not in tick_data:
        return

    current_tick = tick_data[stock_code]

    # 2. 提取累计成交额和累计成交量
    # amount: 成交额 (元)
    # pvolume: 成交总量 (股) -> 注意:这里使用 pvolume (股数) 而不是 volume (手),以保证精度
    total_amount = current_tick.get('amount', 0.0)
    total_volume = current_tick.get('pvolume', 0.0)

    # 3. 计算 VWAP
    # 避免除以零(例如开盘前或刚开盘无成交时)
    if total_volume > 0:
        vwap = total_amount / total_volume
    else:
        # 如果没有成交量,可以用昨收盘价或开盘价暂代,或者设为0
        vwap = current_tick.get('lastClose', 0.0)

    # 4. 打印输出
    # 获取当前时间戳并转换格式方便阅读
    timetag = ContextInfo.get_tick_timetag()
    time_str = timetag_to_datetime(timetag, '%Y-%m-%d %H:%M:%S')
    
    print(f"时间: {time_str} | 代码: {stock_code} | 累计成交额: {total_amount:.2f} | 累计成交量(股): {total_volume} | 实时 VWAP: {vwap:.4f}")

    # 5. 在图表上绘制 VWAP 曲线 (仅在回测或界面运行时有效)
    # 第一个参数是指标名称,第二个是数值,第三个-1代表主图,第四个0代表曲线,颜色为黄色
    ContextInfo.paint('VWAP', vwap, -1, 0, 'yellow')

    # 可以在这里添加基于 VWAP 的交易逻辑
    # 例如:如果最新价低于 VWAP 一定比例则买入
    # last_price = current_tick.get('lastPrice')
    # if last_price < vwap * 0.99:
    #     pass # 执行买入逻辑

代码详解

  1. get_full_tick 接口

    • 这是获取实时快照数据的核心函数。
    • 它返回的 amount当日累计成交额(单位:元)。
    • 它返回的 pvolume当日累计成交量(单位:股)。注意不要混淆 volume(通常单位是手),计算价格时必须用“元/股”。
  2. 除零保护

    • 在早盘集合竞价阶段或极不活跃的标的中,成交量可能为 0。代码中加入了 if total_volume > 0 的判断,防止程序报错。
  3. paint 函数

    • 用于在 QMT 的 K 线图上画线。将 VWAP 画在主图上(参数 -1),可以直观地对比当前价格与 VWAP 的关系。
  4. 适用模式

    • 实盘/模拟交易:此逻辑完全适用,数据随行情实时推送更新。
    • 回测模式get_full_tick 在回测中通常只能获取到当前 Bar 的切片数据(如果回测精度不够高)。如果在回测中需要高精度的 VWAP,建议使用 get_market_data_ex 获取分钟线数据,通过 cumsum() 累加当天的成交额和成交量来模拟计算。

进阶:如何在回测中计算历史 VWAP?

如果你是在做历史回测(而不是实盘监控),且使用的是分钟线(如 1m, 5m),则不能依赖 get_full_tick(因为它只返回最新快照)。你需要利用 Pandas 对当天的分钟数据进行累加。

回测专用 VWAP 计算代码:

# -*- coding: gbk -*-
import pandas as pd

def init(ContextInfo):
    ContextInfo.stock = '600000.SH'
    ContextInfo.set_universe([ContextInfo.stock])
    ContextInfo.period = '1m' # 必须是日内周期

def handlebar(ContextInfo):
    # 获取当前 Bar 的时间
    current_time = timetag_to_datetime(ContextInfo.get_bar_timetag(ContextInfo.barpos), '%Y%m%d')
    
    # 获取当天的所有分钟数据(从当天开盘到现在)
    # 注意:这里简化处理,实际回测中需要获取当天09:30到当前barpos的数据
    # 在QMT回测引擎中,通常我们取过去一定数量的bar,然后按日期过滤
    
    # 获取过去240根K线(覆盖一天4小时)
    df = ContextInfo.get_market_data_ex(
        ['amount', 'volume'], 
        [ContextInfo.stock], 
        period=ContextInfo.period, 
        count=240, 
        dividend_type='none'
    )[ContextInfo.stock]
    
    # 转换索引为字符串日期格式以便筛选
    df.index = df.index.astype(str)
    
    # 筛选出属于“今天”的数据
    # 假设 current_time 格式为 '20231027'
    today_df = df[df.index.str.startswith(current_time)]
    
    if not today_df.empty:
        # 计算累计成交额和累计成交量
        # 注意:分钟线里的 volume 通常是手,需要乘以 100 变成股
        # 但 amount 是元。 VWAP = Sum(Amount) / (Sum(Volume_in_hands) * 100)
        
        cum_amount = today_df['amount'].sum()
        cum_volume = today_df['volume'].sum() * 100 # 转换为股
        
        if cum_volume > 0:
            vwap = cum_amount / cum_volume
            ContextInfo.paint('VWAP_Backtest', vwap, -1, 0, 'cyan')

总结

  • 实盘/实时监控:请使用第一种基于 get_full_tick 的方法,这是最简单且计算量最小的方案,直接利用了交易所推送的累计数据。
  • 历史回测:请使用第二种基于 get_market_data_ex 并配合 sum()cumsum() 的方法。

Q&A

Q: 为什么计算出来的 VWAP 和某些看盘软件上的有一点点误差?
A: 误差通常来源于“成交量单位”的处理。QMT 的 pvolume 是股数,volume 是手。如果软件A使用手计算而忽略了零股(不足一手的部分),或者对 amount 的精度处理不同,会导致微小差异。使用 amount / pvolume 是最标准的定义。

Q: 这个策略能用于期货吗?
A: 可以。但需要注意期货的 volume 单位通常就是“手”,且期货没有“股”的概念。对于期货,直接使用 amount / volume 即可,但需确认 amount 是否为合约价值(通常期货行情中的 amount 是成交金额,计算 VWAP 逻辑一致)。此外,期货还需要考虑合约乘数的问题,但在计算均价时,分子分母同比例变化,直接相除通常即可得到单价。

Q: get_full_tick 在回测模式下返回什么?
A: 在回测模式下,get_full_tick 返回的是当前回测时间点所在 K 线的收盘时的快照数据(如果是日线回测,就是当日收盘快照)。它无法在日线回测中模拟出盘中的动态变化。因此回测日内策略必须使用分钟周期。