🚀 AI 一键生成 qmt 策略代码

如何在 QMT 平台复现经典的海龟交易法则策略?

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

问题描述

请帮我实现海龟交易法则,即价格突破N日高点时买入,跌破M日低点时卖出。

解决方案

这是一个基于 QMT (Quant Maker Trading) 平台的 Python 策略代码,实现了经典的海龟交易法则核心逻辑:唐奇安通道(Donchian Channel)突破策略

策略逻辑

  1. 入场(买入):当当前价格突破过去 N 日的最高价时,做多买入。
  2. 出场(卖出):当当前价格跌破过去 M 日的最低价时,平仓卖出。
  3. 参数设置:默认 N=20(20日突破),M=10(10日止损)。

QMT 策略代码

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

def init(ContextInfo):
    """
    初始化函数,设定策略参数和账号
    """
    # 策略参数设置
    ContextInfo.N = 20       # 买入突破周期 (如:20日高点)
    ContextInfo.M = 10       # 卖出止损周期 (如:10日低点)
    ContextInfo.trade_vol = 1000  # 每次交易的股数
    
    # 设置账号 (请替换为您自己的资金账号)
    # 格式通常为 '账号ID'
    ContextInfo.account_id = 'YOUR_ACCOUNT_ID' 
    ContextInfo.set_account(ContextInfo.account_id)
    
    print("策略初始化完成:海龟法则 (N={}, M={})".format(ContextInfo.N, ContextInfo.M))

def handlebar(ContextInfo):
    """
    K线周期回调函数,处理核心交易逻辑
    """
    # 获取当前主图的股票代码和市场
    stock_code = ContextInfo.stockcode + '.' + ContextInfo.market
    
    # 获取当前K线索引
    index = ContextInfo.barpos
    
    # 确保有足够的历史数据进行计算 (需要 N+1 根K线,因为要计算前N天的极值)
    if index < ContextInfo.N + 1:
        return

    # 获取历史行情数据
    # count = N + 2 是为了确保能取到前 N 天的数据,并包含当前 bar
    # dividend_type='front' 使用前复权数据,防止分红造成假突破
    data = ContextInfo.get_market_data(
        ['high', 'low', 'close'], 
        stock_code=[stock_code], 
        count=ContextInfo.N + 2, 
        period=ContextInfo.period,
        dividend_type='front'
    )
    
    # 如果数据获取失败或长度不足,直接返回
    if data is None or len(data) == 0:
        return
        
    # 将数据转换为 Series 方便计算
    # 注意:get_market_data 返回的是 DataFrame,列是股票代码,我们需要转置或直接取列
    # 这里假设是单只股票运行,直接取该股票的数据
    try:
        high_series = data['high']
        low_series = data['low']
        close_series = data['close']
    except:
        return

    # --- 核心指标计算 ---
    
    # 获取当前最新价格
    current_price = close_series.iloc[-1]
    
    # 计算唐奇安通道上轨:过去 N 天的最高价(不包含当前最新K线)
    # 使用 iloc[-(N+1):-1] 取倒数第 N+1 个到倒数第 2 个数据
    recent_highs = high_series.iloc[-(ContextInfo.N + 1):-1]
    donchian_upper = recent_highs.max()
    
    # 计算唐奇安通道下轨:过去 M 天的最低价(不包含当前最新K线)
    recent_lows = low_series.iloc[-(ContextInfo.M + 1):-1]
    donchian_lower = recent_lows.min()

    # --- 仓位查询 ---
    current_pos = get_holding_position(stock_code, ContextInfo)

    # --- 交易信号判断 ---
    
    # 1. 买入信号:当前价格突破过去 N 日最高价,且当前无持仓
    if current_price > donchian_upper and current_pos == 0:
        print(f"触发买入信号: {stock_code}, 现价: {current_price}, N日高点: {donchian_upper}")
        
        # 下单买入
        order_shares(stock_code, ContextInfo.trade_vol, 'fix', current_price, ContextInfo, ContextInfo.account_id)
        
    # 2. 卖出信号:当前价格跌破过去 M 日最低价,且当前有持仓
    elif current_price < donchian_lower and current_pos > 0:
        print(f"触发卖出信号: {stock_code}, 现价: {current_price}, M日低点: {donchian_lower}")
        
        # 下单卖出 (卖出所有持仓)
        order_shares(stock_code, -current_pos, 'fix', current_price, ContextInfo, ContextInfo.account_id)

def get_holding_position(stock_code, ContextInfo):
    """
    辅助函数:查询指定股票的当前持仓数量
    """
    position_list = get_trade_detail_data(ContextInfo.account_id, 'stock', 'position')
    
    for pos in position_list:
        # QMT返回的证券代码可能不带后缀,或者带后缀,需要做兼容处理
        # 这里的逻辑是简单的字符串包含匹配,实际使用建议严格匹配
        if pos.m_strInstrumentID == stock_code or pos.m_strInstrumentID in stock_code:
            return pos.m_nVolume
            
    return 0

代码使用说明

  1. 编码格式:代码第一行 # -*- coding: gbk -*- 是必须的,因为 QMT 的 Python 编辑器默认使用 GBK 编码,否则中文注释会乱码或报错。
  2. 账号设置:请务必将 init 函数中的 ContextInfo.account_id = 'YOUR_ACCOUNT_ID' 替换为您实际的资金账号(回测模式下通常不需要修改,实盘模式必须修改)。
  3. 运行周期
    • 该策略依赖 ContextInfo.period,请在运行策略时选择 日线 (1d) 周期,这是海龟法则的标准周期。
  4. 数据获取
    • 代码中使用了 dividend_type='front'(前复权)。在突破策略中,复权非常重要,否则分红除权导致的股价“下跌”会触发错误的止损信号。
  5. 指标计算细节
    • 计算 N 日高点时,必须排除当前 K 线。如果包含当前 K 线,那么当前价格永远不可能大于 N 日高点(最多相等),导致永远无法触发买入信号。代码中使用了切片 iloc[-(N+1):-1] 来确保只取历史数据。

如何在 QMT 中运行

  1. 打开 QMT 客户端,进入【模型研究】或【策略编辑器】。
  2. 新建一个 Python 策略。
  3. 将上述代码复制粘贴进去。
  4. 点击【编译】检查是否有语法错误。
  5. 在右侧选择一只股票(例如 600000.SH)和周期(日线)。
  6. 点击【运行】或【回测】查看结果。