async def on_trade_updates(conn, channel, data): # logfeed_data.log(LogLevel.DEBUG, 'Alpaca raw trade update: {0}'.format(data)) try: print('receiving order from ws') order = Order.from_alpaca_api( data.order, logfeed_data) if order is None: logfeed_data.log( LogLevel.WARNING, 'Data stream could not decode an order. Ignoring it' ) print( 'Data stream could not decode an order. Ignoring it' ) cls._queue_update( moment=datetime.now(), update_type=StreamUpdateType.STARTED_UP) else: cls._on_trade_update(order) except Exception as e: logfeed_data.log( LogLevel.ERROR, 'Error handling alpaca trade update:') logfeed_data.log(LogLevel.WARNING, traceback.format_exc()) traceback.print_exc()
def get_order(self) -> Optional[Order]: """ Returns this update's order. Only for StreamUpdateType.ORDER. """ return None if self.raw_data['order'] is None else Order.from_json( self.raw_data['order'])
def _on_trade_update(cls, order: Order) -> None: """ Adds the updated order to the queues, which are processed by AbstractAccount's on other threads. """ # Signal the running strategy to respond to this new order update cls._queue_update(moment=datetime.now(), update_type=StreamUpdateType.ORDER, symbol=order.symbol, order=order.to_json())
def place_stop_order(self, symbol: str, price: float, qty: int) -> bool: # Create a fake order. order = Order(OrderType.STOP, OrderStatus.OPEN, symbol, price, qty, str(uuid.uuid4())) # Remove open stop orders for the symbol. self.open_orders = [ order for order in self.open_orders if order.symbol != symbol or order.type != OrderType.STOP ] # Add the new order. self.open_orders.append(order) return True
def place_limit_sell(self, symbol: str, limit: float, qty: int) -> bool: # Create a fake order. order = Order(OrderType.LIMIT_SELL, OrderStatus.OPEN, symbol, limit, qty, str(uuid.uuid4())) # Remove open limit sell orders for the symbol. self.open_orders = [ order for order in self.open_orders if order.symbol != symbol or order.type != OrderType.LIMIT_SELL ] # Add the new order. self.open_orders.append(order) return True
def refresh_open_orders(self, symbols: List[str]) -> None: """ See https://docs.alpaca.markets/api-documentation/api-v2/orders/#get-a-list-of-orders. """ try: self.open_orders = [] for order_ent in self.rest_client.list_orders(): order = Order.from_alpaca_api(order_ent, self.logfeed_process) if order.symbol in symbols and order.status == OrderStatus.OPEN: self.open_orders.append(order) except Exception as e: self.error_process( 'Error refreshing open orders from alpaca rest api:') self.warn_process(traceback.format_exc())
def load_trade_history(self, symbol: str, start_date: date, end_date: date) -> None: """Gets up to 500 orders placed during the time window (exclusive) and parses them to find round-trip trades.""" # Load trade history from redis self.trade_history[symbol] = self.redis().get_trade_history( symbols=[symbol]) # Load recent orders from Alpaca # See https://docs.alpaca.markets/api-documentation/api-v2/orders/#get-a-list-of-orders order_entities = self.rest_client.list_orders( status='closed', limit=500, after=pd.Timestamp(start_date), until=pd.Timestamp(end_date), direction='desc') orders = [ Order.from_alpaca_api(order_ent._raw, self.logfeed_process) for order_ent in order_entities ] # Parse orders for trades sell_order: Optional[Order] = None for order in orders: if order.status != OrderStatus.FILLED: continue if sell_order is None and order.type != OrderType.LIMIT_BUY: sell_order = order elif sell_order is not None and order.type == OrderType.LIMIT_BUY: trade = RoundTripTrade(order.get_symbol(), order.get_moment(), sell_order.get_moment(), order.get_price(), sell_order.get_price(), order.get_qty()) # Store new trades if trade not in self.trade_history: self.trade_history[symbol].append(trade) self.redis().record_trade(trade) sell_order = None if symbol not in self.trade_history_loaded: self.trade_history_loaded.append(symbol)