3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在 QMT 平台中订阅 Level2(L2)行情数据时,使用的是 ContextInfo.subscribe_quote() 接口。针对您提到的重复订阅和反订阅问题,以下是详细的机制解释和处理建议:
在 QMT 中,每一次调用 subscribe_quote 函数,系统都会生成一个新的订阅任务,并返回一个全新的、唯一的订阅号(subId)。即使您订阅的是同一个标的、同一个周期(如 L2 数据),系统也不会自动覆盖之前的订阅。
重复订阅的后果:
callback)就会被触发 N 次。反订阅使用的是 ContextInfo.unsubscribe_quote(subId) 接口,它严格依赖于订阅时返回的 subId。
subId。如果您只使用最后一次返回的 subId 进行反订阅,那么仅仅只会取消最后一次的订阅任务,之前订阅的任务依然在后台运行,回调函数依然会被触发。subId 都记录下来,并对每一个 subId 都调用一次 unsubscribe_quote(subId)。为了避免重复订阅带来的麻烦,建议在策略中维护一个订阅状态字典,或者利用 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、精准反订阅”的良好习惯,可以有效保障量化策略的稳定运行。