🚀 AI 一键生成 qmt 策略代码

改进传统指标:成交量加权 MACD 的 Python 实现

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

问题描述

如何编写成交量加权的 MACD 指标?

解决方案

成交量加权 MACD(VW-MACD)是一种将成交量因素纳入考量的趋势指标。与传统 MACD 仅使用收盘价计算 EMA 不同,VW-MACD 通常使用**成交量加权移动平均(VWMA)**来替代普通的指数移动平均(EMA)。

这种方法认为,成交量大的价格变动比成交量小的变动更具市场意义。

策略设计思路

  1. 数据获取:获取收盘价(Close)和成交量(Volume)。
  2. 计算 PV:计算每日的 价格 * 成交量
  3. 计算 VWMA
    • 分别计算短期(如12日)和长期(如26日)的 VWMA。
    • 公式:$VWMA_n = \frac{\sum_{i=1}^{n}(Price_i \times Volume_i)}{\sum_{i=1}^{n}(Volume_i)}$
  4. 计算 DIF:$DIF = VWMA_{short} - VWMA_{long}$。
  5. 计算 DEA:对 DIF 进行平滑处理(通常使用 9日 EMA)。
  6. 计算 MACD 柱:$(DIF - DEA) \times 2$。
  7. 绘图:使用 ContextInfo.paint 将指标绘制在副图上。

QMT 策略代码实现

以下是完整的 Python 代码,您可以直接复制到 QMT 的策略编辑器中运行。

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

def init(ContextInfo):
    """
    初始化函数
    """
    # 定义 MACD 的周期参数
    ContextInfo.short_len = 12  # 短期周期
    ContextInfo.long_len = 26   # 长期周期
    ContextInfo.mid_len = 9     # DEA 平滑周期
    
    # 设置绘图位置为副图
    # 注意:在 QMT 界面上运行模型时,请确保选择“副图”显示
    print("VW-MACD 策略初始化完成")

def handlebar(ContextInfo):
    """
    K线周期回调函数
    """
    # 获取当前主图的股票代码和市场
    # 格式如 '600000.SH'
    stock_code = ContextInfo.stockcode + '.' + ContextInfo.market
    
    # 获取历史数据
    # 为了保证计算的准确性,我们需要获取足够多的历史数据来消除移动平均的滞后影响
    # count=300 表示获取当前时刻往前推 300 根K线
    data = ContextInfo.get_market_data_ex(
        ['close', 'volume'], 
        [stock_code], 
        period=ContextInfo.period, 
        count=300, 
        dividend_type=ContextInfo.dividend_type
    )
    
    # 校验数据是否获取成功
    if stock_code not in data:
        return
        
    df = data[stock_code]
    
    # 如果数据长度不足以计算长期均线,则直接返回
    if len(df) < ContextInfo.long_len:
        return

    # --- 核心计算逻辑:成交量加权 MACD (VW-MACD) ---
    
    # 1. 计算 PV (价格 * 成交量)
    # 这是计算 VWMA 的分子部分
    df['pv'] = df['close'] * df['volume']
    
    # 2. 计算 VWMA (成交量加权移动平均)
    # 公式:RollingSum(Price * Volume, N) / RollingSum(Volume, N)
    
    # 计算短期 VWMA
    df['vol_sum_short'] = df['volume'].rolling(window=ContextInfo.short_len).sum()
    df['pv_sum_short'] = df['pv'].rolling(window=ContextInfo.short_len).sum()
    df['vwma_short'] = df['pv_sum_short'] / df['vol_sum_short']
    
    # 计算长期 VWMA
    df['vol_sum_long'] = df['volume'].rolling(window=ContextInfo.long_len).sum()
    df['pv_sum_long'] = df['pv'].rolling(window=ContextInfo.long_len).sum()
    df['vwma_long'] = df['pv_sum_long'] / df['vol_sum_long']
    
    # 3. 计算 DIF (快线 - 慢线)
    # 这里使用 VWMA 替代了传统 MACD 中的 EMA
    df['dif'] = df['vwma_short'] - df['vwma_long']
    
    # 4. 计算 DEA (DIF 的 EMA 平滑)
    # 信号线通常依然使用 EMA 算法进行平滑
    df['dea'] = df['dif'].ewm(span=ContextInfo.mid_len, adjust=False).mean()
    
    # 5. 计算 MACD 柱状值
    df['macd'] = (df['dif'] - df['dea']) * 2
    
    # --- 绘图输出 ---
    
    # 获取当前 K 线(最新一根)的指标值
    current_dif = df['dif'].iloc[-1]
    current_dea = df['dea'].iloc[-1]
    current_macd = df['macd'].iloc[-1]
    
    # 处理 NaN 值(刚开始计算时可能为空),避免绘图报错
    if np.isnan(current_dif) or np.isnan(current_dea) or np.isnan(current_macd):
        return

    # 绘制 DIF (白线)
    # index=-1 表示在当前 K 线位置绘制
    # line_style=0 表示曲线
    ContextInfo.paint('VW_DIF', current_dif, -1, 0, 'white')
    
    # 绘制 DEA (黄线)
    ContextInfo.paint('VW_DEA', current_dea, -1, 0, 'yellow')
    
    # 绘制 MACD 柱状图
    # 根据正负值设置颜色:大于0为红色,小于0为绿色
    color = 'red' if current_macd > 0 else 'green'
    # line_style=42 表示柱状线
    ContextInfo.paint('VW_MACD', current_macd, -1, 42, color)

    # 可选:在图表左上角显示数值
    # msg = f"VW-MACD: DIF={current_dif:.3f} DEA={current_dea:.3f} MACD={current_macd:.3f}"
    # ContextInfo.draw_text(True, current_dif, msg)

代码关键点解析

  1. VWMA 替代 EMA

    • 传统 MACD 使用 df['close'].ewm(span=N).mean()
    • 本代码使用 rolling(N).sum() 计算周期内的总成交额和总成交量,相除得到 VWMA。这更能反映资金的真实平均成本。
  2. 数据预热 (count=300)

    • MACD 类指标依赖历史数据。如果在 get_market_data_ex 中获取的数据太少(例如只获取最近 1 根),会导致无法计算均线或计算结果不准确。建议至少获取 long_len * 3 长度的数据。
  3. 绘图函数 (paint)

    • ContextInfo.paint(name, value, index, line_style, color) 是 QMT 专用的绘图接口。
    • index=-1 确保数值绘制在当前 K 线的时间点上。
    • line_style=42 专门用于绘制类似 MACD 红绿柱的柱状图。

如何使用

  1. 打开 QMT 客户端,进入模型研究/策略编辑器
  2. 新建一个 Python 策略
  3. 将上述代码粘贴进去。
  4. 在右侧属性栏中,将运行位置设置为 “副图”
  5. 点击运行回测,即可在下方副图看到成交量加权的 MACD 指标。

Q&A

Q: 为什么要用成交量加权 MACD?
A: 传统 MACD 仅基于价格,可能会在缩量上涨(诱多)或缩量下跌时发出虚假信号。成交量加权 MACD 考虑了成交量,只有在成交量配合下的价格变动才会显著推动指标,因此能更好地过滤市场噪音,确认趋势的有效性。

Q: 代码中的 get_market_data_ex 为什么使用 count=300
A: 移动平均线(MA)和指数平滑(EMA)都需要一定长度的历史数据才能计算出结果。如果只取当前一根 K 线的数据,无法计算出 26 日均线。取 300 根是为了确保有足够的历史数据来生成稳定的指标值。

Q: 这个指标可以用于回测交易吗?
A: 可以。您可以在 handlebar 函数中添加交易逻辑。例如:

# 金叉买入
if current_dif > current_dea and df['dif'].iloc[-2] <= df['dea'].iloc[-2]:
    passorder(23, 1101, ContextInfo.accid, stock_code, 5, -1, 100, ContextInfo)