跳转到内容

ExecID 行为

execId 是 IBKR 给每一笔成交分配的成交编号。它出现在 Execution.execId 中,也会出现在 commissionAndFeesReport.execId 中。

这意味着你可以用 execId 把成交记录和佣金费用报告关联起来。对交易系统来说,execId 是成交表里最重要的字段之一。

execDetails.execution.execId == commissionAndFeesReport.execId

成交先到、费用后到是常见情况。程序应该允许先保存成交,再根据相同 execId 更新费用字段,而不是假设两个回调一定连续到达。

一个订单可以被分成多笔成交。例如买入 100 股,可能先成交 40 股,再成交 60 股。此时它们可能有相同的 orderIdpermId,但会有不同的 execId

字段粒度说明
orderIdAPI 客户端订单同一个客户端内递增,重连后仍要小心管理。
permIdIBKR 永久订单编号更适合跨客户端、跨会话追踪同一个订单。
execId单笔成交更适合做成交明细、佣金关联和去重。

因此,成交表建议至少把 execIdorderIdpermIdclientId 都保存下来。

def execDetails(self, reqId, contract, execution):
# execId 是成交流水去重的核心字段。
key = execution.execId
row = {
"exec_id": execution.execId,
"perm_id": execution.permId,
"order_id": execution.orderId,
"client_id": execution.clientId,
"symbol": contract.symbol,
"side": execution.side,
"shares": float(execution.shares),
"price": execution.price,
"time": execution.time,
}
save_or_update_execution(key, row)

如果你的系统支持多个账户、多个 TWS 会话或多个交易环境,数据库唯一键可以设计成:

account + execId

或更保守一些:

account + permId + execId
def commissionAndFeesReport(self, report):
# 用同一个 execId 找到之前保存的成交记录,再补齐费用字段。
update_execution_fee(
exec_id=report.execId,
commission_and_fees=report.commissionAndFees,
currency=report.currency,
realized_pnl=report.realizedPNL,
)

commissionAndFeesReport() 的字段名在新版 API 中是 commissionAndFees。一些旧资料可能还写作 commission,读文档或迁移旧代码时要注意版本差异。

EXEC_ROWS=0
COMMISSION_ROWS=0

查询范围内没有成交时,不会出现实际 execId。这不是异常;它只表示 TWS 可见范围里没有成交流水。