总览
逐笔数据用于接收更细粒度的实时成交、买卖报价或中点价。它比普通一档行情更接近 TWS 里的 Time & Sales 窗口,但仍然受到 IBKR 行情订阅、数据行数、交易时段和产品类型限制。
TWS API 使用 reqTickByTickData() 请求逐笔数据,用 cancelTickByTickData() 取消订阅。
官方参考:Tick-by-Tick Data
| 步骤 | 接口 / 回调 | 说明 |
|---|---|---|
| 1 | Contract() | 构造具体合约,例如 AAPL 股票。 |
| 2 | reqTickByTickData() | 请求 Last、AllLast、BidAsk 或 MidPoint。 |
| 3 | tickByTickAllLast() | 接收 Last / AllLast 成交类逐笔数据。 |
| 4 | tickByTickBidAsk() | 接收逐笔买卖报价。 |
| 5 | tickByTickMidPoint() | 接收逐笔中点价。 |
| 6 | cancelTickByTickData() | 取消逐笔订阅。 |
和 reqMktData() 不同,逐笔数据不是“最新报价状态”,而是连续事件流。程序通常需要把每一笔追加保存,再由策略自己决定是否聚合成 1 秒、1 分钟或成交量 K 线。
tickType | 典型回调 | 中文说明 |
|---|---|---|
Last | tickByTickAllLast() | 普通成交流,适合大多数成交明细展示。 |
AllLast | tickByTickAllLast() | 更完整的成交流,可能包含组合、衍生品、平均价格等 Last 不包含的成交类型。 |
BidAsk | tickByTickBidAsk() | 逐笔买卖报价,适合观察报价变化。 |
MidPoint | tickByTickMidPoint() | 买卖价中点。 |
tickType 区分大小写,写成 last、bidask 或 MIDPOINT 都不等同于官方要求的值。
官方限制要点
Section titled “官方限制要点”| 限制 | 说明 |
|---|---|
| 版本要求 | 逐笔实时数据需要较新的 TWS 与 API 版本。旧环境要先升级 TWS 和 API 包。 |
| 同合约重复请求 | 同一个合约不要在 15 秒内反复请求逐笔数据。切换 Last、BidAsk、MidPoint 也应按同一合约限制处理。 |
| 同时订阅数量 | 逐笔订阅数量受账户市场数据额度影响,不适合一次订阅大量合约。 |
| 期权实时逐笔 | 期权没有实时逐笔数据;期权逐笔只能走历史逐笔接口。 |
| 指数逐笔 | 指数逐笔只覆盖官方支持的部分指数。 |
| 组合合约 | 组合合约不支持逐笔数据。 |
| 产品类型差异 | 不是所有产品都支持 Last、AllLast、BidAsk、MidPoint 四种类型。外汇等产品应按实际返回和官方支持范围处理。 |
| 历史补点 | numberOfTicks 大于 0 时,请求开始阶段会先补一段近期逐笔,再进入实时订阅;大量回补应使用历史逐笔接口。 |
AAPL 合约示例
Section titled “AAPL 合约示例”from ibapi.contract import Contract
def aapl_stock() -> Contract: """AAPL 股票合约。逐笔数据也要先写清楚合约。""" contract = Contract() contract.symbol = "AAPL" contract.secType = "STK" contract.exchange = "SMART" contract.currency = "USD" contract.primaryExchange = "NASDAQ" return contract参考边界样例
Section titled “参考边界样例”TWS 连接正常时,逐笔请求可以发送到 TWS:
CONNECTED=TrueCONTRACT=AAPL STK SMART NASDAQ USDREQUESTS=97901:Last:ignoreSize=False,97902:BidAsk:ignoreSize=True,97903:MidPoint:ignoreSize=False,97904:AllLast:ignoreSize=False如果账户没有 AAPL 对应的 API 实时行情权限,三类回调都不会返回数据。本机样本中四个逐笔请求都被 10089 拦截,随后取消未建立的订阅返回 300:
LAST_ROWS=0BIDASK_ROWS=0MIDPOINT_ROWS=0ERROR=reqId=97901;type=Last;code=10089;msg=请求的市场数据对于API来说需要额外订阅。ERROR=reqId=97902;type=BidAsk;code=10089;msg=请求的市场数据对于API来说需要额外订阅ERROR=reqId=97903;type=MidPoint;code=10089;msg=请求的市场数据对于API来说需要额外订阅ERROR=reqId=97904;type=AllLast;code=10089;msg=请求的市场数据对于API来说需要额外订阅外汇等产品还可能表现为 10189。例如 EUR.USD 的 Last / AllLast 请求可能返回:
ERROR=reqId=97901;type=Last;code=10189;msg=请求跳动点数据失败。:No historical market data for EUR/CASH@FXSUBPIP Last 0ERROR=reqId=97904;type=AllLast;code=10189;msg=请求跳动点数据失败。:No historical market data for EUR/CASH@FXSUBPIP AllLast 0这不是 Python 代码错误,而是行情订阅、产品支持或逐笔类型不匹配问题。模拟账户如果没有共享真实账户的市场数据,也会遇到同样错误。
使用逐笔数据前,至少确认:
- 真实账户或模拟账户已经有对应市场实时行情订阅。
- 模拟账户已共享真实账户市场数据权限。
- 没有另一台 TWS / IB Gateway 占用同一行情权限。
- 在目标市场交易时段内测试,尤其是股票逐笔成交。
如果没有权限,程序通常只会进入 error() 回调,不会收到逐笔数据。