接收成交详情
execDetails() 每次返回一条成交记录,execDetailsEnd() 表示这批成交详情已经返回完毕。
def execDetails(self, reqId, contract, execution) -> None: print("成交请求 ID:", reqId) print("合约:", contract.symbol, contract.secType, contract.currency) print("成交 ID:", execution.execId) print("成交时间:", execution.time) print("方向:", execution.side) print("数量:", execution.shares) print("价格:", execution.price) print("订单 ID:", execution.orderId) print("永久订单 ID:", execution.permId)
def execDetailsEnd(self, reqId: int) -> None: print("成交详情结束", reqId)reqId 用来识别这是哪一次 reqExecutions() 请求返回的数据。contract 负责说明成交的合约,execution 负责说明成交本身。
| 表 | 字段 |
|---|---|
| 成交表 | execId、time、symbol、side、shares、price、orderId、permId |
| 费用表 | execId、commissionAndFees、currency、realizedPNL |
成交和费用可以通过 execId 合并。
与费用报告一起处理
Section titled “与费用报告一起处理”def execDetails(self, reqId, contract, execution) -> None: save_execution( exec_id=execution.execId, order_id=execution.orderId, perm_id=execution.permId, symbol=contract.symbol, side=execution.side, shares=float(execution.shares), price=execution.price, time=execution.time, )
def commissionAndFeesReport(self, report) -> None: update_execution_fee( exec_id=report.execId, commission_and_fees=report.commissionAndFees, currency=report.currency, realized_pnl=report.realizedPNL, )上面的 save_execution() 和 update_execution_fee() 是业务系统里的保存函数名。实际项目可以写入 MySQL、SQLite、CSV 或日志系统,关键是用 execId 把两类数据合并。
EXEC_ROWS=0COMMISSION_ROWS=0空结果不代表错误。没有真实成交、过滤条件太窄、或该 clientId 看不到成交,都可能返回 0 行。
如果订单只是提交后撤单,例如模拟账户里用远离市价的限价单检查下单和撤单流程,就会有订单状态和已完成订单记录,但不会有 execDetails()。
接收顺序注意
Section titled “接收顺序注意”execDetails()可能返回多次,一次一笔成交。commissionAndFeesReport()可能在成交回调后到达,不要依赖固定顺序。execDetailsEnd()表示成交详情批次结束,但费用报告是否已经全部到齐要根据程序实际收到的数据处理。- 程序重连后再次查询,可能会读到已经保存过的成交,因此成交表要做去重。