🚀 AI 一键生成 qmt 策略代码

亚历山大·埃尔德的三重滤网策略 Python 代码实现

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

问题描述

请帮我实现三重滤网 (Triple Screen) 交易策略的代码

解决方案

这是一个基于亚历山大·埃尔德(Alexander Elder)博士提出的**三重滤网(Triple Screen)**交易系统的 QMT 策略实现代码。

策略逻辑说明

三重滤网系统通过三个不同的时间维度来过滤交易信号,提高胜率:

  1. 第一层滤网(市场潮流 - 长期趋势):
    • 周期:周线(Weekly)。
    • 指标:MACD 柱状图(MACD Histogram)。
    • 规则:当周线 MACD 柱状图向上倾斜(数值大于前一根)时,定义为多头趋势;反之为空头趋势。本策略仅演示做多逻辑。
  2. 第二层滤网(市场波浪 - 中期回调):
    • 周期:日线(Daily)。
    • 指标:随机指标(KDJ 或 Stochastic)。
    • 规则:当第一层滤网为多头趋势时,寻找日线 KDJ 的超卖区域(例如 K < 30)作为回调买入机会。
  3. 第三层滤网(盘中突破 - 入场点):
    • 执行:在 QMT 量化中,为了简化执行,当满足前两层条件时,我们在下一根 K 线开盘时直接买入(或者使用当前 K 线收盘价模拟)。

QMT 策略代码

请在 QMT 的策略编辑器中新建一个 Python 策略,并将以下代码复制进去。

注意

  1. 请确保您的 QMT 客户端已安装 pandastalib 库(QMT 自带环境通常已包含)。
  2. 策略运行的主图周期建议设置为 日线 (1d)
# -*- coding: gbk -*-
import pandas as pd
import numpy as np
import talib

def init(ContextInfo):
    """
    策略初始化函数
    """
    # 设置账号(请替换为您自己的资金账号)
    ContextInfo.account_id = '6000000000' 
    ContextInfo.account_type = 'STOCK'
    ContextInfo.set_account(ContextInfo.account_id)
    
    # 策略参数设置
    ContextInfo.long_period = '1w'  # 第一层滤网周期:周线
    ContextInfo.short_period = '1d' # 第二层滤网周期:日线 (即主图周期)
    
    # MACD 参数 (用于第一层滤网)
    ContextInfo.macd_fast = 12
    ContextInfo.macd_slow = 26
    ContextInfo.macd_signal = 9
    
    # KDJ 参数 (用于第二层滤网)
    ContextInfo.kdj_n = 9
    ContextInfo.kdj_m1 = 3
    ContextInfo.kdj_m2 = 3
    ContextInfo.oversold_threshold = 30 # 超卖阈值
    ContextInfo.overbought_threshold = 80 # 超买阈值 (用于止盈)
    
    # 每次交易数量
    ContextInfo.trade_vol = 100

def get_macd_trend(ContextInfo, stock_code):
    """
    计算第一层滤网:周线 MACD 趋势
    返回: 1 (趋势向上), -1 (趋势向下), 0 (数据不足)
    """
    # 获取周线数据,取最近 50 根即可
    data = ContextInfo.get_market_data_ex(
        ['close'], 
        [stock_code], 
        period=ContextInfo.long_period, 
        count=50, 
        dividend_type='front'
    )
    
    if stock_code not in data or data[stock_code].empty:
        return 0
        
    df = data[stock_code]
    close_prices = df['close'].values
    
    # 计算 MACD
    # talib.MACD 返回三个数组: macd, signal, hist(柱状图)
    diff, dea, hist = talib.MACD(
        close_prices, 
        fastperiod=ContextInfo.macd_fast, 
        slowperiod=ContextInfo.macd_slow, 
        signalperiod=ContextInfo.macd_signal
    )
    
    # 检查数据长度
    if len(hist) < 2:
        return 0
        
    # 埃尔德规则:MACD 柱状图斜率向上(当前柱 > 上一根柱)即为多头趋势
    # 注意:这里比较的是柱状图的高度变化,不仅仅是正负
    current_hist = hist[-1]
    prev_hist = hist[-2]
    
    if current_hist > prev_hist:
        return 1 # 趋势向上
    elif current_hist < prev_hist:
        return -1 # 趋势向下
    else:
        return 0

def get_kdj_signal(ContextInfo, stock_code):
    """
    计算第二层滤网:日线 KDJ 状态
    返回: 'oversold' (超卖), 'overbought' (超买), 'neutral' (中性)
    """
    # 获取日线数据 (主图周期)
    data = ContextInfo.get_market_data_ex(
        ['high', 'low', 'close'], 
        [stock_code], 
        period=ContextInfo.short_period, 
        count=50, 
        dividend_type='front'
    )
    
    if stock_code not in data or data[stock_code].empty:
        return 'neutral'
        
    df = data[stock_code]
    high = df['high'].values
    low = df['low'].values
    close = df['close'].values
    
    # 计算 KDJ (Stochastic)
    # talib.STOCH 对应 KDJ 的算法
    k, d = talib.STOCH(
        high, 
        low, 
        close, 
        fastk_period=ContextInfo.kdj_n, 
        slowk_period=ContextInfo.kdj_m1, 
        slowk_matype=0, 
        slowd_period=ContextInfo.kdj_m2, 
        slowd_matype=0
    )
    
    # 获取最新的 K 值
    current_k = k[-1]
    
    if current_k < ContextInfo.oversold_threshold:
        return 'oversold'
    elif current_k > ContextInfo.overbought_threshold:
        return 'overbought'
    else:
        return 'neutral'

def handlebar(ContextInfo):
    """
    K线逐根运行函数
    """
    # 获取当前主图的代码
    stock_code = ContextInfo.stockcode + '.' + ContextInfo.market
    
    # 过滤掉未上市或数据不足的情况
    if ContextInfo.is_last_bar():
        # 仅在最后一根K线或回测模式下运行逻辑
        pass
    else:
        # 如果为了加快回测速度,非必要逻辑可以跳过,但为了指标计算连续性,通常不建议完全跳过
        # 这里为了演示简单,我们对每一根K线都进行计算
        pass

    # 1. 获取持仓状态
    positions = get_trade_detail_data(ContextInfo.account_id, ContextInfo.account_type, 'POSITION')
    current_pos = 0
    for pos in positions:
        if pos.m_strInstrumentID == stock_code:
            current_pos = pos.m_nVolume
            break

    # 2. 执行第一层滤网:判断周线趋势
    trend_direction = get_macd_trend(ContextInfo, stock_code)
    
    # 3. 执行第二层滤网:判断日线震荡
    oscillator_status = get_kdj_signal(ContextInfo, stock_code)
    
    # 4. 交易逻辑 (第三层滤网:执行)
    
    # 开仓逻辑:周线趋势向上 且 日线超卖
    if current_pos == 0:
        if trend_direction == 1 and oscillator_status == 'oversold':
            print(f"[{ContextInfo.get_bar_timetag(ContextInfo.barpos)}] 触发买入: 周线趋势向上, 日线超卖")
            # 使用 passorder 下单
            passorder(23, 1101, ContextInfo.account_id, stock_code, 5, -1, ContextInfo.trade_vol, ContextInfo)
            
    # 平仓逻辑:日线超买 (或者可以加入周线趋势反转作为平仓条件)
    elif current_pos > 0:
        # 止盈/离场条件:日线进入超买区,或者周线趋势转弱
        if oscillator_status == 'overbought' or trend_direction == -1:
            print(f"[{ContextInfo.get_bar_timetag(ContextInfo.barpos)}] 触发卖出: 日线超买或趋势反转")
            passorder(24, 1101, ContextInfo.account_id, stock_code, 5, -1, current_pos, ContextInfo)

代码关键点解析

  1. 跨周期数据获取 (get_market_data_ex)

    • 策略核心在于同时获取 周线 (1w)日线 (1d) 数据。
    • get_macd_trend 函数中指定 period='1w' 来获取周线数据计算 MACD。
    • get_kdj_signal 函数中指定 period='1d' 来获取日线数据计算 KDJ。
  2. 指标计算 (talib)

    • 使用了 talib.MACD 计算趋势。埃尔德的规则是看 MACD 柱状图(Histogram)的斜率,即 hist[-1] > hist[-2] 代表多头力量增强。
    • 使用了 talib.STOCH 计算随机指标。当 K 值低于 30 时视为超卖(回调到位),是顺大势逆小势的买点。
  3. 交易执行 (passorder)

    • opType=23:股票买入。
    • opType=24:股票卖出。
    • prType=5:使用最新价下单(模拟市价成交)。

如何使用

  1. 回测

    • 在 QMT 策略编辑器界面,点击“模型回测”。
    • 主图周期选择 日线
    • 选择一个标的(如 600000.SH 浦发银行)和回测时间段。
    • 点击开始回测,查看结果。
  2. 实盘/模拟盘

    • 修改 init 函数中的 ContextInfo.account_id 为您真实的资金账号。
    • 将策略加载到运行界面,确保主图是日线周期。
    • 点击运行。

常见问题 (Q&A)

Q: 为什么回测时没有交易?
A:

  1. 检查回测时间段是否足够长(因为需要计算周线 MACD,至少需要几十周的数据)。
  2. 检查 ContextInfo.account_id 是否设置正确(回测模式下通常不需要真实账号,但代码中保留了设置)。
  3. 这种策略是趋势跟踪+回调买入,如果市场一直单边下跌或没有明显回调,可能不会触发信号。

Q: 如何修改为做空逻辑(期货)?
A:

  1. get_macd_trend 中判断 trend_direction == -1(周线向下)。
  2. get_kdj_signal 中判断 oscillator_status == 'overbought'(日线超买)。
  3. 修改 passorderopType 为期货对应的开空(如 0 开多,3 开空,具体参考 QMT 文档)。

Q: 为什么使用 get_market_data_ex 而不是 get_market_data?
A: get_market_data_ex 是 QMT 推荐的新版接口,返回的数据结构更清晰(字典包含 DataFrame),且支持更灵活的参数配置,处理多股多周期数据更稳定。