🚀 AI 一键生成 qmt 策略代码

如何使用 Python 在 QMT 平台实现唐奇安通道(Donchian Channel)突破策略?

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

问题描述

请帮我编写一个唐奇安通道突破策略。

解决方案

这是一个基于 QMT Python API 编写的 唐奇安通道(Donchian Channel)突破策略

策略逻辑

  1. 计算指标
    • 上轨(Upper Band):过去 $N$ 根 K 线的最高价的最大值(不包含当前 K 线)。
    • 下轨(Lower Band):过去 $N$ 根 K 线的最低价的最小值(不包含当前 K 线)。
  2. 买入信号:当当前 K 线收盘价突破上轨,且当前无持仓时,买入。
  3. 卖出信号:当当前 K 线收盘价跌破下轨,且当前有持仓时,卖出平仓。

策略代码

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

def init(ContextInfo):
    """
    初始化函数,设定策略参数和账户
    """
    # --- 策略参数设置 ---
    ContextInfo.N = 20           # 唐奇安通道周期 (通常为20)
    ContextInfo.stock_code = '600000.SH'  # 标的代码 (示例:浦发银行)
    ContextInfo.period = '1d'    # 运行周期 (日线)
    ContextInfo.amount = 1000    # 每次买入数量 (股)
    ContextInfo.account_id = '666666' # 【重要】请替换为您的实际资金账号
    ContextInfo.account_type = 'STOCK' # 账号类型:'STOCK'股票, 'FUTURE'期货
    
    # --- 系统设置 ---
    # 设定股票池
    ContextInfo.set_universe([ContextInfo.stock_code])
    # 绑定交易账号
    ContextInfo.set_account(ContextInfo.account_id)

def handlebar(ContextInfo):
    """
    K线逐根运行函数
    """
    # 获取当前K线索引
    index = ContextInfo.barpos
    
    # 如果K线数量不足以计算周期,直接返回
    if index < ContextInfo.N:
        return

    # --- 1. 获取行情数据 ---
    # 获取过去 N+1 根K线的数据 (包含当前K线和过去N根)
    # count = N + 1,是为了取过去N根计算通道,第N+1根(即当前根)用于比较价格
    data = ContextInfo.get_market_data_ex(
        ['high', 'low', 'close'], 
        [ContextInfo.stock_code], 
        period=ContextInfo.period, 
        count=ContextInfo.N + 1, 
        dividend_type='front' # 前复权
    )
    
    # 数据校验
    if ContextInfo.stock_code not in data:
        return
    
    df = data[ContextInfo.stock_code]
    
    # 再次确保数据长度足够
    if len(df) < ContextInfo.N + 1:
        return

    # --- 2. 计算唐奇安通道 ---
    # 提取用于计算通道的历史数据 (排除当前最新的一根K线,避免未来函数)
    history_highs = df['high'].iloc[:-1] 
    history_lows = df['low'].iloc[:-1]
    
    # 获取当前最新价格
    current_close = df['close'].iloc[-1]
    current_time = df.index[-1]

    # 计算上轨和下轨
    upper_band = history_highs.max()
    lower_band = history_lows.min()

    # --- 3. 绘图 (可选,用于回测界面展示) ---
    ContextInfo.paint('Upper_Band', upper_band, -1, 0, 'red')
    ContextInfo.paint('Lower_Band', lower_band, -1, 0, 'green')

    # --- 4. 获取当前持仓状态 ---
    # 注意:回测模式和实盘模式获取持仓的方式略有不同,这里使用通用接口
    positions = get_trade_detail_data(ContextInfo.account_id, ContextInfo.account_type, 'POSITION')
    current_pos = 0
    
    for pos in positions:
        if pos.m_strInstrumentID == ContextInfo.stock_code:
            current_pos = pos.m_nVolume
            break

    # --- 5. 交易逻辑 ---
    
    # 信号1:突破上轨 -> 买入
    if current_close > upper_band and current_pos == 0:
        print(f"[{current_time}] 价格 {current_close} 突破上轨 {upper_band},触发买入")
        
        # 下单函数 passorder
        # 23: 买入, 1101: 单股单账号, 5: 最新价
        passorder(23, 1101, ContextInfo.account_id, ContextInfo.stock_code, 5, -1, ContextInfo.amount, ContextInfo)

    # 信号2:跌破下轨 -> 卖出
    elif current_close < lower_band and current_pos > 0:
        print(f"[{current_time}] 价格 {current_close} 跌破下轨 {lower_band},触发卖出")
        
        # 下单函数 passorder
        # 24: 卖出, 1101: 单股单账号, 5: 最新价
        passorder(24, 1101, ContextInfo.account_id, ContextInfo.stock_code, 5, -1, current_pos, ContextInfo)

代码关键点说明

  1. 数据获取 (get_market_data_ex)

    • 我们获取 N + 1 条数据。
    • 使用 iloc[:-1] 切片来获取过去 N 天的数据计算通道。这是为了避免“未来函数”,即不能用今天的最高价来判断今天是否突破了今天的最高价(这在逻辑上是死循环),而是要看今天是否突破了过去 N 天的最高价。
  2. 交易函数 (passorder)

    • 23 代表股票买入,24 代表股票卖出。
    • 1101 代表单账号、按股数下单。
    • 5 代表使用最新价下单(市价成交的模拟)。
    • 注意:在实盘中,请确保 ContextInfo.account_id 填写正确。
  3. 绘图 (paint)

    • 代码中包含了 ContextInfo.paint 函数,这样你在 QMT 的回测界面运行策略时,可以直接在 K 线图上看到红色的上轨和绿色的下轨,方便验证策略逻辑。

如何使用

  1. 打开 QMT 客户端,进入【模型研究】或【策略编辑器】。
  2. 新建一个 Python 策略。
  3. 将上述代码复制粘贴进去。
  4. 修改 init 函数中的 ContextInfo.account_id 为你的真实或模拟账号。
  5. 点击【运行】或【回测】即可。

Q&A

Q: 如何将此策略改为期货策略?
A: 需要修改以下几点:

  1. ContextInfo.account_type 改为 'FUTURE'
  2. passorder 的操作类型代码需要修改:开多(0), 平多(6), 开空(3), 平空(9)。
  3. 逻辑判断中需要增加做空的逻辑(跌破下轨开空,突破上轨平空)。

Q: 为什么使用 get_market_data_ex 而不是 get_market_data?
A: get_market_data_ex 是 QMT 推荐的新版接口,返回的数据结构更清晰(字典包含 DataFrame),且支持更多参数配置(如复权方式、停牌填充等),处理效率更高。

Q: 这里的 N=20 是什么意思?
A: 这是唐奇安通道的经典参数,代表过去20个交易日(约一个月)的价格极值。你可以根据需要修改为 10、55 等其他数值。