🚀 AI 一键生成 qmt 策略代码

QMT 平台如何实现经典的 R-Breaker 日内反转与突破策略?

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

问题描述

请帮我编写一个 R-Breaker 交易策略

解决方案

这是一个基于 QMT Python API 实现的 R-Breaker 交易策略。

R-Breaker 是一种经典的日内交易策略,结合了趋势跟踪(突破交易)和均值回归(反转交易)两种逻辑。它根据前一个交易日的最高价、最低价和收盘价计算出 6 个关键价位,以此来决定当天的交易信号。

策略逻辑简介

  1. 计算关键价位(基于昨日数据):

    • Pivot (枢轴点) = (High + Low + Close) / 3
    • Bbreak (突破买入价) = High + 2 * (Pivot - Low)
    • Ssetup (观察卖出价) = Pivot + (High - Low)
    • Senter (反转卖出价) = 2 * Pivot - Low
    • Benter (反转买入价) = 2 * Pivot - High
    • Bsetup (观察买入价) = Pivot - (High - Low)
    • Sbreak (突破卖出价) = Low - 2 * (High - Pivot)
  2. 交易信号:

    • 趋势策略(突破):
      • 若价格 > Bbreak,开多单。
      • 若价格 < Sbreak,开空单。
    • 反转策略:
      • 若日内最高价 > Ssetup 且 价格跌破 Senter,开空单(做空)。
      • 若日内最低价 < Bsetup 且 价格突破 Benter,开多单(做多)。
  3. 风控与退出:

    • 日内策略,收盘前(如 14:55)强制平仓。

QMT 策略代码实现

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

def init(ContextInfo):
    # ================= 策略参数设置 =================
    # 交易标的:这里以沪深300股指期货主力合约为例
    # 如果是股票,请修改为股票代码,如 '600000.SH'
    ContextInfo.stock = 'IF00.IF' 
    
    # 资金账号 (请修改为您自己的实盘或模拟账号)
    ContextInfo.account_id = 'YOUR_ACCOUNT_ID'
    # 账号类型:'FUTURE' (期货), 'STOCK' (股票)
    ContextInfo.account_type = 'FUTURE'
    
    # 策略运行周期,建议 1分钟 或 5分钟
    ContextInfo.period = '1m'
    
    # 设置股票池
    ContextInfo.set_universe([ContextInfo.stock])
    
    # 绑定账号 (实盘/模拟盘必须)
    ContextInfo.set_account(ContextInfo.account_id)
    
    # 每日收盘平仓时间 (格式 HHMM)
    ContextInfo.close_time = "1455"
    
    # 记录当前持仓状态: 0-空仓, 1-多头, -1-空头
    ContextInfo.position_status = 0 

def handlebar(ContextInfo):
    # 获取当前K线索引
    index = ContextInfo.barpos
    # 获取当前时间戳
    timetag = ContextInfo.get_bar_timetag(index)
    # 转换为时间字符串 HHMM
    current_time = timetag_to_datetime(timetag, '%H%M')
    
    # ================= 1. 每日收盘强平逻辑 =================
    if current_time >= ContextInfo.close_time:
        if ContextInfo.position_status != 0:
            print(f"尾盘强平: {current_time}")
            close_position(ContextInfo)
        return

    # ================= 2. 获取数据 =================
    stock = ContextInfo.stock
    
    # 获取日线数据(取过去2根,index=-2为昨日,index=-1为今日)
    # 注意:get_market_data_ex 返回的是字典 {code: dataframe}
    daily_data = ContextInfo.get_market_data_ex(
        ['high', 'low', 'close'], 
        [stock], 
        period='1d', 
        count=2,
        dividend_type='none'
    )
    
    if stock not in daily_data or len(daily_data[stock]) < 2:
        return # 数据不足,不运行

    df_daily = daily_data[stock]
    
    # 昨日数据
    prev_high = df_daily['high'].iloc[-2]
    prev_low = df_daily['low'].iloc[-2]
    prev_close = df_daily['close'].iloc[-2]
    
    # 今日至今的最高价和最低价 (用于反转逻辑判断)
    # 注意:这里取日线数据的最后一行作为今日实时的High/Low
    today_high = df_daily['high'].iloc[-1]
    today_low = df_daily['low'].iloc[-1]

    # 获取当前周期的最新收盘价 (用于触发信号)
    current_data = ContextInfo.get_market_data_ex(
        ['close'], 
        [stock], 
        period=ContextInfo.period, 
        count=1,
        dividend_type='none'
    )
    if stock not in current_data or len(current_data[stock]) < 1:
        return
        
    current_price = current_data[stock]['close'].iloc[-1]

    # ================= 3. 计算 R-Breaker 关键价位 =================
    pivot = (prev_high + prev_low + prev_close) / 3
    
    # 突破买入价 (Breakout Buy)
    b_break = prev_high + 2 * (pivot - prev_low)
    # 观察卖出价 (Setup Sell)
    s_setup = pivot + (prev_high - prev_low)
    # 反转卖出价 (Enter Sell)
    s_enter = 2 * pivot - prev_low
    
    # 反转买入价 (Enter Buy)
    b_enter = 2 * pivot - prev_high
    # 观察买入价 (Setup Buy)
    b_setup = pivot - (prev_high - prev_low)
    # 突破卖出价 (Breakout Sell)
    s_break = prev_low - 2 * (prev_high - pivot)

    # ================= 4. 交易逻辑判断 =================
    
    # 获取当前持仓 (为了回测准确,这里使用变量记录,实盘建议配合 get_trade_detail_data 使用)
    pos = ContextInfo.position_status
    
    # --- 信号判断 ---
    
    # 1. 趋势突破买入 (空仓 -> 多仓)
    # 条件:当前价格 > 突破买入价
    if pos == 0 and current_price > b_break:
        print(f"触发趋势买入: 价格 {current_price} > Bbreak {b_break}")
        open_long(ContextInfo)
        
    # 2. 趋势突破卖出 (空仓 -> 空仓)
    # 条件:当前价格 < 突破卖出价
    elif pos == 0 and current_price < s_break:
        print(f"触发趋势卖出: 价格 {current_price} < Sbreak {s_break}")
        open_short(ContextInfo)
        
    # 3. 反转做空 (多仓 -> 空仓 或 空仓 -> 空仓)
    # 条件:今日最高价 > 观察卖出价 且 当前价格跌破 反转卖出价
    elif (pos == 0 or pos == 1) and (today_high > s_setup and current_price < s_enter):
        print(f"触发反转做空: 今日高点 {today_high} > Ssetup {s_setup} 且 现价 {current_price} < Senter {s_enter}")
        if pos == 1:
            close_position(ContextInfo) # 平多
        open_short(ContextInfo) # 开空
        
    # 4. 反转做多 (空仓 -> 多仓 或 空仓 -> 多仓)
    # 条件:今日最低价 < 观察买入价 且 当前价格突破 反转买入价
    elif (pos == 0 or pos == -1) and (today_low < b_setup and current_price > b_enter):
        print(f"触发反转做多: 今日低点 {today_low} < Bsetup {b_setup} 且 现价 {current_price} > Benter {b_enter}")
        if pos == -1:
            close_position(ContextInfo) # 平空
        open_long(ContextInfo) # 开多

    # 5. 止损平仓 (可选,这里简单示例)
    # 如果持多仓,价格跌破突破卖出价,止损
    elif pos == 1 and current_price < s_break:
        print("多头止损")
        close_position(ContextInfo)
    # 如果持空仓,价格突破突破买入价,止损
    elif pos == -1 and current_price > b_break:
        print("空头止损")
        close_position(ContextInfo)

# ================= 交易辅助函数 =================

def open_long(ContextInfo):
    """开多单"""
    # 期货开仓:opType=0 (开多), orderType=1101 (单股/单账号/普通/股手)
    # 股票买入:opType=23
    op_type = 0 if ContextInfo.account_type == 'FUTURE' else 23
    passorder(op_type, 1101, ContextInfo.account_id, ContextInfo.stock, 5, -1, 1, ContextInfo)
    ContextInfo.position_status = 1

def open_short(ContextInfo):
    """开空单 (仅期货)"""
    if ContextInfo.account_type != 'FUTURE':
        print("股票账户无法直接开空")
        return
    # 期货开空:opType=3 (开空)
    passorder(3, 1101, ContextInfo.account_id, ContextInfo.stock, 5, -1, 1, ContextInfo)
    ContextInfo.position_status = -1

def close_position(ContextInfo):
    """平仓所有头寸"""
    if ContextInfo.position_status == 1:
        # 平多:期货 opType=1 (平昨多) 或 2 (平今多),这里简化处理
        # 股票卖出:opType=24
        op_type = 1 if ContextInfo.account_type == 'FUTURE' else 24
        passorder(op_type, 1101, ContextInfo.account_id, ContextInfo.stock, 5, -1, 1, ContextInfo)
        
    elif ContextInfo.position_status == -1:
        # 平空:期货 opType=4 (平昨空) 或 5 (平今空)
        passorder(4, 1101, ContextInfo.account_id, ContextInfo.stock, 5, -1, 1, ContextInfo)
        
    ContextInfo.position_status = 0

代码关键点解析

  1. 数据获取 (get_market_data_ex):

    • R-Breaker 的核心在于利用昨日的日线数据计算 Pivot 点。
    • 代码中使用了 period='1d', count=2。在返回的 DataFrame 中,iloc[-2] 代表昨日完整数据,iloc[-1] 代表今日截止目前的数据(用于获取今日实时的 High 和 Low)。
    • 同时使用 period='1m' (或您设置的周期) 获取当前最新的 close 价格来触发信号。
  2. 反转逻辑:

    • 反转信号不仅看当前价格,还必须确认今日的极值(最高价或最低价)已经触及了观察区(Setup)。
    • 例如做空反转:必须是今日最高价已经超过了 Ssetup,证明市场已经冲高过,然后价格回落跌破 Senter,才确认为反转。
  3. 交易执行 (passorder):

    • 代码中针对期货(Future)和股票(Stock)做了简单的区分。
    • opType 参数:期货开多为 0,开空为 3,平多为 1,平空为 4。股票买入为 23,卖出为 24。
    • prType=5 代表使用最新价下单,price=-1 在最新价模式下无效。
  4. 尾盘强平:

    • R-Breaker 是典型的日内策略,不留隔夜仓。代码中设置了 1455 (14:55) 检测时间,一旦到达该时间且有持仓,立即平仓。

注意事项

  • 账号设置: 请务必将 ContextInfo.account_id 替换为您实际的 QMT 资金账号。
  • 标的: 示例使用的是股指期货主力合约 IF00.IF。如果是股票,R-Breaker 只能做多(除非融券),需要调整 open_short 的逻辑。
  • 实盘持仓同步: 示例代码使用 ContextInfo.position_status 变量来记录持仓。在实盘中,建议在 handlebar 开头使用 get_trade_detail_data 获取真实的账户持仓,以防止程序重启后状态丢失。

Q&A

Q: 如何将此策略用于股票交易?
A: 将 ContextInfo.stock 改为股票代码(如 600000.SH),将 ContextInfo.account_type 改为 'STOCK'。注意股票通常只能做多(T+1限制和缺乏做空机制),因此代码中的 open_short 部分在纯股票账户中将无法执行,策略将退化为只做多头的 R-Breaker。

Q: 为什么使用 get_market_data_ex 而不是 get_market_data
A: get_market_data_ex 是 QMT 推荐的新版接口,返回的数据结构更清晰(字典包含 DataFrame),且支持订阅模式,效率更高。

Q: 策略中的 timetag_to_datetime 是哪里来的?
A: 这是 QMT 内置的辅助函数,用于将毫秒时间戳转换为可读的日期时间字符串。无需导入,直接在 QMT 环境中即可调用。