限频行为
Pacing Behavior 指的是:当 API 程序短时间内发送太多消息时,TWS / IB Gateway 怎样处理这些超额请求。
这不是某一个接口的参数,而是整个 TWS API 连接层的行为。无论调用 reqMktData()、reqHistoricalData()、reqContractDetails()、placeOrder() 还是 cancelOrder(),只要请求节奏超过允许范围,都可能受到影响。
官方参考:
IBKR Campus: TWS API Documentation
两种处理方式
Section titled “两种处理方式”TWS / IB Gateway 的 API 设置里有一个选项:
Reject messages above maximum allowed message rate vs. applying pacing可以理解成:
超过最大允许消息速率时,直接拒绝,而不是应用 pacing 排队这个选项会影响超额请求的表现:
| 设置状态 | 表现 | 适合场景 |
|---|---|---|
| 不勾选 | TWS / IB Gateway 尝试按允许速率排队处理,超额请求可能延迟执行 | 更接近默认运行方式 |
| 勾选 | 超过速率的消息更容易被快速拒绝,并返回错误 | 适合开发排查,方便发现哪段代码发得太快 |
两种方式都不是“无限制”。不勾选不代表可以随便发请求;勾选也不代表程序更安全。可靠做法仍然是在程序里自己做请求队列、节流、去重和恢复策略。
错误码 100
Section titled “错误码 100”超过 API 消息速率时,常见错误是:
100 Max rate of messages per second has been exceeded在 Python 的 EWrapper.error() 回调里,通常需要优先判断 errorCode == 100:
from ibapi.wrapper import EWrapper
class App(EWrapper): def error(self, reqId, errorCode, errorString, advancedOrderRejectJson=""): # errorCode=100 表示 API 消息发送太快。 # 不要在这里立刻重试,否则会继续冲击限频。 if errorCode == 100: print(f"触发限频:reqId={reqId}, message={errorString}") self.pause_request_queues(reason="pacing") return
print(f"API 错误:reqId={reqId}, code={errorCode}, message={errorString}")
def pause_request_queues(self, reason: str): # 实际项目里可以暂停行情、历史数据、合约查询、订单等队列。 print(f"暂停请求队列:{reason}")字段解释:
| 字段 | 含义 |
|---|---|
reqId | 触发错误的请求编号;连接级错误可能是 -1 |
errorCode | TWS API 错误码,限频常见为 100 |
errorString | TWS 返回的错误说明 |
advancedOrderRejectJson | 高级拒单信息;普通限频通常用不到 |
不要依赖完整英文错误文本做逻辑判断。不同版本的 TWS / IB Gateway 可能在错误文本里增加 max、rec 等细节,程序逻辑应优先判断错误码。
应用 pacing 排队的风险
Section titled “应用 pacing 排队的风险”不勾选“直接拒绝”时,TWS / IB Gateway 会尝试按允许速率处理请求。这个行为看起来更友好,但有一个隐藏风险:程序以为请求已经立刻执行,实际上它可能已经排队。
容易出问题的场景包括:
- 批量提交订单、改单、撤单。
- 快速切换一批行情订阅。
- 循环拉取大量历史 K 线。
- 前端页面刷新时重复触发同一批请求。
- 错误重试没有退避,失败后立刻再次发送。
如果队列堆得太长,用户看到的可能不是一个清晰异常,而是“数据很慢”“订单状态晚到”“界面等待很久”。所以应用层仍然要自己限速,不能完全依赖 TWS 帮忙排队。
直接拒绝模式的用途
Section titled “直接拒绝模式的用途”勾选 Reject messages above maximum allowed message rate vs. applying pacing 后,超额请求更容易快速返回错误。这个模式适合排查:
- 哪个模块发请求太快。
- 哪类请求没有缓存。
- 是否存在重复订阅。
- 是否有异常重试循环。
- 多个脚本是否同时冲同一个 TWS / IB Gateway。
开发阶段可以临时开启这个选项,让问题更早暴露。正式运行时是否开启,要看系统设计:如果程序已经有完善限流和日志,两种模式都可以运行;如果程序没有限流,任何模式都不可靠。
多次触发后的断线风险
Section titled “多次触发后的断线风险”官方错误说明提到,超过最大消息速率可能导致客户端断开连接。实际表现可能是:
| 表现 | 含义 |
|---|---|
errorCode=100 | TWS 明确提示消息速率过高 |
| socket closed | API Socket 被关闭 |
| connection reset | 连接被对端重置 |
| broken pipe | 程序继续写入已断开的连接 |
收到 100 后,程序应该立即暂停相关队列,而不是继续发送请求。恢复时要降速,并重新检查已经丢失的订阅和未完成任务。
程序恢复流程
Section titled “程序恢复流程”比较稳的处理顺序:
- 记录触发时间、
clientId、reqId、接口名、合约和参数。 - 暂停同类型请求队列,例如历史数据队列先停。
- 取消明显重复或已经过期的请求。
- 等待冷却时间,不要立即重试。
- 降低队列速率后逐步恢复。
- 如果连接已经断开,先重新连接,再重新订阅必要数据。
恢复逻辑不要所有请求一股脑重发。行情订阅、历史数据、订单状态、账户数据应该按优先级恢复。
可以按用途选择:
| 程序类型 | 建议 |
|---|---|
| 学习脚本 | 可以临时勾选直接拒绝,方便发现请求过快 |
| 文档示例脚本 | 程序里保守限流,避免读者一复制就触发错误 |
| 批量历史数据任务 | 使用独立慢速队列,并缓存已经请求过的数据 |
| 自动化交易程序 | 必须在程序层限流,不能依赖 TWS 排队兜底 |
| 多模块系统 | 每个模块有独立队列,同时有全局总速率控制 |
最重要的原则是:限频应该由你的程序主动管理。TWS / IB Gateway 的 pacing 只是保护机制,不应该成为系统设计的一部分。