请求市场扫描器订阅
reqScannerSubscription() 用来提交一个市场扫描器订阅。你需要先创建 ScannerSubscription 对象,再填写扫描条件。
Python 方法签名常见写法如下:
官方参考:IBKR Campus - Request Market Scanner Subscription
app.reqScannerSubscription( reqId, subscription, scannerSubscriptionOptions, scannerSubscriptionFilterOptions,)| 参数 | 中文说明 |
|---|---|
reqId | 请求编号。后续 scannerData()、scannerDataEnd() 和 error() 都会带回同一个编号。 |
subscription | ScannerSubscription 对象,包含扫描范围、规则和过滤条件。 |
scannerSubscriptionOptions | IBKR 保留选项列表,普通开发通常传 []。 |
scannerSubscriptionFilterOptions | 额外过滤条件列表,新版 TWS 支持用 TagValue 扩展过滤。 |
scannerSubscriptionOptions 和 scannerSubscriptionFilterOptions 都是 TagValue 列表。普通股票扫描通常可以先传空列表;需要更细过滤时,再根据 reqScannerParameters() 返回的 XML 选择可用过滤项。
ScannerSubscription 常用属性
Section titled “ScannerSubscription 常用属性”| 属性 | 类型 | 中文说明 |
|---|---|---|
numberOfRows | int | 希望返回的结果数量。官方限制下单个扫描规则最多 50 条。 |
instrument | str | 产品类型,例如 STK 股票。 |
locationCode | str | 市场范围,例如 STK.US.MAJOR 美国主要股票市场。 |
scanCode | str | 扫描排序规则,例如 HOT_BY_VOLUME 成交量活跃。 |
abovePrice / belowPrice | float | 价格上限或下限过滤。 |
aboveVolume | int | 成交量下限过滤。 |
marketCapAbove / marketCapBelow | float | 市值范围过滤,是否可用取决于扫描类型。 |
moodyRatingAbove / moodyRatingBelow | str | 债券评级过滤,主要用于固定收益相关扫描。 |
spRatingAbove / spRatingBelow | str | 标普评级过滤,主要用于固定收益相关扫描。 |
maturityDateAbove / maturityDateBelow | str | 到期日范围过滤,常用于债券或期货类场景。 |
couponRateAbove / couponRateBelow | float | 票息范围过滤,常用于债券扫描。 |
excludeConvertible | bool | 是否排除可转债,适用场景取决于扫描类型。 |
averageOptionVolumeAbove | int | 期权平均成交量过滤,适用于期权相关扫描。 |
scannerSettingPairs | str | 旧式扩展设置字符串;新项目优先考虑 TagValue 过滤。 |
stockTypeFilter | str | 股票类型过滤,具体取值以扫描器参数 XML 为准。 |
这些属性不是每种扫描都支持。写程序时应先从 reqScannerParameters() 返回的 XML 判断可用条件,再给用户开放对应筛选项。
未设置的数值字段在官方 Python API 中通常是 UNSET_DOUBLE 或 UNSET_INTEGER,字符串字段通常是空字符串。它们表示“不启用这个过滤条件”,不是 0。不要为了“字段完整”把所有可选字段都填上,否则很容易把结果过滤到 0 行。
如果不确定某组条件是否合理,可以先在 TWS 的 Advanced Market Scanner / 高级市场扫描器界面里手动选择同样条件。界面能正常创建并返回结果后,再把同样的 instrument、locationCode、scanCode 和过滤条件搬到 API 里。
TagValue 过滤示例
Section titled “TagValue 过滤示例”from ibapi.tag_value import TagValue
filter_options = [ # 市值大于 10,000 美元。字段名称来自扫描器参数 XML。 TagValue("usdMarketCapAbove", "10000"),]
app.reqScannerSubscription(98001, subscription, [], filter_options)过滤条件越多,越容易返回空结果。建议先跑通 instrument、locationCode、scanCode,再逐个增加过滤项。
from __future__ import annotations
import threadingimport time
from ibapi.client import EClientfrom ibapi.scanner import ScannerSubscriptionfrom ibapi.wrapper import EWrapper
class ScannerApp(EWrapper, EClient): def __init__(self) -> None: EClient.__init__(self, self) self.ready = threading.Event() self.done = threading.Event()
def nextValidId(self, orderId: int) -> None: self.ready.set()
def scannerData(self, reqId, rank, contractDetails, distance, benchmark, projection, legsStr) -> None: contract = contractDetails.contract print(rank, contract.symbol, contract.secType, contract.exchange, contract.currency, contract.conId)
def scannerDataEnd(self, reqId: int) -> None: print("扫描结果结束:", reqId) self.done.set()
def hot_us_stocks_by_volume() -> ScannerSubscription: """成交量活跃的美国主要股票。""" subscription = ScannerSubscription() subscription.numberOfRows = 5 subscription.instrument = "STK" subscription.locationCode = "STK.US.MAJOR" subscription.scanCode = "HOT_BY_VOLUME" subscription.abovePrice = 5 subscription.aboveVolume = 100_000 return subscription
app = ScannerApp()app.connect("127.0.0.1", 7497, clientId=98001)
thread = threading.Thread(target=app.run, daemon=True)thread.start()
if app.ready.wait(10): app.reqScannerSubscription(98001, hot_us_stocks_by_volume(), [], [])
app.done.wait(12)app.cancelScannerSubscription(98001)time.sleep(1)app.disconnect()字段选择建议
Section titled “字段选择建议”先用最少字段跑通:
subscription.instrument = "STK"subscription.locationCode = "STK.US.MAJOR"subscription.scanCode = "HOT_BY_VOLUME"跑通后再加过滤:
subscription.numberOfRows = 5subscription.abovePrice = 5subscription.aboveVolume = 100_000如果一开始就加很多条件,返回 0 行时很难判断是权限问题、组合不支持,还是过滤条件太窄。
SCAN_END=TrueSCAN_ROWS=5NON_INFO_ERROR_COUNT=1ERROR=reqId=98001;code=162;msg=历史市场数据服务错误消息:API scanner subscription cancelled: 98001这里 SCAN_ROWS=5 表示订阅成功拿到 5 条结果。后面的 162 是取消订阅后 TWS 发出的提示,核心含义是扫描器订阅已取消;如果数据已经正常返回,可以把它作为取消后的状态消息处理。