请求下一个有效 ID
下一个有效 ID 是 TWS 分配给 API 客户端的订单编号起点。只要准备调用 placeOrder(),就必须先拿到一个可用的 orderId。
TWS 在连接成功后通常会主动触发一次 nextValidId() 回调。也可以显式调用 reqIds(-1),让 TWS 再返回一次下一个可用订单 ID。官方说明里也强调,reqIds() 的参数会被忽略,常见写法就是传 -1。
app.reqIds(-1)numIds 参数已经废弃。不要把 -1 理解成“请求 -1 个 ID”;它只是一个兼容参数。
| 字段 | 中文说明 |
|---|---|
reqIds(numIds) | 请求 TWS 再发送一次 nextValidId() 回调。 |
numIds | 兼容参数,TWS 会忽略它,通常传 -1。 |
nextValidId(orderId) | TWS 返回下一个可用于下单的订单编号。 |
orderId | placeOrder(orderId, contract, order) 的第一个参数。 |
| 场景 | 是否需要调用 reqIds(-1) |
|---|---|
| 刚连接 TWS | 通常不需要,连接完成后 TWS 会主动返回一次 nextValidId()。 |
| 程序丢失了本地订单编号状态 | 可以调用,用 TWS 返回值重新同步。 |
| 多个 API 客户端同时运行 | 可以调用,但还要结合已看到的 openOrder() / orderStatus() 编号判断。 |
| 每次下单前都调用 | 通常没必要,正确做法是本地保存并递增。 |
reqIds(-1) 不是“预占订单号”。它只是让 TWS 告诉你下一个可用编号。真正消耗编号的是你后续用这个 orderId 发送订单请求。
Python 示例
Section titled “Python 示例”from __future__ import annotations
import threading
from ibapi.client import EClientfrom ibapi.wrapper import EWrapper
class NextValidIdApp(EWrapper, EClient): def __init__(self) -> None: EClient.__init__(self, self) self.ready = threading.Event() self.order_id = None
def nextValidId(self, orderId: int) -> None: # orderId 就是下一次 placeOrder 可以使用的订单编号。 self.order_id = orderId self.ready.set()
app = NextValidIdApp()app.connect("127.0.0.1", 7497, clientId=98200)threading.Thread(target=app.run, daemon=True).start()
if app.ready.wait(10): print("连接后收到订单 ID:", app.order_id)
# 需要重新确认时,可以显式请求。app.reqIds(-1)这段代码只演示 ID 获取,不提交订单。正式下单代码要等 ready 被设置后再继续,否则程序可能还没有收到 TWS 分配的订单编号。
CONNECTED=TrueINITIAL_NEXT_VALID_ID=1REQ_IDS_SENT=TrueREQUESTED_NEXT_VALID_ID_RECEIVED=TrueREQUESTED_NEXT_VALID_ID=1NON_INFO_ERROR_COUNT=0连接握手和显式请求都返回 1。这说明这次测试里的 TWS API 订单序列起点是 1,且中间没有新的 API 订单消耗编号。
| 规则 | 说明 |
|---|---|
orderId 必须唯一 | 同一个客户端不要重复用已经提交过的订单 ID。 |
连接后先等 nextValidId() | 不要在还没拿到 ID 时就下单。 |
| 每次下单后自行递增 | 常见做法是 next_order_id += 1。 |
| 多客户端要小心 | 不同 clientId 或 TWS 手工订单可能影响可见订单和编号判断。 |
| 丢失状态时重新请求 | 程序不知道下一个编号时,可以再次调用 reqIds(-1)。 |
和行情 reqId 的区别
Section titled “和行情 reqId 的区别”orderId 是订单编号,给 placeOrder() 用;行情、历史数据、扫描器等接口里的 reqId 只是请求编号。
二者可以都用整数,但语义不同。写程序时建议分开命名,例如 next_order_id 和 market_data_req_id。
不能写死为 1
Section titled “不能写死为 1”示例里返回 1 只是这次账户和订单序列状态下的结果。只要 TWS 曾经接收过 API 订单,或者其它客户端使用过更大的订单编号,下一次返回值就可能变成更大的数字。
新手最容易犯的错误是把示例输出里的 1 写进程序。正确做法是:每次连接后读取 nextValidId(orderId) 返回的值,再用程序变量保存它。