问题描述
VARIABLE:cj1=0,hszhishu=0,BBD=0,zhishu=0,tmp=0,tmpshort=0,buypoint=0,sellpoint=0,
profit=0,TestHolding=0,maxzhishu=0,huiche=0,maxhuiche=0,DCS=0,maxprofit=0,
maxDhuiche=0,Dhuiche=0,maxshortprofit=0,hs300bp=0,hstmp=0,TMPzhishu=0;
ORDERTYPE := 1101; // QMT 限价单类型
ACCOUNTID := '580000'; // 实际资金账号
ORDERCODE := STKLABEL(); // 当前标的代码
VOLUME := 5000; // 委托股数
limit_price := ((C-REF(C,1))/REF(C,1))=0.09; // 计算精确涨停价
// MACD 指标计算
DIFF := EMA(CLOSE,12) - EMA(CLOSE,26);
DEA := EMA(DIFF,9);
MACD1 := 2*(DIFF-DEA);
// 修正后的开仓条件
zt_price := ((C-REF(C,1))/REF(C,1))>=0.09; // 精确涨停价
volume_ratio := DYNAINFO(25)/vol; // QMT 量比参数为 17
bk := MACD1 > REF(MACD1,1)
AND REF(MACD1,1) > REF(MACD1,2) // MACD连续两日上升
AND volume\_ratio > 1 // 量比大于1
AND zt\_price // 当前是涨停状态
AND NOT(REF(zt\_price,1)) // 前一日未涨停
AND TIME >= 093000 AND TIME <= 205900 // 交易时间控制
AND TestHolding = 0; // 无现存持仓
// QMT 下单逻辑
IF bk THEN BEGIN;
TestHolding := 1; // 更新持仓状态
groupbuy(VOLUME);
END;
解决方案
QMT 模型不交易的核心原因分析
您提供的代码是一段典型的麦语言/VBA指标公式代码,而在 QMT(迅投极速量化交易平台)中,实现自动化交易和复杂策略回测的核心引擎是基于 Python 语言的。您的模型不交易,主要有以下几个致命问题:
1. 缺少 Python 策略的核心框架
根据 QMT API 文档,一个合法的 Python 策略必须包含两个核心函数:
init(ContextInfo):初始化函数,在策略启动时运行一次,用于设置账号、股票池等。handlebar(ContextInfo):行情驱动函数,每根 K 线(或每个 Tick)运行一次,核心逻辑必须写在这里。
您的代码完全没有这个框架,平台无法识别并执行。
2. 下单函数使用错误
代码中使用了 groupbuy(VOLUME); 进行下单。在 QMT Python API 中,标准的下单函数是 passorder(综合下单)或 order_lots、order_value 等。QMT 并不识别 groupbuy 这个指令。
3. 数据获取与指标计算方式不兼容
在公式语言中,您可以直接使用 C 代表收盘价,REF(C,1) 代表昨日收盘价,MACD 可以直接调用。但在 QMT Python 环境中,您需要使用 ContextInfo.get_market_data() 或 ContextInfo.get_history_data() 来获取历史数据,并使用 Python 库(如 pandas 或 talib)来计算 MACD 指标。
如何将您的逻辑转换为 QMT Python 策略
为了让您的策略在 QMT 中正常运行,我们需要将您的逻辑(MACD连续两日上升 + 量比大于1 + 今日涨停且昨日未涨停)用 Python 重写。以下是一个基础的转换示例框架:
#coding:gbk
import pandas as pd
import numpy as np
def init(ContextInfo):
# 设置交易账号
ContextInfo.accountID = '580000'
ContextInfo.set_account(ContextInfo.accountID)
# 设置运行的股票池(以平安银行为例)
ContextInfo.set_universe(['000001.SZ'])
# 初始化持仓标记
ContextInfo.TestHolding = 0
def handlebar(ContextInfo):
# 获取当前运行的股票代码
stock_code = ContextInfo.stockcode
# 获取过去35天的日线数据(用于计算MACD)
df = ContextInfo.get_market_data(['close', 'volume'], stock_code=[stock_code], period='1d', count=35)
if df.empty or len(df) < 30:
return
close_prices = df['close']
# 1. 计算 MACD (简易计算示例,实际建议引入 TA-Lib)
exp1 = close_prices.ewm(span=12, adjust=False).mean()
exp2 = close_prices.ewm(span=26, adjust=False).mean()
macd_diff = exp1 - exp2
macd_dea = macd_diff.ewm(span=9, adjust=False).mean()
macd_hist = (macd_diff - macd_dea) * 2
# 获取近三天的 MACD 柱
macd_today = macd_hist.iloc[-1]
macd_yest = macd_hist.iloc[-2]
macd_yest2 = macd_hist.iloc[-3]
# 2. 判断涨停逻辑 (简易判断:今日涨幅>=9.5%,昨日涨幅<9.5%)
close_today = close_prices.iloc[-1]
close_yest = close_prices.iloc[-2]
close_yest2 = close_prices.iloc[-3]
pct_today = (close_today - close_yest) / close_yest
pct_yest = (close_yest - close_yest2) / close_yest2
is_zt_today = pct_today >= 0.095
is_zt_yest = pct_yest >= 0.095
# 3. 获取量比 (此处用简易逻辑替代:今日成交量 / 过去5日均量)
vol_today = df['volume'].iloc[-1]
vol_ma5 = df['volume'].iloc[-6:-1].mean()
volume_ratio = vol_today / vol_ma5 if vol_ma5 > 0 else 0
# 4. 综合条件判断
bk = (macd_today > macd_yest) and (macd_yest > macd_yest2) \
and (volume_ratio > 1) \
and is_zt_today \
and not is_zt_yest \
and ContextInfo.TestHolding == 0
# 5. 执行下单
if bk:
# 使用 passorder 下单:23代表股票买入,1101代表单股单账号普通下单,11代表指定价
passorder(23, 1101, ContextInfo.accountID, stock_code, 11, close_today, 5000, 'MyStrategy', 1, 'BuySignal', ContextInfo)
ContextInfo.TestHolding = 1
print(f"{stock_code} 触发买入信号,已发送委托!")
关键修改点说明:
- 引入
init和handlebar:这是 QMT 策略运行的基石。 - 数据获取:使用
ContextInfo.get_market_data获取历史 K 线数据,返回的是pandas.DataFrame格式,方便进行向量化计算。 - 下单函数:替换为 QMT 标准的
passorder函数。参数23表示股票买入,1101表示普通股/手方式下单。 - 全局变量:将
TestHolding等状态变量挂载到ContextInfo对象上,以便在不同的 K 线周期之间传递状态。
建议您在 QMT 的“策略编辑器”中新建一个 Python 模型,将上述代码粘贴进去,并在历史回测中进行调试,查看日志输出(print)以验证逻辑是否按预期触发。