🚀 AI 一键生成 qmt 策略代码

QMT量化平台Level2行情重复订阅机制与反订阅指南

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

问题描述

如果使用L2数据重复订阅会发生什么

目前使用的是中金的L2 当之前已经订阅过L2数据如果重复订阅会发生什么?

如果重复订阅了 想反订阅 是使用后面订阅返回的订阅号还是?

解决方案

在 QMT 平台中订阅 Level2(L2)行情数据时,使用的是 ContextInfo.subscribe_quote() 接口。针对您提到的重复订阅和反订阅问题,以下是详细的机制解释和处理建议:

1. 重复订阅 L2 数据会发生什么?

在 QMT 中,每一次调用 subscribe_quote 函数,系统都会生成一个新的订阅任务,并返回一个全新的、唯一的订阅号(subId。即使您订阅的是同一个标的、同一个周期(如 L2 数据),系统也不会自动覆盖之前的订阅。

重复订阅的后果:

  • 回调函数被多次触发:如果您为同一个标的重复订阅了 N 次,那么每当该标的有一笔新的 L2 行情推送时,您绑定的回调函数(callback)就会被触发 N 次。
  • 性能损耗与逻辑错误:重复触发会导致您的策略进行大量冗余计算,严重时可能引起系统卡顿、延迟,甚至导致策略内部的下单逻辑被重复执行(例如重复开仓)。

2. 重复订阅后,如何进行反订阅?

反订阅使用的是 ContextInfo.unsubscribe_quote(subId) 接口,它严格依赖于订阅时返回的 subId

  • 使用哪个订阅号?:如果您重复订阅了多次,您会得到多个不同的 subId。如果您只使用最后一次返回的 subId 进行反订阅,那么仅仅只会取消最后一次的订阅任务,之前订阅的任务依然在后台运行,回调函数依然会被触发。
  • 正确的做法:要完全取消该标的的订阅,您必须将每一次订阅返回的 subId 都记录下来,并对每一个 subId 都调用一次 unsubscribe_quote(subId)

3. 最佳实践:如何避免重复订阅?

为了避免重复订阅带来的麻烦,建议在策略中维护一个订阅状态字典,或者利用 QMT 提供的 ContextInfo.get_all_subscription() 接口来检查当前已有的订阅。

示例代码:使用字典管理订阅状态

# 在 init 中初始化一个字典用于保存订阅号
def init(ContextInfo):
    ContextInfo.my_subs = {}

def on_quote(datas):
    print("收到L2数据:", datas)

def subscribe_l2(ContextInfo, stock_code):
    # 检查是否已经订阅过
    if stock_code in ContextInfo.my_subs:
        print(f"{stock_code} 已经订阅过,请勿重复订阅!")
        return
    
    # 发起订阅并记录 subId
    # 注意:订阅 L2 快照使用 'l2quoteaux',L2 逐笔使用 'tick' 等,具体视需求而定
    sub_id = ContextInfo.subscribe_quote(stock_code, 'l2quoteaux', 'none', on_quote)
    ContextInfo.my_subs[stock_code] = sub_id
    print(f"订阅成功,标的: {stock_code}, 订阅号: {sub_id}")

def unsubscribe_l2(ContextInfo, stock_code):
    # 检查是否存在该订阅
    if stock_code in ContextInfo.my_subs:
        sub_id = ContextInfo.my_subs[stock_code]
        ContextInfo.unsubscribe_quote(sub_id)
        # 反订阅后从字典中移除
        del ContextInfo.my_subs[stock_code]
        print(f"反订阅成功,标的: {stock_code}, 订阅号: {sub_id}")
    else:
        print(f"{stock_code} 未被订阅,无需反订阅。")

总结:
千万不要在 handlebar 等高频触发的函数中无条件地调用 subscribe_quote。始终保持“按需订阅、记录 subId、精准反订阅”的良好习惯,可以有效保障量化策略的稳定运行。