🚀 AI 一键生成 qmt 策略代码

如何在 QMT 中实现多周期共振交易策略?

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

问题描述

请帮我编写一个多周期交易策略,在日线看涨时,根据5分钟线的信号进行买入操作。

解决方案

这是一个非常经典的多周期共振策略。在量化交易中,通常的做法是在小周期(如5分钟)上运行策略,同时在代码中获取大周期(如日线)的数据来进行趋势过滤。

策略逻辑设计

  1. 运行周期:策略挂载在 5分钟 K线上运行。
  2. 大周期判断(日线)
    • 获取日线数据。
    • 判断逻辑:当前价格 > 日线20日均线(MA20),视为日线看涨趋势。
  3. 小周期信号(5分钟)
    • 获取5分钟数据。
    • 判断逻辑:5分钟 MA5 上穿 MA10(金叉),视为买入信号。
    • 卖出逻辑(可选):5分钟 MA5 下穿 MA10(死叉)进行平仓。
  4. 交易执行
    • 当“日线看涨”且“5分钟金叉”且“当前无持仓”时,买入。
    • 当“5分钟死叉”且“有持仓”时,卖出。

QMT 策略代码实现

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

def init(ContextInfo):
    """
    初始化函数,设定账户、股票池和参数
    """
    # 1. 设置资金账号 (请替换为您自己的资金账号)
    ContextInfo.accID = '6000000000' 
    ContextInfo.set_account(ContextInfo.accID)
    
    # 2. 设置要交易的股票 (示例:平安银行)
    ContextInfo.stock_code = '000001.SZ'
    ContextInfo.set_universe([ContextInfo.stock_code])
    
    # 3. 策略参数设置
    ContextInfo.trade_qty = 1000       # 每次买入数量
    ContextInfo.day_ma_len = 20        # 日线趋势均线周期
    ContextInfo.min_ma_short = 5       # 5分钟短均线
    ContextInfo.min_ma_long = 10       # 5分钟长均线
    
    # 4. 周期设置
    ContextInfo.period_day = '1d'      # 大周期:日线
    ContextInfo.period_min = '5m'      # 小周期:5分钟

def get_position(ContextInfo, stock_code):
    """
    辅助函数:获取指定股票的持仓数量
    """
    # 获取持仓列表
    positions = get_trade_detail_data(ContextInfo.accID, 'stock', 'position')
    for pos in positions:
        # QMT返回的持仓对象中,证券代码通常不带后缀,需要注意匹配
        # 这里使用 m_strInstrumentID + '.' + m_strExchangeID 拼接成完整代码
        pos_code = pos.m_strInstrumentID + '.' + pos.m_strExchangeID
        if pos_code == stock_code:
            return pos.m_nVolume
    return 0

def handlebar(ContextInfo):
    """
    核心逻辑函数,每根K线(5分钟)执行一次
    """
    # 获取当前正在处理的股票代码
    stock = ContextInfo.stock_code
    
    # ----------------------------------------------------------------
    # 第一步:获取日线数据,判断大趋势
    # ----------------------------------------------------------------
    # 获取足够计算MA20的日线数据,count设大一点防止停牌等导致数据不足
    day_data = ContextInfo.get_market_data_ex(
        ['close'], 
        [stock], 
        period=ContextInfo.period_day, 
        count=ContextInfo.day_ma_len + 5, 
        dividend_type='front', 
        subscribe=True
    )
    
    if stock not in day_data or len(day_data[stock]) < ContextInfo.day_ma_len:
        # 数据不足,跳过
        return

    df_day = day_data[stock]
    # 计算日线 MA20
    df_day['ma20'] = df_day['close'].rolling(window=ContextInfo.day_ma_len).mean()
    
    # 获取最新的日线收盘价和均线值
    last_day_close = df_day['close'].iloc[-1]
    last_day_ma20 = df_day['ma20'].iloc[-1]
    
    # 判断日线趋势:价格在20日均线之上为看涨
    is_day_bullish = last_day_close > last_day_ma20

    # ----------------------------------------------------------------
    # 第二步:获取5分钟数据,判断入场信号
    # ----------------------------------------------------------------
    min_data = ContextInfo.get_market_data_ex(
        ['close'], 
        [stock], 
        period=ContextInfo.period_min, 
        count=ContextInfo.min_ma_long + 5, 
        dividend_type='front', 
        subscribe=True
    )
    
    if stock not in min_data or len(min_data[stock]) < ContextInfo.min_ma_long:
        return

    df_min = min_data[stock]
    # 计算5分钟均线
    df_min['ma_short'] = df_min['close'].rolling(window=ContextInfo.min_ma_short).mean()
    df_min['ma_long'] = df_min['close'].rolling(window=ContextInfo.min_ma_long).mean()
    
    # 获取当前和上一根K线的均线值(用于判断交叉)
    curr_short = df_min['ma_short'].iloc[-1]
    curr_long = df_min['ma_long'].iloc[-1]
    prev_short = df_min['ma_short'].iloc[-2]
    prev_long = df_min['ma_long'].iloc[-2]
    
    # 判断金叉:上一根短线<=长线,且当前短线>长线
    is_golden_cross = (prev_short <= prev_long) and (curr_short > curr_long)
    # 判断死叉:上一根短线>=长线,且当前短线<长线
    is_death_cross = (prev_short >= prev_long) and (curr_short < curr_long)
    
    # 获取最新价格用于下单
    current_price = df_min['close'].iloc[-1]

    # ----------------------------------------------------------------
    # 第三步:交易执行
    # ----------------------------------------------------------------
    # 获取当前持仓
    curr_pos = get_position(ContextInfo, stock)
    
    # 买入逻辑:日线看涨 + 5分钟金叉 + 无持仓
    if is_day_bullish and is_golden_cross and curr_pos == 0:
        print(f"【买入信号】{stock} 日线看涨(价格:{last_day_close:.2f}>MA20:{last_day_ma20:.2f}), 5分钟金叉")
        # 使用 order_shares 下单指定股数
        order_shares(stock, ContextInfo.trade_qty, 'fix', current_price, ContextInfo, ContextInfo.accID)
    
    # 卖出逻辑:5分钟死叉 + 有持仓 (这里只看小周期信号平仓,也可加入日线趋势反转平仓)
    elif is_death_cross and curr_pos > 0:
        print(f"【卖出信号】{stock} 5分钟死叉,执行平仓")
        order_shares(stock, -curr_pos, 'fix', current_price, ContextInfo, ContextInfo.accID)

使用说明

  1. 设置运行周期:在 QMT 界面运行此策略时,请务必将主图周期设置为 5分钟(或者您希望捕捉信号的小周期)。
  2. 账号设置:请将代码中的 ContextInfo.accID = '6000000000' 修改为您实际的资金账号。
  3. 数据补充
    • 在运行或回测前,请确保已下载了对应股票的 日线5分钟线 的历史数据。
    • QMT 菜单 -> 数据管理 -> 补充数据。
  4. API 选择
    • 代码使用了 get_market_data_ex,这是 QMT 推荐的高效数据接口,支持订阅实时行情。
    • 使用了 order_shares 进行下单,fix 代表限价单(以当前最新价下单),如果需要市价单可改为 market(注意回测和实盘的区别)。

常见问题 (Q&A)

Q: 为什么要在5分钟周期上运行,而不是日线周期?
A: 因为买入信号是基于5分钟均线金叉触发的。如果在日线周期上运行,handlebar 函数每天只会在收盘时调用一次,无法捕捉盘中的5分钟级别信号。

Q: get_market_data_ex 中的 subscribe=True 是什么意思?
A: 这表示订阅数据。在实盘模式下,当有新的行情推送过来时,QMT 会自动更新数据并触发策略计算,保证信号的实时性。

Q: 如何修改“日线看涨”的定义?
A: 您可以修改代码中 is_day_bullish 的计算逻辑。例如,改为“日线 MA5 > 日线 MA10”:

# 计算日线 MA5 和 MA10
df_day['ma5'] = df_day['close'].rolling(window=5).mean()
df_day['ma10'] = df_day['close'].rolling(window=10).mean()
is_day_bullish = df_day['ma5'].iloc[-1] > df_day['ma10'].iloc[-1]