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 if orderState.commissionCurrency: self._endReq(order.orderId, orderState) else: key = self.orderKey(order.clientId, order.orderId, order.permId) trade = self.trades.get(key) if trade: trade.order.permId = order.permId trade.order.totalQuantity = order.totalQuantity trade.order.lmtPrice = order.lmtPrice trade.order.auxPrice = order.auxPrice trade.order.orderType = order.orderType else: # ignore '?' values in the order order = Order(**{ k: v for k, v in dataclassAsDict(order).items() if v != '?'}) contract = Contract.create(**dataclassAsDict(contract)) 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) # make sure that the client issues order ids larger then any # order id encountered (even from other clients) to avoid # "Duplicate order id" error self.ib.client.updateReqId(orderId + 1)
def completedOrder(self, contract: Contract, order: Order, orderState: OrderState): contract = Contract.create(**dataclassAsDict(contract)) orderStatus = OrderStatus(orderId=order.orderId, status=orderState.status) trade = Trade(contract, order, orderStatus, [], []) self._results['completedOrders'].append(trade) if order.permId not in self.permId2Trade: self.trades[order.permId] = trade self.permId2Trade[order.permId] = trade
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) if trade: trade.order.permId = order.permId else: # ignore '?' values in the order order = Order(**{ k: v for k, v in dataclassAsDict(order).items() if v != '?' }) contract = Contract.create(**dataclassAsDict(contract)) 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 position(self, account: str, contract: Contract, posSize: float, avgCost: float): contract = Contract.create(**dataclassAsDict(contract)) position = Position(account, contract, posSize, avgCost) positions = self.positions[account] if posSize == 0: positions.pop(contract.conId, None) else: positions[contract.conId] = position self._logger.info(f'position: {position}') results = self._results.get('positions') if results is not None: results.append(position) self.ib.positionEvent.emit(position)
def updatePortfolio(self, contract: Contract, posSize: float, marketPrice: float, marketValue: float, averageCost: float, unrealizedPNL: float, realizedPNL: float, account: str): contract = Contract.create(**dataclassAsDict(contract)) portfItem = PortfolioItem(contract, posSize, marketPrice, marketValue, averageCost, unrealizedPNL, realizedPNL, account) portfolioItems = self.portfolio[account] if posSize == 0: portfolioItems.pop(contract.conId, None) else: portfolioItems[contract.conId] = portfItem self._logger.info(f'updatePortfolio: {portfItem}') self.ib.updatePortfolioEvent.emit(portfItem)
async def startAsync(self): if self._proc: return self._logger.info('Starting') # expand paths d = util.dataclassAsDict(self) for k, v in d.items(): if k.endswith('_PATH') or k.endswith('_INI'): d[k] = os.path.expanduser(v) if not d['TWS_CONFIG_PATH']: d['TWS_CONFIG_PATH'] = d['TWS_PATH'] self.__dict__.update(**d) # run shell command ext = 'bat' if os.sys.platform == 'win32' else 'sh' cmd = f'{d["IBC_PATH"]}/Scripts/DisplayBannerAndLaunch.{ext}' env = {**os.environ, **d} self._proc = await asyncio.create_subprocess_exec( cmd, env=env, stdout=asyncio.subprocess.PIPE) self._monitor = asyncio.ensure_future(self.monitorAsync())
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)
async def startAsync(self): if self._proc: return self._logger.info('Starting') # map from field names to cmd arguments; key=(UnixArg, WindowsArg) args = dict(twsVersion=('', ''), gateway=('--gateway', '/Gateway'), tradingMode=('--mode=', '/Mode:'), twsPath=('--tws-path=', '/TwsPath:'), twsSettingsPath=('--tws-settings-path=', ''), ibcPath=('--ibc-path=', '/IbcPath:'), ibcIni=('--ibc-ini=', '/Config:'), javaPath=('--java-path=', '/JavaPath:'), userid=('--user='******'/User:'******'--pw=', '/PW:'), fixuserid=('--fix-user='******'/FIXUser:'******'--fix-pw=', '/FIXPW:')) # create shell command cmd = [ f'{self.ibcPath}\\scripts\\StartIBC.bat' if self._isWindows else f'{self.ibcPath}/scripts/ibcstart.sh' ] for k, v in util.dataclassAsDict(self).items(): arg = args[k][self._isWindows] if v: if arg.endswith('=') or arg.endswith(':'): cmd.append(f'{arg}{v}') elif arg: cmd.append(arg) else: cmd.append(str(v)) # run shell command self._proc = await asyncio.create_subprocess_exec( *cmd, stdout=asyncio.subprocess.PIPE) self._monitor = asyncio.ensure_future(self.monitorAsync())
def __eq__(self, other): return ( isinstance(other, Contract) and ( self.conId and self.conId == other.conId or util.dataclassAsDict(self) == util.dataclassAsDict(other)))
def __eq__(self, other): if not isinstance(other, Contract): return False return (self.isHashable() and isinstance(other, Contract) and (self.conId == other.conId or util.dataclassAsDict(self) == util.dataclassAsDict(other)))