def get_realtime_bars(self, assets, frequency): if frequency == '1m': resample_freq = '1 Min' elif frequency == '1d': resample_freq = '24 H' else: raise ValueError("Invalid frequency specified: %s" % frequency) df = pd.DataFrame() for asset in assets: self.subscribe_to_market_data(asset) ib_symbol = self._asset_symbol(asset) if ib_symbol in self._tws.bars: trade_prices = self._tws.bars[ib_symbol]['last_trade_price'] trade_sizes = self._tws.bars[ib_symbol]['last_trade_size'] else: log.warning("No tws bar for '%s'." % ib_symbol) trade_prices = pd.Series([1.0], index=[pd.to_datetime('now')]) trade_sizes = pd.Series([1], index=[pd.to_datetime('now')]) ohlcv = trade_prices.resample(resample_freq).ohlc() ohlcv['volume'] = trade_sizes.resample(resample_freq).sum() # Add asset as level 0 column; ohlcv will be used as level 1 cols ohlcv.columns = pd.MultiIndex.from_product([[ asset, ], ohlcv.columns]) df = pd.concat([df, ohlcv], axis=1) return df
def _update_from_order_status(zp_order, ib_order_id): if ib_order_id in self._tws.open_orders: open_order_state = self._tws.open_orders[ib_order_id]['state'] zp_status = self._ib_to_zp_status(open_order_state.status) if zp_status is None: log.warning("Order-{order_id}: " "unknown order status: {order_status}.".format( order_id=ib_order_id, order_status=open_order_state.status)) else: zp_order.status = zp_status if ib_order_id in self._tws.order_statuses: order_status = self._tws.order_statuses[ib_order_id] zp_order.filled = order_status['filled'] zp_status = self._ib_to_zp_status(order_status['status']) if zp_status is None: log.warning("Order-{order_id}: " "unknown order status: {order_status}.".format( order_id=ib_order_id, order_status=order_status['status'])) else: zp_order.status = zp_status
def _parse_order_ref(cls, ib_order_ref): if not ib_order_ref or \ not ib_order_ref.endswith(cls._zl_order_ref_magic): return None try: action, qty, order_type, limit_price, stop_price, dt, _ = \ ib_order_ref.split(' ') if not all([ action.startswith('A:'), qty.startswith('Q:'), order_type.startswith('T:'), limit_price.startswith('L:'), stop_price.startswith('S:'), dt.startswith('D:') ]): return None return { 'action': action[2:], 'qty': int(qty[2:]), 'order_type': order_type[2:].replace('_', ' '), 'limit_price': float(limit_price[2:]), 'stop_price': float(stop_price[2:]), 'dt': pd.to_datetime(dt[2:], unit='s', utc=True) } except ValueError: log.warning( "Error parsing order metadata: {}".format(ib_order_ref)) return None
def subscribe_to_market_data(self, asset): if asset not in self.subscribed_assets: ib_symbol = self._asset_symbol(asset) self._tws.subscribe_to_market_data(ib_symbol) self._subscribed_assets.append(asset) try: polling.poll( lambda: ib_symbol in self._tws.bars, timeout=_max_wait_subscribe, step=_poll_frequency) except polling.TimeoutException as te: log.warning('Cannot subscribe market data for %s.' % ib_symbol) else: log.debug("Subscription completed")
def tickSnapshotEnd(self, ticker_id): key = "SYMBOL_" + str(ticker_id) if key not in self.tick_dict: return ib_symbol = self.tick_dict[key] try: last_trade_price = float(self.tick_dict["LAST_" + str(ticker_id)]) last_trade_size = int(self.tick_dict["LAST_SIZE_" + str(ticker_id)]) last_trade_time = float(self.tick_dict["LAST_TIMESTAMP_" + str(ticker_id)]) last_trade_dt = pd.to_datetime(last_trade_time, unit='s', utc=True) except KeyError: log.warning('Cannot subscribe market data for %s.' % ib_symbol) return self._add_bar(ib_symbol, last_trade_price, last_trade_size, last_trade_dt)
def _get_positions_from_broker(self): """ get the positions from the broker and update zipline objects ( the ledger ) should be used once at startup and once every time we want to refresh the positions array """ cur_pos_in_tracker = self.metrics_tracker.positions for ib_symbol in self._tws.ib_positions: ib_position = self._tws.ib_positions[ib_symbol] equity = self._safe_symbol_lookup(ib_symbol) if not equity: log.warning( 'Wanted to subscribe to %s, but this asset is probably not ingested' % ib_symbol) continue zp_position = zp.Position(zp.InnerPosition(equity)) editable_position = MutableView(zp_position) editable_position._underlying_position.amount = int( ib_position.position) editable_position._underlying_position.cost_basis = float( ib_position.average_cost) editable_position._underlying_position.last_sale_price = ib_position.market_price last_close = self.metrics_tracker._trading_calendar.session_close( self.metrics_tracker._last_session) editable_position._underlying_position.last_sale_date = last_close self.metrics_tracker.update_position( zp_position.asset, amount=zp_position.amount, last_sale_price=zp_position.last_sale_price, last_sale_date=zp_position.last_sale_date, cost_basis=zp_position.cost_basis) for asset in cur_pos_in_tracker: ib_symbol = self._asset_symbol(asset) if ib_symbol not in self._tws.ib_positions: # deleting object from the metrcs_tracker as its not in the portfolio self.metrics_tracker.update_position(asset, amount=0) self.metrics_tracker._ledger._portfolio.positions = zp.Positions( self.metrics_tracker.positions)
def subscribe_to_market_data(self, asset): if asset not in self.subscribed_assets: ib_symbol = self._asset_symbol(asset) exchange = 'SMART' primaryExchange = 'ISLAND' secType = 'STK' currency = 'USD' self._tws.subscribe_to_market_data(ib_symbol, exchange, primaryExchange, secType, currency) self._subscribed_assets.append(asset) try: polling.poll(lambda: ib_symbol in self._tws.bars, timeout=_max_wait_subscribe, step=_poll_frequency) except polling.TimeoutException as te: log.warning('Cannot subscribe market data for %s.' % ib_symbol) else: log.debug("Subscription completed")
def _update_transactions(self): all_orders = list(self.orders.values()) for ib_order_id, executions in iteritems(self._tws.executions): orders = [ order for order in all_orders if order.broker_order_id == ib_order_id ] if not orders: log.warning( "No order found for executions: {}".format(executions)) continue assert len(orders) == 1 order = orders[0] for exec_id, execution in iteritems(executions): if exec_id in self._transactions: continue try: commission = self._tws.commissions[ib_order_id][ exec_id].commission except KeyError: log.warning( "Commission not found for execution: {}".format( exec_id)) commission = 0 exec_detail = execution['exec_detail'] is_buy = order.amount > 0 amount = (exec_detail.shares if is_buy else -1 * exec_detail.shares) tx = Transaction(asset=order.asset, amount=amount, dt=pd.to_datetime(exec_detail.time, utc=True), price=exec_detail.price, order_id=order.id) self._transactions[exec_id] = tx
def _get_or_create_zp_order(self, ib_order_id, ib_order=None, ib_contract=None): zp_order_id = self._ib_to_zp_order_id(ib_order_id) if zp_order_id in self._orders: return self._orders[zp_order_id] # Try to reconstruct the order from the given information: # open order state and execution state ib_symbol, order_details = None, None if ib_order and ib_contract: ib_symbol = ib_contract.symbol order_details = self._parse_order_ref(ib_order.orderRef) if not order_details and ib_order_id in self._tws.open_orders: open_order = self._tws.open_orders[ib_order_id] ib_symbol = open_order['contract'].symbol order_details = self._parse_order_ref(open_order['order'].orderRef) if not order_details and ib_order_id in self._tws.executions: executions = self._tws.executions[ib_order_id] last_exec_detail = list(executions.values())[-1]['exec_detail'] last_exec_contract = list(executions.values())[-1]['contract'] ib_symbol = last_exec_contract.symbol order_details = self._parse_order_ref(last_exec_detail.orderRef) asset = self._safe_symbol_lookup(ib_symbol) if not asset: log.warning("Ignoring symbol {symbol} which has associated " "order but it is not registered in bundle".format( symbol=ib_symbol)) return None if order_details: amount = self._action_qty_to_amount(order_details['action'], order_details['qty']) stop_price = order_details['stop_price'] limit_price = order_details['limit_price'] dt = order_details['dt'] else: dt = pd.to_datetime('now', utc=True) amount, stop_price, limit_price = 0, None, None if ib_order_id in self._tws.open_orders: open_order = self._tws.open_orders[ib_order_id]['order'] amount = self._action_qty_to_amount(open_order.action, open_order.totalQuantity) stop_price = open_order.auxPrice limit_price = open_order.lmtPrice stop_price = None if stop_price == 0 else stop_price limit_price = None if limit_price == 0 else limit_price self._orders[zp_order_id] = ZPOrder(dt=dt, asset=asset, amount=amount, stop=stop_price, limit=limit_price, id=zp_order_id) self._orders[zp_order_id].broker_order_id = ib_order_id return self._orders[zp_order_id]
def hold(self, order_id, reason=''): log.warning("Unexpected hold request for {}: '{}'".format( order_id, reason))