async def listen_for_order_book_snapshots(self,
                                           ev_loop: asyncio.BaseEventLoop,
                                           output: asyncio.Queue):
     while True:
         try:
             async with aiohttp.ClientSession() as client:
                 for trading_pair in self._trading_pairs:
                     try:
                         snapshot: Dict[str, Any] = await self.get_snapshot(
                             client, trading_pair)
                         snapshot_timestamp: float = time.time()
                         snapshot_msg: OrderBookMessage = BlocktaneOrderBook.snapshot_message_from_exchange(
                             snapshot,
                             snapshot_timestamp,
                             metadata={"trading_pair": trading_pair})
                         output.put_nowait(snapshot_msg)
                         # self.logger().debug(f"Saved order book snapshot for {trading_pair}")
                         # Be careful not to go above blocktane's API rate limits.
                         await asyncio.sleep(5.0)
                     except asyncio.CancelledError:
                         raise
                     except Exception:
                         self.logger().error("Unexpected error.",
                                             exc_info=True)
                         await asyncio.sleep(5.0)
                 this_hour: pd.Timestamp = pd.Timestamp.utcnow().replace(
                     minute=0, second=0, microsecond=0)
                 next_hour: pd.Timestamp = this_hour + pd.Timedelta(hours=1)
                 delta: float = next_hour.timestamp() - time.time()
                 await asyncio.sleep(delta)
         except asyncio.CancelledError:
             raise
         except Exception:
             self.logger().error("Unexpected error.", exc_info=True)
             await asyncio.sleep(5.0)
    async def listen_for_trades(self, ev_loop: asyncio.BaseEventLoop,
                                output: asyncio.Queue):
        while True:
            try:
                ws_path: str = "&stream=".join([
                    f"{convert_to_exchange_trading_pair(trading_pair)}.trades"
                    for trading_pair in self._trading_pairs
                ])
                stream_url: str = f"{DIFF_STREAM_URL}/?stream={ws_path}"

                ws: websockets.WebSocketClientProtocol = await self.get_ws_connection(
                    stream_url)
                async for raw_msg in self._inner_messages(ws):
                    msg = ujson.loads(raw_msg)
                    if (list(msg.keys())[0].endswith("trades")):
                        trade_msg: OrderBookMessage = BlocktaneOrderBook.trade_message_from_exchange(
                            msg)
                        output.put_nowait(trade_msg)
            except asyncio.CancelledError:
                raise
            except asyncio.TimeoutError:
                self.logger().warning(
                    "WebSocket ping timed out. Reconnecting after 30 seconds..."
                )
            except Exception:
                self.logger().error(
                    "Unexpected error while maintaining the user event listen key. Retrying after "
                    "30 seconds...",
                    exc_info=True)
            finally:
                await ws.close()
                await asyncio.sleep(30)
 async def get_new_order_book(self, trading_pair: str) -> OrderBook:
     async with aiohttp.ClientSession() as client:
         snapshot: Dict[str, Any] = await self.get_snapshot(
             client, trading_pair, 1000)
         snapshot_timestamp: float = time.time()
         snapshot_msg: OrderBookMessage = BlocktaneOrderBook.snapshot_message_from_exchange(
             snapshot,
             snapshot_timestamp,
             metadata={"trading_pair": trading_pair})
         order_book: OrderBook = self.order_book_create_function()
         order_book.apply_snapshot(snapshot_msg.bids, snapshot_msg.asks,
                                   snapshot_msg.update_id)
         return order_book
    async def listen_for_order_book_diffs(self, ev_loop: asyncio.BaseEventLoop,
                                          output: asyncio.Queue):
        while True:
            try:
                ws_path: str = "&stream=".join([
                    f"{convert_to_exchange_trading_pair(trading_pair)}.ob-inc"
                    for trading_pair in self._trading_pairs
                ])
                stream_url: str = f"{DIFF_STREAM_URL}/?stream={ws_path}"

                ws: websockets.WebSocketClientProtocol = await self.get_ws_connection(
                    stream_url)
                async for raw_msg in self._inner_messages(ws):
                    msg = ujson.loads(raw_msg)
                    key = list(msg.keys())[0]
                    if ('ob-inc' in key):
                        pair = re.sub(r'\.ob-inc', '', key)
                        parsed_msg = {
                            "pair": convert_from_exchange_trading_pair(pair),
                            "bids":
                            msg[key]["bids"] if "bids" in msg[key] else [],
                            "asks":
                            msg[key]["asks"] if "asks" in msg[key] else []
                        }
                        order_book_message: OrderBookMessage = BlocktaneOrderBook.diff_message_from_exchange(
                            parsed_msg, time.time())
                        output.put_nowait(order_book_message)
            except asyncio.CancelledError:
                raise
            except asyncio.TimeoutError:
                self.logger().warning(
                    "WebSocket ping timed out. Reconnecting after 30 seconds..."
                )
            except Exception:
                self.logger().error(
                    "Unexpected error while maintaining the user event listen key. Retrying after "
                    "30 seconds...",
                    exc_info=True)
            finally:
                await ws.close()
                await asyncio.sleep(30)