🚀 AI 一键生成 qmt 策略代码

QMT 平台 deal_callback 成交回报重复触发怎么办?

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

问题描述

大家有没有遇到过deal_callback重复触发的情况?

我按示例写了deal_callback方法,将api返回的数据写入本地数据库,发现会有重复记录,有些是同一时间2条,然后这些记录又再后面一段时间反复触发。这个机制是只要其中任何一只股票触发,就会触发其他股票的也返回一次历史记录吗?

解决方案

遇到 deal_callback 重复触发的情况在量化交易接口中是非常常见的现象。这并不是因为“某一只股票触发导致其他股票返回历史记录”,而是由底层交易柜台的推送机制和订单撮合机制决定的。\n\n### 一、 为什么会出现重复触发或多条记录?\n\n1. 分笔成交(部成):你提到“同一时间有2条记录”,这通常是因为一笔较大的委托单在交易所被拆分成了多笔成交(部分成交)。虽然它们发生的时间几乎相同,但实际上是不同的成交记录,拥有不同的成交数量和成交编号。\n2. 状态同步与断线重连:QMT客户端与底层交易柜台之间会保持状态同步。如果网络出现微小的波动导致重连,或者柜台主动发起状态对账,系统为了防止漏单,会把当天的历史成交记录重新推送一遍。这就导致了你观察到的“后面一段时间反复触发历史记录”。\n3. 委托状态变更伴随推送:有时候订单状态的改变(如部成后撤单)也会触发底层状态的刷新,从而连带推送已有的成交信息。\n\n### 二、 解决方案:如何正确处理并去重?\n\n在处理交易回报(如 deal_callbackorder_callback)时,绝对不能仅仅依赖触发动作本身来作为插入数据库的依据,而必须依赖数据本身的唯一标识符进行去重。\n\n对于 deal_callback 返回的 dealInfo 对象,其唯一标识符是 m_strTradeID(成交编号)。\n\n#### 1. 数据库层面去重(推荐)\n在你的本地数据库中,将 m_strTradeID(成交编号)设置为**唯一索引(Unique Index)**或主键。\n- 如果使用 MySQL/SQLite,可以使用 INSERT IGNOREINSERT ... ON DUPLICATE KEY UPDATE 语句。\n- 这样即使 QMT 反复推送同一笔成交,数据库也会自动忽略重复数据,保证数据的一致性。\n\n#### 2. 代码内存层面去重\n如果你不想给数据库增加压力,可以在 Python 代码中维护一个集合(Set)来记录已经处理过的成交编号:\n\npython\n# 在全局或 init 中初始化一个集合用于记录已处理的成交编号\nprocessed_deals = set()\n\ndef deal_callback(ContextInfo, dealInfo):\n global processed_deals\n \n # 获取成交编号\n trade_id = dealInfo.m_strTradeID\n \n # 如果该成交编号已经处理过,则直接跳过\n if trade_id in processed_deals:\n return\n \n # 记录新的成交编号\n processed_deals.add(trade_id)\n \n # 下面执行你的数据库写入逻辑\n print(f"收到新成交,成交编号: {trade_id}, 证券代码: {dealInfo.m_strInstrumentID}, 成交量: {dealInfo.m_nVolume}")\n # insert_into_db(dealInfo)\n\n\n### 总结\nQMT 的 deal_callback 机制是“状态驱动”而非纯粹的“增量事件驱动”。为了保证数据的绝对安全,底层会进行冗余推送。开发者在接收端必须使用 dealInfo.m_strTradeID 做好幂等性处理(即去重),这是编写稳健量化交易系统的标准做法。