def orderStatus(self, orderId: int, status: str, filled: float, remaining: float, avgFillPrice: float, permId: int, parentId: int, lastFillPrice: float, clientId: int, whyHeld: str, mktCapPrice: float = 0.0): key = self.orderKey(clientId, orderId, permId) trade = self.trades.get(key) if trade: msg: Optional[str] oldStatus = trade.orderStatus.status new = dict(status=status, filled=filled, remaining=remaining, avgFillPrice=avgFillPrice, permId=permId, parentId=parentId, lastFillPrice=lastFillPrice, clientId=clientId, whyHeld=whyHeld, mktCapPrice=mktCapPrice) curr = dataclassAsDict(trade.orderStatus) isChanged = curr != {**curr, **new} if isChanged: dataclassUpdate(trade.orderStatus, **new) msg = '' elif (status == 'Submitted' and trade.log and trade.log[-1].message == 'Modify'): # order modifications are acknowledged msg = 'Modified' else: msg = None if msg is not None: logEntry = TradeLogEntry(self.lastTime, status, msg) trade.log.append(logEntry) self._logger.info(f'orderStatus: {trade}') self.ib.orderStatusEvent.emit(trade) trade.statusEvent.emit(trade) if status != oldStatus: if status == OrderStatus.Filled: trade.filledEvent.emit(trade) elif status == OrderStatus.Cancelled: trade.cancelledEvent.emit(trade) else: self._logger.error( 'orderStatus: No order found for ' 'orderId %s and clientId %s', orderId, clientId)
def openOrder( self, orderId: int, contract: Contract, order: Order, orderState: OrderState): """ This wrapper is called to: * feed in open orders at startup; * feed in open orders or order updates from other clients and TWS if clientId=master id; * feed in manual orders and order updates from TWS if clientId=0; * handle openOrders and allOpenOrders responses. """ if order.whatIf: # response to whatIfOrder self._endReq(order.orderId, orderState) else: key = self.orderKey(order.clientId, order.orderId, order.permId) trade = self.trades.get(key) # ignore '?' values in the order d = {k: v for k, v in dataclassAsDict(order).items() if v != '?'} if trade: dataclassUpdate(trade.order, **d) else: contract = Contract.create(**dataclassAsDict(contract)) order = Order(**d) orderStatus = OrderStatus( orderId=orderId, status=orderState.status) trade = Trade(contract, order, orderStatus, [], []) self.trades[key] = trade self._logger.info(f'openOrder: {trade}') self.permId2Trade.setdefault(order.permId, trade) results = self._results.get('openOrders') if results is None: self.ib.openOrderEvent.emit(trade) else: # response to reqOpenOrders or reqAllOpenOrders results.append(order)
def commissionReport(self, commissionReport: 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 = dataclassUpdate(fill.commissionReport, commissionReport) self._logger.info(f'commissionReport: {report}') trade = self.permId2Trade.get(fill.execution.permId) 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: # commission report is not for this client pass