跳转到内容

取消市场扫描器订阅

cancelScannerSubscription(reqId) 用来取消市场扫描器订阅。只要某个扫描结果不再需要继续更新,就应该主动取消,避免 TWS 继续维护无用订阅。

取消时只传一个参数:之前请求扫描订阅时使用的 reqId

官方参考:IBKR Campus - Cancel Market Scanner Subscription

app.reqScannerSubscription(98001, subscription, [], [])
# 等待 scannerDataEnd() 或拿到足够结果后取消
app.cancelScannerSubscription(98001)

98001 必须和请求时的 reqId 一致。不要拿订单 ID、合约 ID 或行情 ticker ID 混用。

if app.ready.wait(10):
req_id = 98001
app.reqScannerSubscription(req_id, subscription, [], [])
# 等待本轮扫描结果结束,或者根据业务设置超时。
app.scan_done.wait(12)
# 不再需要扫描器更新时取消。
app.cancelScannerSubscription(req_id)

示例运行中,扫描结果已经正常返回 5 行,取消后 TWS 又返回了下面的提示:

ERROR=reqId=98001;code=162;msg=历史市场数据服务错误消息:API scanner subscription cancelled: 98001

这个提示的重点是 API scanner subscription cancelled,表示扫描器订阅已经被取消。虽然它通过 error() 回调出现,但在“已收到数据后主动取消”的场景里,可以按正常取消状态处理。

如果还没有收到任何 scannerData() 就出现 162,则要结合上下文判断:可能是主动取消太早,也可能是扫描条件不支持、过滤过窄或 TWS 没有返回结果。

场景是否取消
页面关闭应该取消。
用户切换扫描条件先取消旧 reqId,再发起新请求。
已拿到足够结果可以取消。
长时间无结果可以取消并提示用户放宽条件。
程序退出先取消订阅,再断开连接更干净。
问题说明
取消错 reqIdTWS 不会取消原来的扫描订阅。
重复使用同一个 reqId多个请求混在一起,回调难以区分。
没有等待 scannerDataEnd()可能只拿到部分结果就取消。
162 当成失败主动取消后出现 162 通常表示取消已经生效。

为每个扫描订阅维护一个状态对象,记录 reqId、扫描条件、已收到的结果和是否已取消。这样在界面或日志中可以清楚显示“请求中、已完成、已取消、无结果、出错”等状态。