🚀 AI 一键生成 qmt 策略代码

QMT 交易策略库:如何实现经典的 Aberration 通道突破策略?

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

问题描述

请帮我写一个基于布林带通道突破的交易策略,当价格突破上轨时买入,跌破下轨时卖出。

解决方案

这是一个基于布林带(Bollinger Bands)通道突破的量化交易策略。

策略逻辑

  1. 指标计算
    • 中轨 (MB):过去 N 根 K 线的收盘价移动平均线(通常 N=20)。
    • 上轨 (UP):中轨 + K 倍标准差(通常 K=2)。
    • 下轨 (DN):中轨 - K 倍标准差。
  2. 交易信号
    • 买入:当收盘价突破上轨(Close > UP),且当前无持仓时,全仓买入。
    • 卖出:当收盘价跌破下轨(Close < DN),且当前有持仓时,清仓卖出。

代码实现

该代码使用了 ContextInfo.get_market_data_ex 获取数据,并使用 pandas 计算指标。下单函数使用了 order_target_percent,这在回测中非常方便(自动计算股数),实盘中同样适用(需确保账号设置正确)。

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

def init(ContextInfo):
    """
    初始化函数,策略启动时调用一次
    """
    # --- 策略参数设置 ---
    ContextInfo.M = 20       # 布林带周期
    ContextInfo.K = 2.0      # 标准差倍数
    ContextInfo.account_id = '6000000000' # 请替换为您真实的资金账号
    ContextInfo.account_type = 'STOCK'    # 账号类型:'STOCK'股票, 'FUTURE'期货
    
    # 设置股票池(此处示例为平安银行,实际使用时可在界面设置或此处修改)
    ContextInfo.set_universe(['000001.SZ']) 
    
    # 绑定账号(实盘/模拟盘必须)
    ContextInfo.set_account(ContextInfo.account_id)
    
    print("策略初始化完成:布林带突破策略 (N={}, K={})".format(ContextInfo.M, ContextInfo.K))

def handlebar(ContextInfo):
    """
    K线周期回调函数,每根K线执行一次
    """
    # 获取当前正在运行的K线索引
    index = ContextInfo.barpos
    
    # 获取当前图表的主图代码(如果是多股回测,建议遍历 ContextInfo.get_universe())
    # 这里为了演示清晰,我们只针对当前主图代码或股票池中的第一个代码进行操作
    stock_code = ContextInfo.get_universe()[0]
    
    # --- 1. 获取历史行情数据 ---
    # 我们需要计算MA20,所以至少需要前20根K线,为了安全起见取 M + 5 根
    # subscribe=True 确保实盘时数据自动更新
    data_map = ContextInfo.get_market_data_ex(
        ['close'], 
        [stock_code], 
        period=ContextInfo.period, 
        count=ContextInfo.M + 5,
        dividend_type='front', # 前复权
        subscribe=True
    )
    
    if stock_code not in data_map:
        return

    df = data_map[stock_code]
    
    # 数据长度不足以计算指标时直接返回
    if len(df) < ContextInfo.M:
        return

    # --- 2. 计算布林带指标 ---
    # 计算移动平均线 (中轨)
    df['ma'] = df['close'].rolling(window=ContextInfo.M).mean()
    # 计算标准差
    df['std'] = df['close'].rolling(window=ContextInfo.M).std()
    # 计算上轨
    df['upper'] = df['ma'] + ContextInfo.K * df['std']
    # 计算下轨
    df['lower'] = df['ma'] - ContextInfo.K * df['std']

    # 获取最新一根K线的数据(iloc[-1])
    # 注意:在回测模式下,handlebar是在K线结束时调用的,所以[-1]就是当前K线
    # 在实盘模式下,如果希望K线走完再确认信号,应判断 ContextInfo.is_last_bar() 并结合时间逻辑
    # 这里采用标准回测逻辑,取最新值
    current_close = df['close'].iloc[-1]
    current_upper = df['upper'].iloc[-1]
    current_lower = df['lower'].iloc[-1]
    
    # 打印调试信息 (可选)
    # print(f"代码:{stock_code} 收盘:{current_close:.2f} 上轨:{current_upper:.2f} 下轨:{current_lower:.2f}")

    # --- 3. 获取当前持仓 ---
    # 使用 get_trade_detail_data 获取持仓对象列表
    positions = get_trade_detail_data(ContextInfo.account_id, ContextInfo.account_type, 'POSITION')
    current_volume = 0
    
    for pos in positions:
        if pos.m_strInstrumentID + '.' + pos.m_strExchangeID == stock_code:
            current_volume = pos.m_nVolume
            break
            
    # --- 4. 交易逻辑 ---
    
    # 信号1:价格突破上轨 -> 买入
    if current_close > current_upper:
        # 如果当前没有持仓,则全仓买入
        if current_volume == 0:
            print(f"{stock_code} 触发买入信号: 价格 {current_close} > 上轨 {current_upper}")
            # order_target_percent(代码, 目标仓位比例, ...)
            # 1.0 代表调整至 100% 仓位
            order_target_percent(stock_code, 1.0, ContextInfo, ContextInfo.account_id)

    # 信号2:价格跌破下轨 -> 卖出
    elif current_close < current_lower:
        # 如果当前有持仓,则清仓
        if current_volume > 0:
            print(f"{stock_code} 触发卖出信号: 价格 {current_close} < 下轨 {current_lower}")
            # 0.0 代表调整至 0% 仓位(即清仓)
            order_target_percent(stock_code, 0.0, ContextInfo, ContextInfo.account_id)

使用说明与注意事项

  1. 账号设置

    • 代码中的 ContextInfo.account_id = '6000000000' 必须修改为您实际的 QMT 资金账号。
    • 如果是回测模式,QMT 会自动模拟一个账号,通常不需要修改,但在实盘或模拟交易界面运行时必须匹配。
  2. 数据获取

    • 使用了 get_market_data_ex 接口,这是 QMT 推荐的高效数据接口。
    • dividend_type='front' 设置为前复权,这对于技术指标策略非常重要,避免因分红除权导致的价格跳空触发错误信号。
  3. 下单函数

    • 使用了 order_target_percent。这个函数非常智能,它会自动计算需要买入多少股才能达到目标仓位(例如 1.0 表示满仓)。
    • 如果需要固定数量下单(例如每次买100股),可以将 order_target_percent 替换为 order_shares(stock_code, 100, ContextInfo, ContextInfo.account_id)
  4. 运行模式

    • 回测:在策略编辑器中点击“回测”,设置好时间区间和基准即可。
    • 实盘/模拟:在策略交易界面运行。注意,实盘中 handlebar 会随行情 Tick 推送触发(如果设置为逐Tick运行)或 K线生成时触发。上述代码逻辑是基于 K 线收盘价的,建议在设置中将运行频率设为“K线生成”或在代码中增加 ContextInfo.is_new_bar() 判断以避免盘中闪烁信号导致频繁交易。

Q&A

Q: 如何修改布林带的参数?
A: 在代码的 init 函数中,修改 ContextInfo.M (周期) 和 ContextInfo.K (标准差倍数) 的值即可。

Q: 这个策略可以用于期货吗?
A: 可以,但需要做两处调整:

  1. ContextInfo.account_type 改为 'FUTURE'
  2. 期货通常支持做空。目前的逻辑是“跌破下轨卖出平仓”。如果需要“跌破下轨开空单”,需要修改卖出部分的逻辑,将 order_target_percent 的目标设为负数(如果API支持)或使用 passorder 函数发送开空指令(opType=3)。

Q: 为什么使用 get_market_data_ex 而不是 get_market_data
A: get_market_data_ex 是 QMT 新版推荐的接口,支持更灵活的参数(如复权、订阅开关),且返回的数据结构更规范(字典包含 DataFrame),处理多股数据时效率更高。