def test_track_single_book_snapshot_message_with_past_diffs(self):
        past_diff_msg: OrderBookMessage = BitmexPerpetualOrderBook.diff_message_from_exchange(
            msg={
                "lastUpdateId": 1,
                "data_dict": {
                    "symbol": "COINALPHA-USD",
                    "bids": [["4.00000100", "431.00000000"]],
                    "asks": [["4.00000300", "12.00000000"]]
                }
            },
            timestamp=time.time())
        snapshot_msg: OrderBookMessage = BitmexPerpetualOrderBook.snapshot_message_from_exchange(
            msg={
                "trading_pair": "COINALPHA-USD",
                "update_id": 2,
                "bids": [["4.00000000", "431.00000000"]],
                "asks": [["4.00000200", "12.00000000"]]
            },
            timestamp=time.time())

        self.tracking_task = self.ev_loop.create_task(
            self.tracker._track_single_book(self.trading_pair))

        self.ev_loop.run_until_complete(asyncio.sleep(0.5))

        self._simulate_message_enqueue(
            self.tracker._past_diffs_windows[self.trading_pair], past_diff_msg)
        self._simulate_message_enqueue(
            self.tracker._tracking_message_queues[self.trading_pair],
            snapshot_msg)

        self.ev_loop.run_until_complete(asyncio.sleep(0.5))

        self.assertTrue(
            1 < self.tracker.order_books[self.trading_pair].snapshot_uid)
    async def listen_for_order_book_snapshots(self,
                                              ev_loop: asyncio.BaseEventLoop,
                                              output: asyncio.Queue):
        while True:
            try:
                for trading_pair in self._trading_pairs:
                    snapshot: Dict[str, Any] = await self.get_snapshot(
                        trading_pair,
                        domain=self._domain,
                        throttler=self._throttler,
                        api_factory=self._api_factory)

                    snapshot_timestamp: float = time.time()
                    bids = []
                    asks = []
                    size_currency = await utils.get_trading_pair_size_currency(
                        await self.convert_to_exchange_trading_pair(
                            hb_trading_pair=trading_pair,
                            domain=self._domain,
                            throttler=self._throttler))
                    if size_currency.is_base:
                        for order in snapshot:
                            order_details = [order['price'], order['size']]
                            asks.append(
                                order_details
                            ) if order['side'] == "Sell" else bids.append(
                                order_details)
                    else:
                        for order in snapshot:
                            order_details = [
                                order['price'], order['size'] / order['price']
                            ]
                            asks.append(
                                order_details
                            ) if order['side'] == "Sell" else bids.append(
                                order_details)

                    snapshot_dict = {
                        "bids": bids,
                        "asks": asks,
                        "update_id": snapshot[-1]["id"]
                    }
                    snapshot_msg: OrderBookMessage = BitmexPerpetualOrderBook.snapshot_message_from_exchange(
                        snapshot_dict,
                        snapshot_timestamp,
                        metadata={"trading_pair": trading_pair})
                    output.put_nowait(snapshot_msg)
                    self.logger().debug(
                        f"Saved order book snapshot for {trading_pair}")
                delta = CONSTANTS.ONE_HOUR - time.time() % CONSTANTS.ONE_HOUR
                await self._sleep(delta)
            except asyncio.CancelledError:
                raise
            except Exception:
                self.logger().error(
                    "Unexpected error occurred fetching orderbook snapshots. Retrying in 5 seconds...",
                    exc_info=True)
                await self._sleep(5.0)
    def setUp(self) -> None:
        super().setUp()
        self.tracker: BitmexPerpetualOrderBookTracker = BitmexPerpetualOrderBookTracker(
            trading_pairs=[self.trading_pair])
        self.tracking_task: Optional[asyncio.Task] = None

        # Simulate start()
        self.tracker._order_books[
            self.trading_pair] = BitmexPerpetualOrderBook()
        self.tracker._tracking_message_queues[
            self.trading_pair] = asyncio.Queue()
        self.tracker._past_diffs_windows[self.trading_pair] = deque()
        self.tracker._order_books_initialized.set()
 async def listen_for_trades(self, ev_loop: asyncio.BaseEventLoop,
                             output: asyncio.Queue):
     while True:
         msg = await self._message_queue[CONSTANTS.TRADE_STREAM_ID].get()
         msg.data["data_dict"] = {}
         trading_pair = await self.convert_from_exchange_trading_pair(
             exchange_trading_pair=msg.data["data"][0]["symbol"],
             domain=self._domain,
             throttler=self._throttler)
         for trade in msg.data["data"]:
             trade["symbol"] = trading_pair
             trade_message: OrderBookMessage = BitmexPerpetualOrderBook.trade_message_from_exchange(
                 trade)
             output.put_nowait(trade_message)
    def test_track_single_book_diff_message(self):
        diff_msg: OrderBookMessage = BitmexPerpetualOrderBook.diff_message_from_exchange(
            msg={
                "lastUpdateId": 1,
                "data_dict": {
                    "symbol": "COINALPHA-USD",
                    "bids": [["4.00000100", "431.00000000"]],
                    "asks": [["4.00000300", "12.00000000"]]
                }
            },
            timestamp=time.time())

        self._simulate_message_enqueue(
            self.tracker._tracking_message_queues[self.trading_pair], diff_msg)

        self.tracking_task = self.ev_loop.create_task(
            self.tracker._track_single_book(self.trading_pair))
        self.ev_loop.run_until_complete(asyncio.sleep(0.5))
    async def get_new_order_book(self, trading_pair: str) -> OrderBook:
        snapshot: List[Dict[str, Any]] = await self.get_snapshot(
            trading_pair, 1000, self._domain, self._throttler,
            self._api_factory)
        bids = []
        asks = []
        size_currency = await utils.get_trading_pair_size_currency(
            await
            self.convert_to_exchange_trading_pair(hb_trading_pair=trading_pair,
                                                  domain=self._domain,
                                                  throttler=self._throttler))
        if size_currency.is_base:
            for order in snapshot:
                order_details = [order['price'], order['size']]
                asks.append(
                    order_details) if order['side'] == "Sell" else bids.append(
                        order_details)
        else:
            for order in snapshot:
                order_details = [
                    order['price'], order['size'] / order['price']
                ]
                asks.append(
                    order_details) if order['side'] == "Sell" else bids.append(
                        order_details)

        snapshot_dict = {
            "bids": bids,
            "asks": asks,
            "update_id": snapshot[-1]["id"]
        }

        snapshot_timestamp: float = time.time()
        snapshot_msg: OrderBookMessage = BitmexPerpetualOrderBook.snapshot_message_from_exchange(
            snapshot_dict,
            snapshot_timestamp,
            metadata={"trading_pair": trading_pair})
        order_book = 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:
            msg = await self._message_queue[CONSTANTS.DIFF_STREAM_ID].get()
            timestamp: float = time.time()
            if msg.data["action"] in ["update", "insert", "delete"]:
                msg.data["data_dict"] = {}
                exchange_trading_pair = msg.data["data"][0]["symbol"]
                trading_pair = await self.convert_from_exchange_trading_pair(
                    exchange_trading_pair=exchange_trading_pair,
                    domain=self._domain,
                    throttler=self._throttler)

                size_currency = await utils.get_trading_pair_size_currency(
                    exchange_trading_pair)

                def size_fn(size, price):
                    final_size = size if size_currency.is_base else size / price
                    return final_size

                msg.data["data_dict"]["symbol"] = trading_pair
                asks = []
                bids = []
                for order in msg.data["data"]:
                    price = await self.order_id_to_price(
                        trading_pair, order["id"])
                    amount = 0.0 if msg.data['action'] == "delete" else size_fn(
                        order["size"], price)
                    order_details = [price, amount]
                    asks.append(order_details
                                ) if order["side"] == "Sell" else bids.append(
                                    order_details)

                msg.data["data_dict"]["bids"] = bids
                msg.data["data_dict"]["asks"] = asks
                order_book_message: OrderBookMessage = BitmexPerpetualOrderBook.diff_message_from_exchange(
                    msg.data, timestamp)
                output.put_nowait(order_book_message)