quickTrade 是 QMT passorder 函数的关键参数,决定委托是立即发送还是经过确认弹窗流程。取值为 0 时通过确认弹窗下单,取值为 1 时在当前 Bar 的 handlebar 中立即触发,取值为 2 时在 subscribe 回调或 run_time 定时任务中触发。正确选择 quickTrade 值是委托成功执行的前提。
QMT passorder 函数与 quickTrade 参数
passorder 是 QMT 内置 Python 的底层下单函数,quickTrade 是其参数之一。passorder 的完整参数包括:操作类型、委托类型、账户 ID、品种代码、价格类型、价格、数量、quickTrade 和 ContextInfo。quickTrade 参数控制委托的发送方式和生效上下文。
passorder 是最底层的下单接口,order_volume、order_value 等便捷函数内部最终都调用 passorder。quickTrade 参数的取值决定了委托是在哪个执行上下文中发送、是否需要用户手动确认。选择错误的 quickTrade 值会导致委托无法发送或需要手动确认,是策略下单失败的常见原因。
小建议 理解 quickTrade 三个取值的区别是实盘交易的基础。在使用 passorder 前,先明确当前代码处于哪个执行上下文(handlebar、subscribe 回调还是 run_time 回调),再选择对应的 quickTrade 值。
# passorder 基本调用格式
ContextInfo.passorder(
opType, # 操作类型:0=买入, 1=卖出
orderType, # 委托类型
accountid, # 账户 ID
orderCode, # 品种代码
priceType, # 价格类型
price, # 委托价格
volume, # 委托数量
quickTrade, # 0, 1, 2
ContextInfo # 上下文对象
)
QMT quickTrade=0:确认弹窗下单
quickTrade=0 时,passorder 会弹出确认弹窗,用户需要手动点击确认后委托才会发送。此模式适合学习环境和回测环境,以及需要人工审核每笔委托的场景。
quickTrade=0 是最安全的下单方式,每笔委托都需要人工确认,可以有效防止策略错误导致的非预期交易。但这种方式不适合自动化交易,因为弹窗会阻塞策略执行,且在非交易时段或无人值守时无法完成下单。
小建议 在策略开发和调试阶段使用 quickTrade=0,逐笔确认委托的正确性。策略验证通过后,在仿真交易环境中切换为 quickTrade=1 或 2 进行自动化测试。切勿在真实交易环境中使用 quickTrade=0 进行自动化策略运行。
def handlebar(ContextInfo):
if not ContextInfo.is_last_bar():
return
# quickTrade=0:弹出确认窗口
ContextInfo.passorder(
0, 1101, ContextInfo.accountid,
'000001.SZ', 11, 10.5, 100,
0, # quickTrade=0,需手动确认
ContextInfo
)
QMT quickTrade=1:handlebar 中立即触发
quickTrade=1 时,passorder 不弹出确认窗口,委托在当前 Bar 的 handlebar 执行上下文中立即发送。此模式仅适用于 handlebar 函数内部,不能在 subscribe 回调或 run_time 回调中使用。
quickTrade=1 的核心约束是"必须在 handlebar 上下文中调用"。QMT 的交易系统在 handlebar 执行期间允许发送委托,handlebar 结束后交易窗口关闭。如果在非 handlebar 上下文(如 subscribe 回调)中使用 quickTrade=1,委托将无法发送。
小建议 在 handlebar 中进行 K 线信号驱动的交易时,使用 quickTrade=1。确保 passorder 调用位于 handlebar 函数的执行路径上,且在 is_last_bar() 判断之后。避免在 handlebar 调用的辅助函数中使用 quickTrade=1 时丢失上下文信息。
def handlebar(ContextInfo):
if not ContextInfo.is_last_bar():
return
close = ContextInfo.get_close_price()
closes = ContextInfo.get_history_data('close', 20)
if closes and len(closes) >= 20:
ma20 = sum(closes) / len(closes)
if close > ma20:
# quickTrade=1:在 handlebar 中立即下单
ContextInfo.passorder(
0, 1101, ContextInfo.accountid,
'000001.SZ', 11, close, 100,
1, # quickTrade=1,handlebar 上下文
ContextInfo
)
print(f'买入信号触发,价格: {close}')
QMT quickTrade=2:回调与定时任务中触发
quickTrade=2 时,passorder 不弹出确认窗口,委托在 subscribe 回调函数或 run_time 定时任务的执行上下文中立即发送。此模式适用于非 handlebar 上下文的自动化交易场景。
quickTrade=2 解决了在 subscribe 回调和 run_time 回调中下单的需求。这些回调不在 handlebar 的执行上下文中,使用 quickTrade=1 无法发送委托,必须使用 quickTrade=2。典型场景包括:subscribe 回调中的实时止损下单、run_time 定时任务中的定时调仓。
小建议 在 subscribe 回调和 run_time 回调中下单时,务必使用 quickTrade=2。在 order_callback 和 deal_callback 等委托回报回调中也应使用 quickTrade=2。使用 quickTrade=2 时要特别注意风控,因为回调可能在短时间内多次触发,需要添加防重复下单逻辑。
def init(ContextInfo):
ContextInfo.subscribe_quote('000001.SZ', 0, 'on_quote', ContextInfo)
ContextInfo.position = 100
ContextInfo.stop_loss_price = 10.0
ContextInfo.order_sent = False
def on_quote(ContextInfo, accountid, tick):
# subscribe 回调中使用 quickTrade=2
if ContextInfo.position > 0 and not ContextInfo.order_sent:
if tick.m_dLastPrice <= ContextInfo.stop_loss_price:
ContextInfo.passorder(
1, 1101, accountid,
'000001.SZ', 14, 0, ContextInfo.position,
2, # quickTrade=2,回调上下文
ContextInfo
)
ContextInfo.order_sent = True # 防止重复下单
print(f'止损单已发送,价格: {tick.m_dLastPrice}')
QMT quickTrade 三种取值的适用场景对比
quickTrade 的三种取值在确认方式、执行上下文和适用环境上存在明确区别。
| 对比维度 | quickTrade=0 | quickTrade=1 | quickTrade=2 |
|---|---|---|---|
| 确认弹窗 | 有,需手动确认 | 无,立即发送 | 无,立即发送 |
| 执行上下文 | 任意上下文 | 仅 handlebar | subscribe 回调、run_time 回调 |
| 适用环境 | 学习环境、回测环境 | 仿真交易环境、真实交易环境 | 仿真交易环境、真实交易环境 |
| 是否阻塞 | 是,等待用户确认 | 否 | 否 |
| 典型场景 | 开发调试、人工审核 | K 线信号驱动下单 | 实时止损、定时调仓 |
小建议 根据执行上下文选择 quickTrade 值:handlebar 中用 1,回调中用 2,调试时用 0。在策略从开发到上线的过程中,按 quickTrade=0 -> 1/2 的顺序逐步切换,确保每个阶段的委托行为符合预期。
QMT quickTrade 常见错误
开发者在使用 quickTrade 时常犯以下错误,导致委托无法发送或行为异常。
| 错误 | 原因 | 后果 | 解决方法 |
|---|---|---|---|
| 在 subscribe 回调中使用 quickTrade=1 | 回调不在 handlebar 上下文 | 委托无法发送 | 改用 quickTrade=2 |
| 在 run_time 回调中使用 quickTrade=1 | 回调不在 handlebar 上下文 | 委托无法发送 | 改用 quickTrade=2 |
| 在实盘自动化策略中使用 quickTrade=0 | 弹窗阻塞策略执行 | 策略卡死等待确认 | 改用 quickTrade=1 或 2 |
| 回调中未做防重复处理 | 回调可能多次触发 | 重复下单 | 添加状态标记防止重复 |
| 在 handlebar 中对非最新 Bar 下单 | 历史回放阶段触发 | 回测中异常下单 | 添加 is_last_bar() 判断 |
小建议 最常见的错误是在 subscribe 回调中使用 quickTrade=1。记住规则:handlebar 中用 1,回调中用 2。在回调中下单时,务必添加防重复下单的标记变量,并在 order_callback 中重置标记。
def init(ContextInfo):
ContextInfo.subscribe_quote('000001.SZ', 0, 'on_quote', ContextInfo)
ContextInfo.last_order_bar = -1 # 防重复标记
def on_quote(ContextInfo, accountid, tick):
# 错误写法:quickTrade=1 在回调中无效
# ContextInfo.passorder(..., 1, ContextInfo) # 不会发送
# 正确写法:quickTrade=2
if tick.m_dLastPrice > 15:
# 防重复:同一时间只发一次
current_time = ContextInfo.get_bar_timetag(ContextInfo.barpos)
if ContextInfo.last_order_bar != current_time:
ContextInfo.passorder(
0, 1101, accountid,
'000001.SZ', 12, tick.m_dLastPrice, 100,
2, # 正确:回调中使用 2
ContextInfo
)
ContextInfo.last_order_bar = current_time
print(f'回调下单成功,价格: {tick.m_dLastPrice}')
QMT 回测环境中 quickTrade 的行为
在回测环境中,passorder 的委托为模拟委托,不会真实发送到交易所。quickTrade 参数在回测中的行为与实时环境有所不同:回测中不弹出确认弹窗,委托按回测引擎的规则模拟执行。
回测环境中 quickTrade=0 不会弹出确认窗口(回测无人交互),委托直接按模拟方式处理。回测中的委托成交取决于回测引擎的撮合规则,通常以 K 线的开盘价、收盘价或指定价格模拟成交。quickTrade=1 和 quickTrade=2 在回测中的行为基本一致,都按模拟方式处理。
小建议 在回测中无需纠结 quickTrade 的取值,因为回测引擎会统一处理。但从代码可移植性角度,建议在回测代码中也按照实时环境的规则选择 quickTrade 值(handlebar 中用 1,回调中用 2),这样代码切换到实时环境时无需修改。
def handlebar(ContextInfo):
if not ContextInfo.is_last_bar():
return
close = ContextInfo.get_close_price()
if close > 10:
# 回测中 quickTrade 值不影响模拟撮合
# 但建议按实时规则使用,便于代码迁移
ContextInfo.passorder(
0, 1101, ContextInfo.accountid,
'000001.SZ', 11, close, 100,
1, # 按实时规则:handlebar 中用 1
ContextInfo
)