跳转到内容

持仓总览

持仓接口用来请求这个 TWS 会话可见账户的实时持仓数据。它会返回每个持仓合约的账户、合约信息、持仓数量和平均成本。

reqPositions()
-> position(account, contract, position, avgCost)
-> positionEnd()
cancelPositions()

reqPositions() 没有参数,也没有 reqId。它请求的是这个会话可见账户的持仓,而不是某一个单独账户。需要按账户或模型组合过滤时,可以使用 reqPositionsMulti()

和账户更新里的持仓有什么区别

Section titled “和账户更新里的持仓有什么区别”
接口主要用途回调
reqAccountUpdates()账户状态页,可能包含组合持仓行updatePortfolio()
reqPositions()专门请求这个会话可见账户的持仓position()positionEnd()
reqPositionsMulti()按账户和模型组合请求持仓positionMulti()positionMultiEnd()

如果你的目标是“拿持仓列表”,优先看 reqPositions()。如果你的目标是“账户资金字段和账户状态”,看账户更新。

名称类型中文含义说明
reqPositions()请求方法请求持仓没有参数,返回可见账户的持仓
position()回调方法接收单条持仓每个持仓合约一行
positionEnd()回调方法初始持仓批次结束表示这一轮初始持仓行已经发完
cancelPositions()请求方法取消持仓更新停止继续接收实时持仓更新
def position(self, account, contract, position, avgCost):
...
字段中文含义说明
account账户代码真实账户号,公开输出应脱敏
contract合约对象包含 conIdsymbolsecTypeexchangecurrency
position持仓数量可能是小数类型,期权、股票、期货都用这个字段
avgCost平均成本TWS 返回的平均成本,公开日志应避免直接显示真实值

positionEnd() 到达但 position() 行数为 0,表示这个会话没有返回持仓行。这通常是正常的空持仓结果,不应直接判定为失败。

import threading
import time
from collections import Counter
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
INFO_CODES = {2100, 2104, 2106, 2158}
class PositionsOverviewApp(EWrapper, EClient):
def __init__(self):
EClient.__init__(self, self)
self.ready = threading.Event()
self.positions_end = threading.Event()
self.positions = []
self.info_codes = []
self.errors_seen = []
def nextValidId(self, orderId):
self.ready.set()
def position(self, account, contract, position, avgCost):
# 真实账户号、持仓数量和成本都可能敏感;公开输出只统计结构。
self.positions.append({
"account": account,
"conId": contract.conId,
"symbol": contract.symbol,
"secType": contract.secType,
"currency": contract.currency,
"position": position,
"avgCost": avgCost,
})
def positionEnd(self):
self.positions_end.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 = PositionsOverviewApp()
cancel_sent = False
try:
app.connect("127.0.0.1", 7497, clientId=984)
thread = threading.Thread(target=app.run, daemon=True)
thread.start()
connected = app.ready.wait(8)
if not connected:
raise RuntimeError("等待 nextValidId 超时")
app.reqPositions()
if not app.positions_end.wait(8):
raise RuntimeError("等待 positionEnd 超时")
rows_before_cancel = len(app.positions)
app.cancelPositions()
cancel_sent = True
time.sleep(0.5)
rows_after_cancel = len(app.positions)
finally:
if app.isConnected():
app.disconnect()
sec_type_counts = Counter(row["secType"] or "EMPTY" for row in app.positions)
currency_counts = Counter(row["currency"] or "EMPTY" for row in app.positions)
print(f"CONNECTED={connected}")
print("REQUEST_SENT=True")
print(f"POSITION_END_RECEIVED={app.positions_end.is_set()}")
print(f"POSITION_ROW_COUNT={len(app.positions)}")
print("SEC_TYPE_COUNTS=" + (",".join(f"{key}:{value}" for key, value in sec_type_counts.items()) if sec_type_counts else "NONE"))
print("CURRENCY_COUNTS=" + (",".join(f"{key}:{value}" for key, value in currency_counts.items()) if currency_counts else "NONE"))
print(f"CANCEL_SENT={cancel_sent}")
print(f"ROWS_BEFORE_CANCEL={rows_before_cancel}")
print(f"ROWS_AFTER_CANCEL_WAIT={rows_after_cancel}")
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)}")
print(f"IS_CONNECTED_AFTER_DISCONNECT={app.isConnected()}")

如果 TWS 模拟账户没有持仓,脱敏输出通常类似:

CONNECTED=True
REQUEST_SENT=True
POSITION_END_RECEIVED=True
POSITION_ROW_COUNT=0
SEC_TYPE_COUNTS=NONE
CURRENCY_COUNTS=NONE
CANCEL_SENT=True
ROWS_BEFORE_CANCEL=0
ROWS_AFTER_CANCEL_WAIT=0
INFO_CODES=2104,2106,2158
NON_INFO_ERROR_COUNT=0
IS_CONNECTED_AFTER_DISCONNECT=False

这说明接口请求成功、结束回调正常到达,只是账户没有返回持仓行。

需求是否适合
展示持仓列表适合
获取合约、数量、平均成本适合
按账户和模型组合过滤reqPositionsMulti()
查询账户资金字段不适合,应看账户摘要或账户更新
查询订单状态不适合,应看订单管理接口
查询历史成交不适合,应看成交接口

持仓数据通常比账户摘要更敏感,因为它能暴露账户持有的证券、数量、成本和账户号。公开日志建议只输出:

  • 持仓行数。
  • 证券类型分布。
  • 币种分布。
  • 是否收到 positionEnd()
  • 非信息类错误数量。

不要公开打印真实账户号、真实持仓数量、平均成本和完整持仓列表。

IBKR Campus: TWS API Documentation