跳转到内容

成交

get_executions() 用来查询成交记录。成交记录表示订单已经至少部分成交,和“未完成订单”不是同一种数据。

它对应原始 TWS API 的这一组调用和回调:

reqExecutions(reqId, executionFilter)
-> execDetails(reqId, contract, execution)
-> execDetailsEnd(reqId)

如果过滤条件下没有成交,返回空列表是正常结果,不代表 API 连接失败。

本地官方源码中的同步封装如下:

def get_executions(self, exec_filter=None, timeout=10):
if exec_filter is None:
exec_filter = ExecutionFilter()
req_id = self.get_next_valid_id()
if req_id in self.executions:
del self.executions[req_id]
self.reqExecutions(req_id, exec_filter)
return self._wait_for_response(req_id, "executions", timeout)

execDetails() 回调会把每条成交整理成:

{
"contract": contract,
"execution": execution,
}

contract 说明成交的合约,execution 说明成交本身,例如成交时间、方向、数量、价格、交易所、订单 ID 和永久订单 ID。

ExecutionFilter 用来缩小查询范围。常用字段如下:

字段中文含义示例
clientIdAPI 客户端 ID955
acctCode账户代码通常建议日志中脱敏
time起始时间"20260613 09:30:00"
symbol合约代码"AAPL"
secType证券类型"STK"
exchange交易所"SMART" 或具体交易所
side买卖方向"BOT""SLD"

最常用的做法是先按 symbolclientId 过滤。如果系统有多条策略,建议每条策略使用固定 clientId 和清晰的 orderRef,后面查成交时更容易定位来源。

下面示例查询账户里 AAPL 相关成交。代码不会下单,只读取 TWS 可返回的成交记录。

from ibapi.execution import ExecutionFilter
from ibapi.sync_wrapper import TWSSyncWrapper, ResponseTimeout
app = TWSSyncWrapper(timeout=12)
try:
if not app.connect_and_start("127.0.0.1", 7497, 956):
raise RuntimeError("连接 TWS API 失败")
exec_filter = ExecutionFilter()
exec_filter.symbol = "AAPL"
executions = app.get_executions(exec_filter, timeout=10)
print(f"EXECUTION_COUNT={len(executions)}")
for index, item in enumerate(executions[:5], start=1):
contract = item["contract"]
execution = item["execution"]
print(f"ROW={index}")
print(f"SYMBOL={contract.symbol}")
print(f"SEC_TYPE={contract.secType}")
print(f"CURRENCY={contract.currency}")
print(f"EXCHANGE={execution.exchange}")
print(f"SIDE={execution.side}")
print(f"SHARES={execution.shares}")
print(f"PRICE={execution.price}")
print(f"ORDER_ID={execution.orderId}")
print(f"PERM_ID={execution.permId}")
print(f"ORDER_REF={execution.orderRef}")
print(f"TIME={execution.time}")
except ResponseTimeout:
print("等待成交回调超时,请确认 TWS API 连接正常,或放宽过滤条件后重试。")
finally:
app.disconnect_and_stop()
print(f"IS_CONNECTED_AFTER_STOP={app.isConnected()}")

使用 TWS 模拟账户、127.0.0.1:7497 和独立 clientId 检查时,如果 AAPL 过滤条件下没有成交,输出类似:

CONNECTED=True
EXECUTION_COUNT=0
IS_CONNECTED_AFTER_STOP=False

这个结果是合理的:前面订单示例使用的是极低价格限价单,并且已经撤单,没有产生实际成交。

连接时还可能看到 210421062158 这类市场数据场或合约数据场状态提示。它们是连接状态消息,不等于成交查询失败。

如果账户有符合过滤条件的成交,常见字段含义如下:

字段中文含义
contract.symbol合约代码
contract.secType证券类型
contract.currency币种
execution.execId成交 ID,通常用于唯一识别成交
execution.time成交时间
execution.acctNumber账户代码,展示和日志中建议脱敏
execution.exchange成交交易所
execution.side成交方向,常见为 BOTSLD
execution.shares本次成交数量
execution.price本次成交价格
execution.permIdIBKR 永久订单 ID
execution.clientId提交订单的 API 客户端 ID
execution.orderIdAPI 会话中的订单 ID
execution.cumQty累计成交数量
execution.avgPrice平均成交价格
execution.orderRef自定义订单标记

真正做交易系统时,建议至少保存 execIdpermIdorderIdclientIdorderRefsymbolsidesharespricetime。这些字段能帮助你把成交记录和策略订单、风控日志、盈亏统计对应起来。

订单状态和成交记录经常一起出现,但用途不同:

数据来源回调说明
订单状态orderStatus()告诉你订单现在是 SubmittedFilledCancelled 等状态
未完成订单openOrder()给出还活跃的订单参数和状态对象
成交记录execDetails()给出已经发生的成交明细

一个订单可能分多次成交,因此一个 orderId 可能对应多条 execDetails()。如果只看 orderStatus() 里的 filledavgFillPrice,通常只能知道累计状态;如果要做成交流水、手续费、对账和策略复盘,就要保存成交明细。

官方文档说明,成交查询默认通常返回当天午夜以来的成交。TWS 里的交易日志设置会影响可返回的历史范围,例如 “Show trades for …” 相关设置。

这意味着:

目标建议
查询刚刚成交的订单直接用 get_executions() 或按 clientId / symbol 过滤
做日内成交流水程序运行中实时保存 execDetails(),并定期落库
做长期历史对账不要只依赖 TWS API 成交查询,应结合报表或 Flex 服务
使用 IB Gateway注意 IB Gateway 没有 TWS 交易日志界面,历史范围配置能力不同
现象常见原因处理方式
EXECUTION_COUNT=0过滤条件下没有成交放宽 symbolclientId 或时间过滤;确认订单是否真的成交
下单后没有成交记录订单还未成交,或只是 Submitted / PreSubmitted先看 orderStatus()filledremaining
成交数量和订单数量不一致部分成交execId 保存每一笔成交,再按 permIdorderId 汇总
找不到昨天以前的成交TWS 交易日志范围或 API 查询范围限制使用报表或 Flex 服务做长期对账
日志里出现账户号execution.acctNumber 是成交对象字段写入文档或公开日志前必须脱敏

IBKR Campus: TWS API Documentation