成交
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 过滤条件
Section titled “ExecutionFilter 过滤条件”ExecutionFilter 用来缩小查询范围。常用字段如下:
| 字段 | 中文含义 | 示例 |
|---|---|---|
clientId | API 客户端 ID | 955 |
acctCode | 账户代码 | 通常建议日志中脱敏 |
time | 起始时间 | "20260613 09:30:00" |
symbol | 合约代码 | "AAPL" |
secType | 证券类型 | "STK" |
exchange | 交易所 | "SMART" 或具体交易所 |
side | 买卖方向 | "BOT" 或 "SLD" |
最常用的做法是先按 symbol 或 clientId 过滤。如果系统有多条策略,建议每条策略使用固定 clientId 和清晰的 orderRef,后面查成交时更容易定位来源。
最小查询示例
Section titled “最小查询示例”下面示例查询账户里 AAPL 相关成交。代码不会下单,只读取 TWS 可返回的成交记录。
from ibapi.execution import ExecutionFilterfrom 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=TrueEXECUTION_COUNT=0IS_CONNECTED_AFTER_STOP=False这个结果是合理的:前面订单示例使用的是极低价格限价单,并且已经撤单,没有产生实际成交。
连接时还可能看到 2104、2106、2158 这类市场数据场或合约数据场状态提示。它们是连接状态消息,不等于成交查询失败。
成交字段解释
Section titled “成交字段解释”如果账户有符合过滤条件的成交,常见字段含义如下:
| 字段 | 中文含义 |
|---|---|
contract.symbol | 合约代码 |
contract.secType | 证券类型 |
contract.currency | 币种 |
execution.execId | 成交 ID,通常用于唯一识别成交 |
execution.time | 成交时间 |
execution.acctNumber | 账户代码,展示和日志中建议脱敏 |
execution.exchange | 成交交易所 |
execution.side | 成交方向,常见为 BOT 或 SLD |
execution.shares | 本次成交数量 |
execution.price | 本次成交价格 |
execution.permId | IBKR 永久订单 ID |
execution.clientId | 提交订单的 API 客户端 ID |
execution.orderId | API 会话中的订单 ID |
execution.cumQty | 累计成交数量 |
execution.avgPrice | 平均成交价格 |
execution.orderRef | 自定义订单标记 |
真正做交易系统时,建议至少保存 execId、permId、orderId、clientId、orderRef、symbol、side、shares、price 和 time。这些字段能帮助你把成交记录和策略订单、风控日志、盈亏统计对应起来。
成交和订单状态的区别
Section titled “成交和订单状态的区别”订单状态和成交记录经常一起出现,但用途不同:
| 数据 | 来源回调 | 说明 |
|---|---|---|
| 订单状态 | orderStatus() | 告诉你订单现在是 Submitted、Filled、Cancelled 等状态 |
| 未完成订单 | openOrder() | 给出还活跃的订单参数和状态对象 |
| 成交记录 | execDetails() | 给出已经发生的成交明细 |
一个订单可能分多次成交,因此一个 orderId 可能对应多条 execDetails()。如果只看 orderStatus() 里的 filled 和 avgFillPrice,通常只能知道累计状态;如果要做成交流水、手续费、对账和策略复盘,就要保存成交明细。
时间范围限制
Section titled “时间范围限制”官方文档说明,成交查询默认通常返回当天午夜以来的成交。TWS 里的交易日志设置会影响可返回的历史范围,例如 “Show trades for …” 相关设置。
这意味着:
| 目标 | 建议 |
|---|---|
| 查询刚刚成交的订单 | 直接用 get_executions() 或按 clientId / symbol 过滤 |
| 做日内成交流水 | 程序运行中实时保存 execDetails(),并定期落库 |
| 做长期历史对账 | 不要只依赖 TWS API 成交查询,应结合报表或 Flex 服务 |
| 使用 IB Gateway | 注意 IB Gateway 没有 TWS 交易日志界面,历史范围配置能力不同 |
| 现象 | 常见原因 | 处理方式 |
|---|---|---|
EXECUTION_COUNT=0 | 过滤条件下没有成交 | 放宽 symbol、clientId 或时间过滤;确认订单是否真的成交 |
| 下单后没有成交记录 | 订单还未成交,或只是 Submitted / PreSubmitted | 先看 orderStatus() 的 filled 和 remaining |
| 成交数量和订单数量不一致 | 部分成交 | 按 execId 保存每一笔成交,再按 permId 或 orderId 汇总 |
| 找不到昨天以前的成交 | TWS 交易日志范围或 API 查询范围限制 | 使用报表或 Flex 服务做长期对账 |
| 日志里出现账户号 | execution.acctNumber 是成交对象字段 | 写入文档或公开日志前必须脱敏 |