跳转到内容

管理账户总览

管理账户接口用来获取 TWS 或 IB Gateway 会话可见的账户列表。很多账户类接口都需要账户号,例如账户摘要、账户更新、持仓和盈亏;新手最稳妥的做法是先调用 reqManagedAccts(),再把返回的账户号传给账户类接口。

reqManagedAccts()
-> managedAccounts(accountsList)

这个接口没有请求参数,也没有取消方法。回调返回的是逗号分隔的账户字符串。

问题说明
不知道登录会话有哪些账户reqManagedAccts() 获取可见账户列表
不想在代码里写死账户号先请求账户列表,再选择目标账户
多账户或顾问账户开发用返回列表做账户选择和权限检查
公开日志需要脱敏把真实账户号映射成 ACCOUNT_1 这类别名

虽然官方源码注释里强调 FA managed account 场景,但实际 TWS API 开发里,普通账户也常用这个回调获取可见账户号。TWS 模拟账户验证也能正常返回 1 个可见账户。

名称类型中文含义说明
reqManagedAccts()请求方法请求可见账户列表没有参数
managedAccounts(accountsList)回调方法接收账户列表accountsList 是逗号分隔字符串

accountsList 示例:

DU1234567,DU2345678

公开文档和日志里不要直接展示真实账户号,应改成:

ACCOUNT_1,ACCOUNT_2
import threading
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
INFO_CODES = {2100, 2104, 2106, 2158}
class ManagedAccountsOverviewApp(EWrapper, EClient):
def __init__(self):
EClient.__init__(self, self)
self.ready = threading.Event()
self.managed_ready = threading.Event()
self.accounts = []
self.info_codes = []
self.errors_seen = []
def nextValidId(self, orderId):
self.ready.set()
def managedAccounts(self, accountsList):
# accountsList 是逗号分隔的真实账户号。公开输出前要脱敏。
self.accounts = [item for item in (accountsList or "").split(",") if item]
self.managed_ready.set()
def error(self, reqId, errorTime, errorCode, errorString, advancedOrderRejectJson=""):
if errorCode in INFO_CODES:
self.info_codes.append(errorCode)
else:
self.errors_seen.append((reqId, errorCode, errorString))
app = ManagedAccountsOverviewApp()
try:
app.connect("127.0.0.1", 7497, clientId=981)
thread = threading.Thread(target=app.run, daemon=True)
thread.start()
if not app.ready.wait(8):
raise RuntimeError("等待 nextValidId 超时")
app.reqManagedAccts()
if not app.managed_ready.wait(8):
raise RuntimeError("等待 managedAccounts 回调超时")
finally:
if app.isConnected():
app.disconnect()
aliases = [f"ACCOUNT_{index}" for index, _ in enumerate(app.accounts, 1)]
print("REQUEST_SENT=True")
print(f"MANAGED_CALLBACK_RECEIVED={app.managed_ready.is_set()}")
print(f"ACCOUNT_COUNT={len(app.accounts)}")
print("ACCOUNT_ALIASES=" + (",".join(aliases) if aliases else "NONE"))
print("INFO_CODES=" + (",".join(map(str, sorted(set(app.info_codes)))) if app.info_codes else "NONE"))
print(f"NON_INFO_ERROR_COUNT={len(app.errors_seen)}")

使用TWS 模拟账户、127.0.0.1:7497 和独立 clientId 检查时,脱敏输出如下:

CONNECTED=True
REQUEST_SENT=True
MANAGED_CALLBACK_RECEIVED=True
ACCOUNT_COUNT=1
ACCOUNT_ALIASES=ACCOUNT_1
RAW_LIST_HAS_TRAILING_COMMA=False
INFO_CODES=2104,2106,2158
NON_INFO_ERROR_COUNT=0
IS_CONNECTED_AFTER_DISCONNECT=False

这说明这个会话可见 1 个账户,回调正常到达,没有非信息类错误。

拿到账户号后,常见用法如下:

account = app.accounts[0]
app.reqAccountSummary(8001, "All", "NetLiquidation,BuyingPower")
app.reqAccountUpdates(True, account)
app.reqPositions()
app.reqPnL(9001, account, "")

不同接口对账户参数的要求不完全一样。不要把 accountsList 原始字符串直接传给所有接口,通常应先 split 成列表,再取目标账户。

测试脚本可以临时写死,但正式程序不建议。账户号可能因模拟账户、真实账户、多账户权限或登录用户不同而变化。先请求 managedAccounts() 更稳。

不是。普通个人模拟账户通常只返回 1 个可见账户。多账户、顾问账户或 IBroker 场景才更常见多个账户。

信息码 210421062158 是失败吗?

Section titled “信息码 2104、2106、2158 是失败吗?”

不是。它们通常是数据服务连接状态提示。判断请求是否成功,应看是否收到 managedAccounts() 回调,以及是否有非信息类错误。

IBKR Campus: TWS API Documentation