🚀 AI 一键生成 qmt 策略代码

QMT 策略如何处理下单失败?orderError_callback 使用指南

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

问题描述

我的策略在交易时可能会遇到下单失败的情况,如何才能捕获这些错误并进行处理?

解决方案

在 QMT 平台中,交易下单是一个异步过程。要捕获下单失败或委托异常的情况,不能仅依赖下单函数的返回值,而必须使用 交易回报回调函数

主要有两个核心回调函数用于处理错误:

  1. orderError_callback:专门用于捕获下单时的直接错误(如参数错误、资金不足被柜台直接拒绝等)。
  2. order_callback:用于监控委托状态的变化(例如委托变为“废单”状态)。

核心步骤

  1. 初始化账号:在 init 中必须调用 set_account,否则无法接收任何回调。
  2. 实现 orderError_callback:获取具体的错误信息 errMsg
  3. 实现 order_callback:检查 m_nOrderStatus 是否为废单状态(通常为 57),并读取 m_strCancelInfo(废单原因)。

策略代码实现

以下是一个完整的示例代码,展示了如何捕获和处理下单错误:

# -*- coding: gbk -*-

def init(ContextInfo):
    # 1. 设置资金账号 (必须步骤)
    # 请将 '6000000000' 替换为您真实的资金账号
    ContextInfo.accID = '6000000000'
    ContextInfo.set_account(ContextInfo.accID)
    
    print("策略初始化完成,已绑定账号接收回报")

def handlebar(ContextInfo):
    # 示例:在最后一根K线尝试下单
    if not ContextInfo.is_last_bar():
        return
    
    # 这里模拟一个下单操作
    # 实际策略中,这里是您的交易逻辑
    # order_shares(stock_code, amount, style, price, ContextInfo, accountID)
    # 下面这行代码仅作演示,运行时请确保有对应的行情数据
    # order_shares('600000.SH', 100, 'fix', 10.0, ContextInfo, ContextInfo.accID)
    pass

# ==============================================================================
# 错误处理核心函数 1:orderError_callback
# ==============================================================================
def orderError_callback(ContextInfo, orderArgs, errMsg):
    """
    当账号下单出现直接异常时(如参数错误、未登录、柜台拒单),触发此函数
    """
    print("=" * 30)
    print("【警告】捕获到下单异常!")
    print(f"错误信息 (errMsg): {errMsg}")
    
    # 解析下单参数 (orderArgs 是一个对象,包含下单时的参数)
    # 注意:orderArgs 的具体属性取决于具体的下单接口,通常包含 code, price 等
    # 这里可以打印出来辅助调试
    print(f"涉及账号: {ContextInfo.accID}")
    
    # --- 错误处理逻辑 ---
    # 1. 记录日志
    # 2. 停止策略运行 (可选)
    # 3. 发送报警通知 (可选)
    print("=" * 30)

# ==============================================================================
# 错误处理核心函数 2:order_callback
# ==============================================================================
def order_callback(ContextInfo, orderInfo):
    """
    当委托状态发生变化时触发(如:已报、已成、废单、已撤)
    """
    # 获取委托状态
    status = orderInfo.m_nOrderStatus
    
    # 状态码 57 代表 "废单" (ENTRUST_STATUS_JUNK)
    # 状态码 54 代表 "已撤" (ENTRUST_STATUS_CANCELED)
    # 状态码 52 代表 "拒单/部成待撤" (视柜台而定)
    
    if status == 57:
        print("=" * 30)
        print(f"【警告】委托变为废单!委托号: {orderInfo.m_strOrderSysID}")
        print(f"证券代码: {orderInfo.m_strInstrumentID}")
        print(f"废单原因: {orderInfo.m_strCancelInfo}")  # 关键:获取废单的具体原因
        
        # --- 废单处理逻辑 ---
        # 例如:如果是价格超出涨跌停,可以尝试重新计算价格下单
        # 例如:如果是额度不足,停止后续买入
        print("=" * 30)
        
    elif status == 52:
        print(f"【提示】委托被拒绝或部成待撤: {orderInfo.m_strCancelInfo}")

代码详解

  1. ContextInfo.set_account(ContextInfo.accID):

    • 这是最关键的一步。如果不调用此函数,QMT 认为该策略不需要接收交易回报,因此 orderError_callbackorder_callback 永远不会被触发。
  2. orderError_callback(ContextInfo, orderArgs, errMsg):

    • 触发时机: 当下单指令发送那一刻,如果系统检测到错误(例如:账号未登录、资金账号格式错误、下单参数非法),会立即回调此函数。
    • errMsg: 包含具体的错误描述字符串,例如 "账号未登录" 或 "资金不足"。
  3. order_callback(ContextInfo, orderInfo):

    • 触发时机: 委托发送到交易所或柜台后,状态发生变更时。
    • orderInfo 对象: 包含了委托的详细信息。
    • m_nOrderStatus: 这是一个整数,代表状态。57 是最常见的“废单”状态(Junk)。
    • m_strCancelInfo: 如果是废单,这个字段通常包含交易所或柜台返回的具体拒绝原因(例如 "价格超出涨跌停限制"、"没有持仓" 等)。

常见状态码参考 (m_nOrderStatus)

  • 48: 未报
  • 50: 已报
  • 56: 已成
  • 54: 已撤
  • 57: 废单 (重点关注)

通过结合这两个回调函数,您可以覆盖绝大多数下单失败的场景,并根据 errMsgm_strCancelInfo 的内容编写具体的重试或风控逻辑。


Q&A

Q: 为什么我写了 orderError_callback 却从来没有触发过?
A: 请检查 init 函数中是否调用了 ContextInfo.set_account()。如果没有绑定账号,策略无法接收任何交易回报。另外,确保您的运行模式是“实盘”或“模拟交易”,回测模式下对某些错误的模拟可能不完全。

Q: orderError_callbackorder_callback 有什么区别?
A: orderError_callback 通常捕获的是下单请求发出时的错误(比如API调用参数不对,或者本地风控拦截)。order_callback 捕获的是委托产生后的状态变化(比如委托发到了交易所,但因为价格超限被交易所退回,变成了废单)。

Q: 如何在捕获错误后自动重单?
A: 在回调函数中,您可以根据错误信息判断是否需要重单。如果需要,可以再次调用 passorderorder_shares 等函数。但请务必设置一个计数器或标志位,防止因为持续错误导致死循环无限下单(例如资金不足时无限重试)。