🚀 AI 一键生成 qmt 策略代码

如何使用价格变动率(ROC)指标构建 QMT 动量交易策略?

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

问题描述

请帮我用 ROC 指标写一个动量策略,当 ROC 上穿零轴时买入,下穿时卖出。

解决方案

这是一个基于 QMT 平台的 ROC(变动率指标)动量策略实现。

策略逻辑

  1. ROC 计算公式:$ROC = \frac{今天的收盘价 - N天前的收盘价}{N天前的收盘价} \times 100$。
  2. 买入条件:ROC 线从下向上穿过 0 轴(即上一根 K 线 ROC < 0,当前 K 线 ROC > 0)。
  3. 卖出条件:ROC 线从上向下穿过 0 轴(即上一根 K 线 ROC > 0,当前 K 线 ROC < 0)。
  4. 仓位管理:信号触发时全仓买入或清仓卖出。

策略代码

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

def init(ContextInfo):
    """
    初始化函数,设定策略参数和账号
    """
    # 策略参数设置
    ContextInfo.N = 12  # ROC指标的周期,通常为12
    ContextInfo.account_id = '6000000000'  # 请在此处填写您的资金账号
    ContextInfo.account_type = 'STOCK'     # 账号类型:'STOCK'股票, 'FUTURE'期货
    
    # 绑定账号,用于接收交易回报(实盘必须)
    ContextInfo.set_account(ContextInfo.account_id)
    
    print("策略初始化完成,ROC周期: {}".format(ContextInfo.N))

def handlebar(ContextInfo):
    """
    K线周期运行函数
    """
    # 获取当前主图的股票代码
    stock_code = ContextInfo.stockcode
    
    # 确保是最后一根K线才下单(避免历史回测时的信号闪烁,实盘中通常只在最新K线判断)
    # 如果是回测模式,每一根K线都会运行;如果是实盘,ContextInfo.is_last_bar()为True时代表最新行情
    
    # 计算 ROC 需要 N 天前的数据,为了计算上一个 ROC(用于判断穿越),
    # 我们至少需要 N + 2 根 K 线的数据。这里取 N + 10 以防万一。
    count = ContextInfo.N + 10
    
    # 获取历史行情数据
    # 使用 get_market_data_ex 接口获取数据
    data_dict = ContextInfo.get_market_data_ex(
        ['close'],      # 获取收盘价
        [stock_code],   # 股票代码列表
        period=ContextInfo.period, # 跟随主图周期
        count=count,    # 获取数量
        dividend_type='front', # 前复权
        fill_data=True  # 停牌填充
    )
    
    # 检查数据是否获取成功
    if stock_code not in data_dict:
        return
        
    df = data_dict[stock_code]
    
    # 数据长度不足以计算 ROC 时直接返回
    if len(df) < ContextInfo.N + 2:
        return

    # 获取收盘价序列 (转换为 numpy 数组提高计算效率)
    closes = df['close'].values
    
    # --- 计算 ROC 指标 ---
    # 公式: ROC = (当前价格 - N天前价格) / N天前价格 * 100
    
    # 1. 计算当前的 ROC (对应 closes[-1])
    curr_price = closes[-1]
    curr_ref_price = closes[-1 - ContextInfo.N] # N天前的价格
    roc_curr = (curr_price - curr_ref_price) / curr_ref_price * 100
    
    # 2. 计算上一根K线的 ROC (对应 closes[-2]),用于判断交叉
    prev_price = closes[-2]
    prev_ref_price = closes[-2 - ContextInfo.N] # (N+1)天前的价格
    roc_prev = (prev_price - prev_ref_price) / prev_ref_price * 100
    
    # --- 交易逻辑 ---
    
    # 获取当前持仓
    # 注意:回测模式下可用 ContextInfo.get_position() 或类似逻辑,
    # 这里使用 order_target_percent 简化仓位管理,它会自动判断买卖方向
    
    # 信号 1: ROC 上穿 0 轴 (金叉) -> 买入
    if roc_prev < 0 and roc_curr > 0:
        print(f"[{stock_code}] ROC上穿0轴 (前值:{roc_prev:.2f}, 现值:{roc_curr:.2f}) -> 触发买入")
        # 调整仓位到 100% (全仓买入)
        order_target_percent(stock_code, 1.0, ContextInfo, ContextInfo.account_id)
        
    # 信号 2: ROC 下穿 0 轴 (死叉) -> 卖出
    elif roc_prev > 0 and roc_curr < 0:
        print(f"[{stock_code}] ROC下穿0轴 (前值:{roc_prev:.2f}, 现值:{roc_curr:.2f}) -> 触发卖出")
        # 调整仓位到 0% (清仓卖出)
        order_target_percent(stock_code, 0.0, ContextInfo, ContextInfo.account_id)

    # (可选) 在图表上画出 ROC 值,方便调试
    # ContextInfo.paint('ROC', roc_curr, -1, 0)

代码说明

  1. 编码格式:首行 # -*- coding: gbk -*- 是 QMT Python 策略必须的,防止中文乱码。
  2. 数据获取:使用了 ContextInfo.get_market_data_ex,这是 QMT 推荐的高效数据接口。我们获取了 N + 10 条数据,确保有足够的历史数据来计算当前的 ROC 和前一时刻的 ROC。
  3. ROC 计算
    • roc_curr:当前 K 线的 ROC 值。
    • roc_prev:前一根 K 线的 ROC 值。
    • 通过比较这两个值与 0 的关系,判断是否发生了“上穿”或“下穿”。
  4. 交易函数:使用了 order_target_percent。这是一个非常方便的高级函数:
    • 当目标比例为 1.0 时,系统会自动计算可用资金,买入直到满仓。
    • 当目标比例为 0.0 时,系统会自动卖出该股票的所有持仓。
  5. 账号设置:在 init 函数中,请务必将 ContextInfo.account_id 修改为您实际的资金账号。

如何运行

  1. 打开 QMT 客户端,进入“模型研究”或“策略编辑器”。
  2. 新建一个 Python 策略,将上述代码复制进去。
  3. 修改 init 函数中的 ContextInfo.account_id 为您的真实或模拟账号。
  4. 在右侧选择回测区间、基准和初始资金进行回测,或者在行情图上加载该策略进行实时运行

Q&A

Q: 如何修改 ROC 的周期参数?
A: 在代码的 init 函数中,修改 ContextInfo.N = 12 这一行,将 12 改为您想要的数字(例如 20 或 60)。

Q: 为什么使用 order_target_percent 而不是 passorder
A: order_target_percent 是封装好的高级函数,它自动处理了“当前持有多少股”、“需要买卖多少股才能达到目标仓位”的计算逻辑,非常适合这种趋势跟踪策略。如果您需要更精细的控制(如指定价格、指定手数),可以使用 passorder

Q: 这个策略可以用于期货吗?
A: 逻辑上可以,但需要修改下单函数。order_target_percent 主要用于股票。如果是期货,需要使用 buy_open (开多), sell_close (平多), sell_open (开空), buy_close (平空) 等函数,并且需要处理保证金和合约乘数。