问题描述
你好:
我使用回调函数 on_stock_trade()接收交易订单的成交触发。对于一次轮动交易,涉及的多笔卖出订单可以通过此函数接收到成交触发。而涉及的多笔买入订单,只能接收到第 1 笔买入的成交通知,后面的买入订单就收不到成交触发了。
之前,我使用 xtquant_241014,跑了 4 个多月,都是正常的,但此从上周更新 xtquant_250516 版本后,就出现了上面的问题。
请问,xtquant_250516 版本,有什么改动吗?我需要怎么适配?
解决方案
针对您在升级 xtquant_250516 版本后遇到的 on_stock_trade 回调函数丢失后续买入订单成交通知的问题,这通常与新版本底层的事件推送机制变更、回调线程阻塞或并发处理逻辑有关。以下是详细的排查思路与适配建议:
1. 检查回调函数是否发生阻塞(核心排查点)
在较新的 xtquant 版本中,底层对回调线程的管理可能更加严格。如果在 on_stock_trade 回调函数中执行了耗时操作(如复杂的计算、数据库写入、甚至过多的 print 或 sleep),可能会导致底层事件队列阻塞,从而丢弃后续密集到达的买入成交通知。
适配方案:将回调函数设计为极轻量级的操作,仅负责将数据推入线程安全的队列(如 queue.Queue),由主线程或其他工作线程异步处理。
import queue
import threading
# 创建一个线程安全的队列
trade_queue = queue.Queue()
def on_stock_trade(trade):
# 仅做入队操作,绝对不要在这里做耗时逻辑
trade_queue.put(trade)
# 在主线程或单独的消费者线程中处理
def process_trades():
while True:
trade = trade_queue.get()
# 在这里处理具体的成交逻辑
print("处理成交回报:", trade.stock_code, trade.traded_volume)
2. 检查交易事件订阅机制
确保在初始化并登录交易账号后,正确且完整地调用了交易事件订阅接口。某些版本更新可能会重置默认的订阅行为。
# 确保调用了订阅接口
xt_trader.subscribe(account)
3. 增加主动查询作为兜底机制(推荐架构)
在实盘量化交易中,完全依赖回调(Push)是存在风险的(网络抖动、底层丢包等都可能导致回调丢失)。建议采用**“回调推送 + 定时主动查询”**的双重机制。
既然卖出正常,买入丢失,您可以在轮动买入发出后,通过主动查询接口来核对成交状态:
# 定时或在关键节点主动查询当日成交
trades = xt_trader.query_stock_trades(account)
for trade in trades:
# 对比本地维护的订单状态,更新未通过回调接收到的成交信息
update_local_trade_status(trade)
4. 订单并发发送频率限制
轮动交易时,多笔买入订单如果是通过 for 循环瞬间并发发出的,新版本底层 C++ 核心在处理极高并发的买入回报时可能存在合并或丢包现象。尝试在连续发送买入订单时,增加微小的延迟(如 time.sleep(0.05)),观察回调是否恢复正常。
总结
如果上述代码层面的优化(特别是异步处理回调和增加主动查询兜底)仍无法解决问题,这极有可能是 xtquant_250516 版本在特定并发场景下的底层 Bug。建议:
- 暂时回退到稳定运行的
xtquant_241014版本以保证实盘安全。 - 准备一段最小可复现代码(Minimal Reproducible Example),反馈给迅投 QMT 官方技术支持,等待后续的小版本修复。