接收市场扫描器结果
scannerData() 是市场扫描器每一条结果的回调。一次扫描通常会返回多条 scannerData(),最后用 scannerDataEnd() 表示本轮结果结束。
扫描器返回的是“符合条件的合约列表”,不是价格行情。最重要的字段通常是 rank、contractDetails.contract.symbol 和 contractDetails.contract.conId。
官方参考:IBKR Campus - Receive Market Scanner Subscription
def scannerData( self, reqId: int, rank: int, contractDetails, distance: str, benchmark: str, projection: str, legsStr: str,) -> None: ...| 字段 | 中文说明 |
|---|---|
reqId | 请求编号,用来区分是哪一个扫描订阅返回的数据。 |
rank | 结果排名,从 0 开始。 |
contractDetails | 合约详情对象,里面包含 contract、交易类别、最小价格变动等信息。 |
distance | IBKR 保留字段,部分扫描类型可能返回距离或排序辅助信息。 |
benchmark | IBKR 保留字段,部分扫描类型可能返回基准信息。 |
projection | IBKR 保留字段,部分扫描类型可能返回投影信息。 |
legsStr | 组合腿信息,主要用于 EFP 或组合类扫描。 |
distance、benchmark、projection、legsStr 经常为空字符串,这是正常现象。不要因为这些字段为空就丢弃结果,核心合约信息通常在 contractDetails.contract 里。
读取合约信息
Section titled “读取合约信息”def scannerData(self, reqId, rank, contractDetails, distance, benchmark, projection, legsStr) -> None: contract = contractDetails.contract
print({ "排名": rank, "代码": contract.symbol, "证券类型": contract.secType, "交易所": contract.exchange, "货币": contract.currency, "合约ID": contract.conId, })拿到 conId 后,后续可以更稳定地请求行情或历史数据,因为 conId 比单纯的 symbol 更明确。
SCAN=reqId=98001;rank=0;symbol=PEMX;secType=STK;exchange=SMART;currency=USD;conId=631370177;distance=;benchmark=;projection=SCAN=reqId=98001;rank=1;symbol=UBXG;secType=STK;exchange=SMART;currency=USD;conId=885295404;distance=;benchmark=;projection=SCAN=reqId=98001;rank=2;symbol=SPCL;secType=STK;exchange=SMART;currency=USD;conId=871422657;distance=;benchmark=;projection=SCAN=reqId=98001;rank=3;symbol=GRAF;secType=STK;exchange=SMART;currency=USD;conId=722498821;distance=;benchmark=;projection=SCAN=reqId=98001;rank=4;symbol=CFIT;secType=STK;exchange=SMART;currency=USD;conId=771754279;distance=;benchmark=;projection=这些结果来自一次实际扫描,具体代码和排名会随时间变化。写程序时应该按字段处理,不要把示例里的股票代码写死。
def scannerDataEnd(self, reqId: int) -> None: print("扫描器结果结束:", reqId)scannerDataEnd() 到达后,说明这一轮结果已经发完。它不表示订阅永久结束;如果你不再需要更新,应主动调用 cancelScannerSubscription(reqId)。
结果里没有什么
Section titled “结果里没有什么”扫描器不会在 scannerData() 里返回以下行情字段:
| 你可能想要的字段 | 应该再调用什么 |
|---|---|
| 最新价、买价、卖价 | reqMktData() |
| 历史 K 线 | reqHistoricalData() |
| 逐笔成交 | reqTickByTickData() |
| 合约更完整资料 | reqContractDetails() |
也就是说,扫描器适合做“发现标的”,后续行情和交易逻辑应该用其它接口继续处理。
常见处理方式
Section titled “常见处理方式”| 场景 | 建议 |
|---|---|
| 返回多条结果 | 按 rank 排序展示。 |
| 返回 0 条结果 | 放宽过滤条件,或换一个 scanCode / locationCode。 |
| 想拿实时价格 | 对返回的合约再调用 reqMktData()。 |
| 想拿历史 K 线 | 对返回的合约再调用 reqHistoricalData()。 |