跳转到内容

建立 API 连接

建立 API 连接,是所有 TWS API 程序的第一步。你的 Python、Java、C# 或 C++ 程序并不是直接连交易所,而是先连接已经登录好的 TWS / IB Gateway。

可以把链路理解成这样:

你的程序 -> Socket 端口 -> TWS / IB Gateway -> IBKR 后端

程序端是客户端,TWS / IB Gateway 是本地服务端。程序先打开 TCP socket,完成 API 版本握手,然后 TWS / IB Gateway 才会把账户、下一个可用订单 ID、连接时间等会话信息回调给程序。

连接代码写对之前,先确认 TWS / IB Gateway 本身已经准备好:

检查项常见值说明
已登录账户模拟账户或真实账户新手建议先用模拟账户
启用 Socket APIEnable ActiveX and Socket ClientsTWS API 设置中必须打开
回环连接地址127.0.0.1程序和 TWS 在同一台电脑上运行时使用
TWS 模拟账户端口7497常见 Paper Trading 端口
TWS 真实账户端口7496真实账户下单前必须再次确认
IB Gateway 模拟账户端口4002服务器部署常见选择
IB Gateway 真实账户端口4001真实账户谨慎使用

端口不是写死规则,最终以你 TWS / IB Gateway 的 API Settings 里显示的 Socket Port 为准。

Python 里通常这样连接:

app.connect("127.0.0.1", 7497, clientId=1)

这三个参数分别是:

参数含义新手建议
hostTWS / IB Gateway 所在机器地址同一台电脑运行时先用 127.0.0.1
portTWS / IB Gateway 的 API Socket 端口模拟账户先确认是否为 7497
clientIdAPI 客户端编号不同脚本使用不同 clientId

clientId 用来区分多个 API 程序。TWS 同一会话可以接受多个 API 客户端,但不要让两个正在运行的程序使用同一个 clientId,否则可能出现连接冲突、订单 ID 混乱或 socket 异常。

不要在 connect 后立刻发业务请求

Section titled “不要在 connect 后立刻发业务请求”

connect() 成功只代表 socket 已经打开,不代表所有 API 会话信息都准备好了。

更稳的判断方式是等待 nextValidId() 回调。这个回调表示 TWS / IB Gateway 已经完成初始握手,并给出了下一个可用订单 ID。官方也建议通常把 nextValidId 作为连接完成、可以开始发送其他请求的信号。

错误示例:

app.connect("127.0.0.1", 7497, clientId=1)
app.reqCurrentTime() # 太早,连接握手可能还没完成

更稳的方式:

def nextValidId(self, orderId: int):
self.reqCurrentTime()

下面示例只做一件事:连接 TWS,等到 nextValidId() 后请求服务器时间,收到 currentTime() 后断开。

import threading
import time
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
class App(EWrapper, EClient):
def __init__(self):
EClient.__init__(self, self)
self.ready = threading.Event()
self.done = threading.Event()
self.server_time = None
def nextValidId(self, orderId: int):
# 收到 nextValidId 后,说明初始握手已经完成。
self.ready.set()
# 这里请求 TWS / IB Gateway 返回服务器时间。
self.reqCurrentTime()
def currentTime(self, time_: int):
# time_ 是 Unix 时间戳,表示 IBKR 服务器时间。
self.server_time = time_
self.done.set()
self.disconnect()
def error(self, reqId, errorCode, errorString, advancedOrderRejectJson=""):
# 注意:TWS API 会把通知、警告和错误都放到 error 回调里。
print(f"API message: reqId={reqId}, code={errorCode}, message={errorString}")
app = App()
app.connect("127.0.0.1", 7497, clientId=1)
# Python API 需要启动 run() 循环处理从 TWS 返回的消息。
thread = threading.Thread(target=app.run, daemon=True)
thread.start()
if not app.ready.wait(8):
app.disconnect()
raise TimeoutError("连接已发起,但没有收到 nextValidId 回调")
if not app.done.wait(8):
app.disconnect()
raise TimeoutError("已连接,但 reqCurrentTime 没有返回")
print(f"SERVER_TIME={app.server_time}")
time.sleep(0.2)
thread.join(timeout=1)

这段代码里有两个重点:

  • App 同时继承 EWrapperEClientEClient 负责发请求,EWrapper 负责接回调。
  • app.run() 必须运行:否则 TWS 返回的消息进了队列,但你的程序不会处理回调。

使用 TWS 模拟账户、127.0.0.1:7497 和独立 clientId 检查,连接和 reqCurrentTime() 正常时,会看到类似输出:

TWS API OK: server_time=1781368619, host=127.0.0.1, port=7497

server_time 是 Unix 时间戳。它能返回,说明 Python API 包、TWS Socket 端口、nextValidId()reqCurrentTime() 和回调处理链路都已经通了。

现象常见原因排查方向
502 Couldn't connect to TWSTWS 没开、API 没启用、端口不一致、防火墙拦截先看 TWS 是否登录,再核对 API Settings 端口
一直收不到 nextValidIdsocket 打开了,但握手没有完成,或 TWS 弹出确认窗口未接受切回 TWS 查看是否有连接确认;如果之前已经信任过同一台电脑的连接,可能不会再弹
收到 501 Already Connected同一个客户端对象重复连接不要对同一个 App 实例重复 connect()
收到 504 Not connected还没连接成功就发请求,或连接已经断开nextValidId 后再发请求
一连接就断开clientId 冲突、TWS 关闭、端口变化或网络中断换一个 clientId,检查 TWS 日志和 API 设置

其中 502 是客户端本地错误,不一定会出现在 TWS 日志里。遇到它时,先检查 TWS / IB Gateway 是否正在监听对应端口。

IBKR Campus: TWS API Documentation