🚀 AI 一键生成 qmt 策略代码

如何编写一个日内放量突破策略来捕捉强势股启动点?(附 Python 源码)

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

问题描述

请帮我写一个策略,当某只股票5分钟K线的成交量是过去20根K线平均成交量的3倍以上,并且价格突破这20根K线的最高点时,就买入。

解决方案

这是一个基于QMT Python API编写的量化策略。

策略逻辑分析

  1. 运行周期:策略需要在 5分钟 周期上运行。
  2. 数据获取:获取当前股票过去 21 根 K 线的数据(当前 1 根 + 过去 20 根)。
  3. 计算指标
    • 平均成交量:计算过去 20 根 K 线(不含当前)的成交量平均值。
    • 最高价:计算过去 20 根 K 线(不含当前)的最高价的最大值。
  4. 交易信号
    • 条件 A:当前 K 线成交量 > 3 * 过去 20 根平均成交量。
    • 条件 B:当前价格 > 过去 20 根最高价。
  5. 执行动作:当 A 和 B 同时满足,且当前 K 线未开仓过,执行买入。

策略代码

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

def init(ContextInfo):
    """
    初始化函数,策略启动时执行一次
    """
    # 设置资金账号,请修改为您自己的实盘或模拟账号
    ContextInfo.accid = '6000000000' 
    ContextInfo.set_account(ContextInfo.accid)
    
    # 策略参数设置
    ContextInfo.lookback_period = 20      # 回溯周期:20根K线
    ContextInfo.vol_multiplier = 3.0      # 成交量倍数:3倍
    ContextInfo.trade_period = '5m'       # 运行周期:5分钟
    ContextInfo.buy_amount = 100          # 每次买入数量(股)
    
    # 用于记录最近一次买入的K线位置,防止同一根K线重复下单
    ContextInfo.last_buy_barpos = -1

def handlebar(ContextInfo):
    """
    行情事件函数,每根K线或每个Tick执行一次
    """
    # 获取当前图表上的K线索引
    barpos = ContextInfo.barpos
    
    # 获取当前主图的股票代码
    stock_code = ContextInfo.stockcode
    
    # 1. 获取行情数据
    # 我们需要获取过去20根 + 当前1根,共21根数据
    # 注意:dividend_type='front' 表示使用前复权数据,这在处理价格突破时很重要
    count = ContextInfo.lookback_period + 1
    data_map = ContextInfo.get_market_data_ex(
        ['volume', 'high', 'close'],  # 需要的字段:成交量、最高价、收盘价(当前价)
        [stock_code],                 # 股票代码列表
        period=ContextInfo.trade_period, 
        count=count,
        dividend_type='front',
        fill_data=False,
        subscribe=True
    )
    
    # 检查数据是否获取成功
    if stock_code not in data_map:
        return
        
    df = data_map[stock_code]
    
    # 确保数据长度足够进行计算
    if len(df) < count:
        return

    # 2. 数据切片与计算
    # 历史数据:不包含当前这根K线(即前20根)
    # iloc[-21:-1] 取倒数第21个到倒数第2个
    history_df = df.iloc[-(ContextInfo.lookback_period + 1) : -1]
    
    # 当前数据:最后一根K线
    current_bar = df.iloc[-1]
    
    # 计算过去20根K线的平均成交量
    avg_volume = history_df['volume'].mean()
    
    # 计算过去20根K线的最高价中的最大值
    max_high = history_df['high'].max()
    
    # 获取当前成交量和当前价格
    current_volume = current_bar['volume']
    current_price = current_bar['close']
    
    # 3. 信号判断
    # 条件1:当前成交量是过去20根平均成交量的3倍以上
    # 注意:防止分母为0
    if avg_volume == 0:
        return
    condition_vol = current_volume > (avg_volume * ContextInfo.vol_multiplier)
    
    # 条件2:当前价格突破过去20根K线的最高点
    condition_price = current_price > max_high
    
    # 4. 执行交易
    # 如果满足条件,且当前这根K线还没有买入过
    if condition_vol and condition_price:
        if ContextInfo.last_buy_barpos != barpos:
            print(f"触发买入信号: {stock_code}, 时间: {df.index[-1]}")
            print(f"当前量: {current_volume}, 均量: {avg_volume:.2f}, 当前价: {current_price}, 前高: {max_high}")
            
            # 执行下单:买入,操作类型23,下单方式1101(单股单账号普通),最新价下单(报价类型5)
            # 注意:实盘中请确保账号已登录且资金充足
            passorder(23, 1101, ContextInfo.accid, stock_code, 5, -1, ContextInfo.buy_amount, ContextInfo)
            
            # 更新买入标记,防止同根K线重复下单
            ContextInfo.last_buy_barpos = barpos
            
            # 在图表上画出买入信号(可选)
            ContextInfo.draw_text(True, current_price, '买')

使用说明与注意事项

  1. 运行设置

    • 在QMT界面运行此策略时,请务必将策略的运行周期设置为 5分钟(或者在策略编辑器基本信息中设置默认周期为5分钟)。
    • 如果策略运行在日线图上,handlebar 每天只触发一次,无法捕捉盘中5分钟级别的突破。
  2. 账号配置

    • 代码第 9 行 ContextInfo.accid = '6000000000' 需要修改为您实际的资金账号。
  3. 防抖动处理

    • 代码中使用了 ContextInfo.last_buy_barpos 变量。这是为了防止在实盘或模拟盘中,当一根 5 分钟 K 线尚未走完(实时 Tick 不断推送)时,信号反复触发导致重复下单。该逻辑保证了同一根 5 分钟 K 线内最多只买入一次
  4. 成交量逻辑

    • 策略使用的是 current_volume(当前累积成交量)。在盘中(K线未走完时),这个成交量是随着时间递增的。一旦累积量超过均量的3倍且价格突破,就会立即触发信号,不需要等到 K 线收盘。
  5. 下单函数

    • 使用了 passorder 函数,参数 23 代表买入,1101 代表单股单账号下单,5 代表使用最新价报价。您可以根据需要修改为 order_value(按金额买入)或其他下单方式。

Q&A

Q: 如何将买入数量改为按金额买入(例如每次买1万元)?
A: 可以将 passorder 行替换为 order_value 函数:

# 需要先定义 order_value 函数或直接使用 passorder 的金额模式
# 简单方式是使用 QMT 封装好的 order_value (如果环境支持) 或者修改 passorder 参数
# passorder 参数 orderType 改为 1102 (金额下单)
passorder(23, 1102, ContextInfo.accid, stock_code, 5, -1, 10000, ContextInfo)

Q: 为什么使用 get_market_data_ex 而不是 get_market_data
A: get_market_data_ex 是 QMT 推荐的新版接口,效率更高,且返回的数据结构(Pandas DataFrame)更易于进行数学计算和逻辑处理。

Q: 策略在回测和实盘中有什么区别?
A: 在回测模式下,handlebar 通常在 K 线结束时调用一次。在实盘/模拟交易模式下,如果是最新的一根 K 线,handlebar 会随着每一个 Tick(分笔数据)的到来而被调用,因此必须加入 last_buy_barpos 这样的逻辑来控制下单频率。