问题描述
解决方案
在 QMT 中,默认的交易机制是K线走完确认信号后,在下一根K线的第一个Tick下单。
如果您希望在信号触发的当前K线(盘中)立即下单,主要有两种方法:
- 使用
passorder函数的quickTrade参数(推荐):将该参数设置为1。 - 使用
do_order函数:强制立即执行当前产生的信号(常用于日线策略在收盘前几分钟提前下单)。
以下是详细说明和代码实现。
方法一:设置 quickTrade=1 (最常用)
在调用 passorder 函数时,第 9 个参数是 quickTrade。
- 0 (默认):当前K线走完,下一根K线开盘下单。
- 1 (立即下单):只要
handlebar在最新一根K线(ContextInfo.is_last_bar()为 True)运行时被调用且条件满足,立即发出委托,不等待K线结束。
代码示例
# -*- coding: gbk -*-
def init(ContextInfo):
# 设置资金账号
ContextInfo.accid = '6000000000' # 请替换为您的实际账号
ContextInfo.set_account(ContextInfo.accid)
# 设置股票池
ContextInfo.set_universe(['600000.SH'])
def handlebar(ContextInfo):
# 获取当前K线索引
index = ContextInfo.barpos
# 获取当前主图代码
code = ContextInfo.stockcode
# 获取收盘价
close_data = ContextInfo.get_market_data(['close'], stock_code=[code], count=1, period=ContextInfo.period)
if code not in close_data or len(close_data[code]) == 0:
return
current_price = close_data[code]['close'][-1]
# 示例策略逻辑:价格大于 10 元时买入
# 注意:在实盘中,handlebar 会在每个 tick 更新时调用。
# 如果不加控制,可能会导致一个K线内重复下单。
# 建议配合全局变量或持仓判断来防止单根K线重复交易。
# 获取当前持仓,防止重复买入
positions = get_trade_detail_data(ContextInfo.accid, 'stock', 'position')
has_position = False
for pos in positions:
if pos.m_strInstrumentID == code and pos.m_nVolume > 0:
has_position = True
break
if current_price > 10.0 and not has_position:
print(f"触发立即下单信号,当前价: {current_price}")
# passorder 参数详解:
# opType: 23 (买入)
# orderType: 1101 (单股单账号普通股/手下单)
# accountid: 账号
# orderCode: 代码
# prType: 5 (最新价)
# modelprice: -1 (使用prType报价)
# volume: 100 (股数)
# strategyName: "my_strategy" (策略名,不可省略,否则无法传递后面的参数)
# quickTrade: 1 (重点:设置为 1 代表立即下单)
# userOrderId: "remark" (备注)
# ContextInfo: 上下文对象
passorder(23, 1101, ContextInfo.accid, code, 5, -1, 100, "my_strategy", 1, "buy_signal", ContextInfo)
方法二:使用 do_order 函数
do_order 通常用于日线级别的策略,在收盘前(例如 14:55)强制将本该在明天开盘发的信号在今天发出。它会把上一根K线(或者当前未走完的K线视为已完成)生成的信号立即执行。
代码示例
# -*- coding: gbk -*-
import time
def init(ContextInfo):
ContextInfo.accid = '6000000000'
ContextInfo.set_account(ContextInfo.accid)
ContextInfo.set_universe(['600000.SH'])
def timetag_to_datetime(timetag, format):
import time
return time.strftime(format, time.localtime(timetag / 1000))
def handlebar(ContextInfo):
# 正常的交易逻辑,使用普通的下单函数(quickTrade默认为0)
# 这里的 order_lots 默认是在下一根K线才发单
order_lots(ContextInfo.stockcode, 1, ContextInfo, ContextInfo.accid)
# 获取当前 Tick 的时间
ticktimetag = ContextInfo.get_tick_timetag()
if ticktimetag == 0:
return
# 格式化时间为 HHMMSS
int_time = int(timetag_to_datetime(ticktimetag, '%H%M%S'))
# 设定在 14:55:00 到 14:55:05 之间强制触发下单
# 这样可以将原本要在明日开盘执行的信号,提前到今日收盘前执行
if 145500 <= int_time < 145505:
print("收盘前强制触发信号")
do_order(ContextInfo)
总结
| 需求场景 | 推荐方法 | 关键设置 |
|---|---|---|
| 盘中即时交易 (如分钟线突破、Tick级止损) | 方法一 | passorder(..., quickTrade=1, ...) |
| 日线收盘前抢跑 (如日线策略在14:55执行) | 方法二 | 配合时间判断调用 do_order(ContextInfo) |
Q&A
Q: 设置 quickTrade=1 后,回测结果会受影响吗?
A: quickTrade 参数在回测模式下通常无效(回测通常严格遵循K线收盘结算机制)。但在实盘或模拟交易模式下,它决定了信号是立即发出还是等待K线结束。
Q: 为什么使用了 quickTrade=1 还是没有成交?
A: 请检查以下几点:
passorder的参数顺序是否正确。quickTrade是第9个参数,因此第8个参数strategyName必须填写(可以填空字符串""或策略名称),不能跳过。- 是否处于
ContextInfo.is_last_bar()为True的状态(即最新的实时行情)。 - 是否有风控限制或资金不足。
Q: quickTrade=2 是什么意思?
A: quickTrade=2 表示不判断 Bar 的状态,即使在历史 K 线上也会触发下单。这通常用于极其特殊的调试场景,实盘中请勿使用,否则策略启动加载历史数据时可能会导致大量错误下单。