🚀 AI 一键生成 qmt 策略代码

QMT 经典策略:如何编写 Hans123 开盘突破交易策略?

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

问题描述

如何在 QMT 实现 Hans123 突破策略?

解决方案

Hans123 策略 QMT 实现指南

Hans123 是一种经典的日内突破策略。其核心逻辑是在开盘后的一段时间内(如开盘前30分钟)建立一个高低点区间,当价格突破该区间的上轨时做多,跌破下轨时做空,并在收盘前平仓。

以下是在 QMT 平台上实现该策略的详细代码和说明。

策略逻辑概述

  1. 设定时间窗口:例如 09:30 - 10:00。
  2. 计算上下轨:记录时间窗口内的最高价(上轨)和最低价(下轨)。
  3. 交易信号
    • 做多:10:00 后,价格突破上轨。
    • 做空:10:00 后,价格跌破下轨。
  4. 出场规则
    • 止损:价格反向突破(如做多后跌破下轨,或固定点数止损)。
    • 收盘平仓:在每日收盘前(如 14:55)强制平仓。

QMT Python 策略代码

本代码以**股指期货(IF)**为例,因为 Hans123 是典型的 T+0 策略。如果您用于股票,请注意 A 股的 T+1 限制(当日买入无法当日卖出)。

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

def init(ContextInfo):
    """
    策略初始化函数
    """
    # 1. 设定交易标的 (此处以沪深300主力合约为例,实盘请修改为具体合约代码)
    ContextInfo.asset = 'IF00.IF' 
    
    # 2. 设定账户 (请修改为您的资金账号)
    ContextInfo.account_id = 'YOUR_ACCOUNT_ID'
    ContextInfo.account_type = 'FUTURE' # FUTURE: 期货, STOCK: 股票
    
    # 3. 策略参数设置
    ContextInfo.setup_time_end = "10:00:00"  # 突破区间建立结束时间
    ContextInfo.close_time = "14:55:00"      # 尾盘平仓时间
    ContextInfo.trade_qty = 1                # 每次交易手数
    
    # 4. 全局变量初始化
    ContextInfo.day_high = -1       # 当日区间最高价
    ContextInfo.day_low = 999999    # 当日区间最低价
    ContextInfo.current_date = ''   # 当前日期记录
    ContextInfo.trade_triggered = False # 当日是否已开仓标记
    
    # 5. 设定运行周期 (建议使用 1分钟 或 5分钟 线)
    # 注意:在界面上运行策略时,请选择相应的周期

def handlebar(ContextInfo):
    """
    K线周期运行函数
    """
    # 获取当前K线位置
    index = ContextInfo.barpos
    
    # 获取当前时间
    timetag = ContextInfo.get_bar_timetag(index)
    # 将时间戳转换为日期和时间字符串
    current_dt_str = timetag_to_datetime(timetag, '%Y%m%d %H:%M:%S')
    current_date = current_dt_str[0:8]
    current_time = current_dt_str[9:]
    
    # --- 1. 新的一天,重置变量 ---
    if ContextInfo.current_date != current_date:
        ContextInfo.current_date = current_date
        ContextInfo.day_high = -1
        ContextInfo.day_low = 999999
        ContextInfo.trade_triggered = False
        print(f"New Day: {current_date}, Reset parameters.")

    # 获取最新行情数据 (开高低收)
    # 使用 get_market_data_ex 获取数据更高效
    data_dict = ContextInfo.get_market_data_ex(
        ['open', 'high', 'low', 'close'], 
        [ContextInfo.asset], 
        period=ContextInfo.period, 
        count=1,
        subscribe=True
    )
    
    if ContextInfo.asset not in data_dict:
        return
        
    df = data_dict[ContextInfo.asset]
    if df.empty:
        return
        
    # 获取当前K线的最高、最低、收盘价
    current_high = df.iloc[-1]['high']
    current_low = df.iloc[-1]['low']
    current_close = df.iloc[-1]['close']
    
    # --- 2. 建立突破区间 (开盘 - 10:00) ---
    if current_time <= ContextInfo.setup_time_end:
        # 更新区间最高价
        if current_high > ContextInfo.day_high:
            ContextInfo.day_high = current_high
        # 更新区间最低价
        if current_low < ContextInfo.day_low:
            ContextInfo.day_low = current_low
            
        # 在图表上画出区间线 (仅供回测观察)
        ContextInfo.paint('Setup_High', ContextInfo.day_high, -1, 0)
        ContextInfo.paint('Setup_Low', ContextInfo.day_low, -1, 0)
        
    # --- 3. 交易阶段 (10:00 - 14:55) ---
    elif current_time < ContextInfo.close_time:
        # 绘制延续的区间线
        ContextInfo.paint('Setup_High', ContextInfo.day_high, -1, 0)
        ContextInfo.paint('Setup_Low', ContextInfo.day_low, -1, 0)
        
        # 如果今日尚未交易,检查突破信号
        if not ContextInfo.trade_triggered:
            # 向上突破
            if current_close > ContextInfo.day_high:
                print(f"Breakout UP: Price {current_close} > High {ContextInfo.day_high}")
                # 期货开多 (23:买入, 1101:单股/手)
                # 注意:期货开仓通常用 buy_open,这里演示通用 passorder
                # opType: 23(买入/开多), 24(卖出/开空) - 股票逻辑
                # 期货逻辑: 0(开多), 3(开空)
                
                # 这里使用期货专用函数 buy_open 更加清晰
                buy_open(ContextInfo.asset, ContextInfo.trade_qty, "LATEST", current_close, ContextInfo, ContextInfo.account_id)
                
                ContextInfo.trade_triggered = True
                
            # 向下突破
            elif current_close < ContextInfo.day_low:
                print(f"Breakout DOWN: Price {current_close} < Low {ContextInfo.day_low}")
                # 期货开空
                sell_open(ContextInfo.asset, ContextInfo.trade_qty, "LATEST", current_close, ContextInfo, ContextInfo.account_id)
                
                ContextInfo.trade_triggered = True
        
        # --- 止损逻辑 (可选) ---
        # 如果持多仓,价格跌破下轨,止损平仓
        # 如果持空仓,价格突破上轨,止损平仓
        # 此处需要获取持仓信息,为简化代码,此处略过复杂持仓判断,仅展示核心逻辑
        
    # --- 4. 尾盘平仓 (14:55 以后) ---
    else:
        # 获取当前持仓
        positions = get_trade_detail_data(ContextInfo.account_id, ContextInfo.account_type, 'POSITION')
        
        for pos in positions:
            if pos.m_strInstrumentID == ContextInfo.asset:
                # 如果有多单,平多
                if pos.m_nVolume > 0 and pos.m_nDirection == 48: # 48代表多头
                    print(f"Closing Long Position at {current_time}")
                    sell_close_tdayfirst(ContextInfo.asset, pos.m_nVolume, "LATEST", current_close, ContextInfo, ContextInfo.account_id)
                
                # 如果有空单,平空
                elif pos.m_nVolume > 0 and pos.m_nDirection == 49: # 49代表空头
                    print(f"Closing Short Position at {current_time}")
                    buy_close_tdayfirst(ContextInfo.asset, pos.m_nVolume, "LATEST", current_close, ContextInfo, ContextInfo.account_id)

代码关键点解析

  1. 时间处理

    • QMT 的 get_bar_timetag 返回的是毫秒级时间戳。
    • 使用 timetag_to_datetime 转换为字符串(如 '10:00:00'),方便进行字符串比较来判断当前处于哪个交易阶段(建立区间、交易、平仓)。
  2. 数据获取 (get_market_data_ex)

    • 这是 QMT 推荐的高效数据接口。
    • count=1 表示只取最新的一根 K 线数据,用于实时判断。
    • 返回的是一个字典,Key 是股票代码,Value 是 Pandas DataFrame。
  3. 状态管理

    • ContextInfo.day_highday_low 用于存储当天的关键点位。
    • ContextInfo.current_date 用于检测日期变更,确保第二天开盘时重置策略状态。
  4. 交易函数

    • 代码中使用了 buy_open (买入开仓) 和 sell_open (卖出开仓),这是针对期货的便捷函数。
    • 尾盘平仓使用了 sell_close_tdayfirst (卖出平仓,平今优先),适合日内交易,优先平掉当天的仓位以节省手续费(针对某些品种)。

注意事项

  • 股票 vs 期货
    • 上述代码逻辑是针对期货(T+0)设计的。
    • 如果是股票(T+1),你不能在当天买入后当天卖出。要在股票上实现 Hans123,通常需要你有“底仓”(即昨天已经持有的股票),通过“做T”的方式(高抛低吸)来实现日内价差,或者将策略改为波段策略(持有过夜)。
  • 回测与实盘
    • 在回测模式下,QMT 会模拟撮合。
    • 在实盘模式下,请务必先在模拟账户测试,确认 ContextInfo.account_id 设置正确。
  • 周期选择
    • Hans123 对时间敏感,建议在策略编辑器界面选择 1分钟5分钟 周期运行。

Q&A

Q: 如何修改止损逻辑?
A: 在“交易阶段”的代码块中,可以使用 get_trade_detail_data 获取当前持仓成本。如果 (现价 - 成本) / 成本 < -0.01 (亏损1%),则触发平仓函数。

Q: 为什么使用 get_market_data_ex 而不是 get_market_data?
A: get_market_data_ex 是 QMT 的新版接口,返回 Pandas 格式,处理数据更方便,且支持订阅模式,效率更高。

Q: 如何在股票上做空?
A: 在 A 股市场,普通账户无法直接做空。如果是信用账户(融资融券),可以使用 passorder 函数配合 opType=28 (融券卖出) 来实现做空逻辑。