def execDetails( self, reqId: int, contract: Contract, execution: Execution): """ This wrapper handles both live fills and responses to reqExecutions. """ self._logger.info(f'execDetails {execution}') if execution.orderId == UNSET_INTEGER: # bug in TWS: executions of manual orders have unset value execution.orderId = 0 trade = self.permId2Trade.get(execution.permId) if not trade: key = self.orderKey( execution.clientId, execution.orderId, execution.permId) trade = self.trades.get(key) if trade and contract == trade.contract: contract = trade.contract else: contract = Contract.create(**dataclassAsDict(contract)) execId = execution.execId isLive = reqId not in self._futures time = self.lastTime if isLive else execution.time fill = Fill(contract, execution, CommissionReport(), time) if execId not in self.fills: # first time we see this execution so add it self.fills[execId] = fill if trade: trade.fills.append(fill) logEntry = TradeLogEntry( time, trade.orderStatus.status, f'Fill {execution.shares}@{execution.price}') trade.log.append(logEntry) if isLive: self._logger.info(f'execDetails: {fill}') self.ib.execDetailsEvent.emit(trade, fill) trade.fillEvent(trade, fill) if not isLive: self._results[reqId].append(fill)
def execDetails(self, reqId, contract, execution): """ This wrapper handles both live fills and responses to reqExecutions. """ if execution.orderId == 2147483647: # bug in TWS: executions of manual orders have orderId=2**31 - 1 execution.orderId = 0 key = self.orderKey( execution.clientId, execution.orderId, execution.permId) trade = self.trades.get(key) if trade and contract.conId == trade.contract.conId: contract = trade.contract else: contract = self._getContract(contract) execId = execution.execId execution = Execution(**execution.__dict__) execution.time = util.parseIBDatetime(execution.time). \ astimezone(datetime.timezone.utc) isLive = reqId not in self._futures time = self.lastTime if isLive else execution.time fill = Fill(contract, execution, CommissionReport(), time) if execId not in self.fills: # first time we see this execution so add it self.fills[execId] = fill if trade: trade.fills.append(fill) logEntry = TradeLogEntry( self.lastTime, trade.orderStatus.status, f'Fill {execution.shares}@{execution.price}') trade.log.append(logEntry) if isLive: self._logger.info(f'execDetails: {fill}') self._ib.execDetailsEvent.emit(trade, fill) trade.fillEvent(trade, fill) if not isLive: self._results[reqId].append(fill)
def commissionReport(self, commissionReport): if commissionReport.yield_ == UNSET_DOUBLE: commissionReport.yield_ = 0.0 if commissionReport.realizedPNL == UNSET_DOUBLE: commissionReport.realizedPNL = 0.0 fill = self.fills.get(commissionReport.execId) if fill: report = fill.commissionReport.update(**commissionReport.__dict__) self._logger.info(f'commissionReport: {report}') key = self.orderKey(fill.execution.clientId, fill.execution.orderId, fill.execution.permId) trade = self.trades.get(key) if trade: self._ib.commissionReportEvent.emit(trade, fill, report) trade.commissionReportEvent.emit(trade, fill, report) else: # this is not a live execution and the order was filled # before this connection started pass else: report = CommissionReport(**commissionReport.__dict__) self._logger.error( 'commissionReport: ' 'No execution found for %s', report)