3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
这是一个基于亚历山大·埃尔德(Alexander Elder)博士提出的**三重滤网(Triple Screen)**交易系统的 QMT 策略实现代码。
三重滤网系统通过三个不同的时间维度来过滤交易信号,提高胜率:
请在 QMT 的策略编辑器中新建一个 Python 策略,并将以下代码复制进去。
注意:
pandas 和 talib 库(QMT 自带环境通常已包含)。# -*- 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)
跨周期数据获取 (get_market_data_ex):
1w) 和 日线 (1d) 数据。get_macd_trend 函数中指定 period='1w' 来获取周线数据计算 MACD。get_kdj_signal 函数中指定 period='1d' 来获取日线数据计算 KDJ。指标计算 (talib):
talib.MACD 计算趋势。埃尔德的规则是看 MACD 柱状图(Histogram)的斜率,即 hist[-1] > hist[-2] 代表多头力量增强。talib.STOCH 计算随机指标。当 K 值低于 30 时视为超卖(回调到位),是顺大势逆小势的买点。交易执行 (passorder):
opType=23:股票买入。opType=24:股票卖出。prType=5:使用最新价下单(模拟市价成交)。回测:
实盘/模拟盘:
init 函数中的 ContextInfo.account_id 为您真实的资金账号。Q: 为什么回测时没有交易?
A:
ContextInfo.account_id 是否设置正确(回测模式下通常不需要真实账号,但代码中保留了设置)。Q: 如何修改为做空逻辑(期货)?
A:
get_macd_trend 中判断 trend_direction == -1(周线向下)。get_kdj_signal 中判断 oscillator_status == 'overbought'(日线超买)。passorder 的 opType 为期货对应的开空(如 0 开多,3 开空,具体参考 QMT 文档)。Q: 为什么使用 get_market_data_ex 而不是 get_market_data?
A: get_market_data_ex 是 QMT 推荐的新版接口,返回的数据结构更清晰(字典包含 DataFrame),且支持更灵活的参数配置,处理多股多周期数据更稳定。