🚀 AI 一键生成 qmt 策略代码

QMT/miniqmt 委托失败回调中查询资产与持仓的正确姿势

qmt | 发布时间: 2026/5/25
以下内容由 EasyQuant 生成。

问题描述

可以在on_order_error回调中进行资产和持仓数据的查询吗

我用的券商版 miniqmt 模拟环境,想在委托失败的回调中查询并重置该笔失败委托占用的资金,我这里测试没反应

解决方案

在 QMT 或 miniqmt (xtquant) 的委托失败回调(如 on_order_errororderError_callback)中,理论上是可以调用查询接口的,但强烈不建议直接在回调函数中进行同步的资产和持仓查询。这通常是你测试“没反应”或卡死的主要原因。

为什么在回调中查询会“没反应”?

  1. 线程阻塞与死锁:miniqmt (xtquant) 的回调函数通常运行在底层的 C++ 回调线程中。如果你在这个线程里调用同步的查询接口(如 query_stock_asset),可能会阻塞该线程,甚至与底层通信机制产生死锁,导致程序无响应。
  2. 查询频率限制:券商柜台对资产和持仓的查询有严格的频率限制(通常建议间隔 2-3 秒以上)。如果在短时间内产生大量失败委托,触发密集查询,会被柜台拒绝或导致连接异常。
  3. 数据延迟:委托失败后,柜台的资金解冻可能存在微小的延迟,立即查询可能获取不到最新的可用资金。

正确的解决姿势:异步处理(生产者-消费者模式)

为了避免阻塞回调线程,最佳实践是:在回调函数中仅记录失败的委托信息(放入队列),然后在主线程或专门的业务线程中消费这些信息,并进行资产查询和状态重置。

基于 miniqmt (xtquant) 的异步处理示例:

import time
import threading
import queue
from xtquant import xtdata
from xtquant.xttrader import XtQuantTrader, XtQuantTraderCallback
from xtquant.xttype import StockAccount

# 创建一个线程安全的队列,用于存放失败的委托
error_order_queue = queue.Queue()

class MyTraderCallback(XtQuantTraderCallback):
    def on_order_error(self, error):
        # 回调中只做最简单的操作:将错误信息放入队列
        print(f"[回调] 收到委托失败回报: {error.order_remark}, 错误信息: {error.error_msg}")
        error_order_queue.put(error)

def process_error_orders(trader, account):
    """
    专门处理失败委托的线程函数
    """
    while True:
        try:
            # 阻塞等待队列中的错误委托,超时时间1秒
            error_order = error_order_queue.get(timeout=1.0)
            print(f"[处理线程] 开始处理失败委托: {error_order.order_sysid}")
            
            # 稍微等待一下,确保柜台资金已解冻
            time.sleep(0.5)
            
            # 在这里进行资产查询
            asset = trader.query_stock_asset(account)
            if asset:
                print(f"[处理线程] 当前可用资金: {asset.cash}")
                # 在这里执行你的资金重置或重新下单逻辑
                # reset_my_strategy_fund(error_order, asset.cash)
                
        except queue.Empty:
            continue
        except Exception as e:
            print(f"[处理线程] 处理异常: {e}")

if __name__ == '__main__':
    # 初始化 trader 和 account (此处省略具体的初始化路径和账号)
    path = r'D:\国信证券QMT交易端\userdata_mini'
    session_id = int(time.time())
    trader = XtQuantTrader(path, session_id)
    account = StockAccount('你的资金账号')
    
    callback = MyTraderCallback()
    trader.register_callback(callback)
    
    trader.start()
    trader.connect()
    trader.subscribe(account)
    
    # 启动专门处理错误委托的后台线程
    processor_thread = threading.Thread(target=process_error_orders, args=(trader, account))
    processor_thread.daemon = True
    processor_thread.start()
    
    # 保持主线程运行
    while True:
        time.sleep(1)

总结

  • 不要on_order_errororderError_callback 中直接调用 query_stock_assetget_trade_detail_data
  • 应该使用 queue.Queue 将回调数据传递给主线程或独立的工作线程。
  • 注意查询频率,避免因频繁查询导致账号被限制。