def test_track_single_book_diff_message(self, mock_utils): # Mocks binance_utils for BinanceOrderBook.diff_message_from_exchange() mock_utils.return_value = self.trading_pair diff_msg: OrderBookMessage = BinanceOrderBook.diff_message_from_exchange( msg={ "e": "depthUpdate", "E": 123456789, "s": "BNBBTC", "U": 1, "u": 2, "b": [ [ "0.0024", "10" ] ], "a": [ [ "0.0026", "100" ] ] } ) 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)) self.assertEqual(0, self.tracker.order_books[self.trading_pair].snapshot_uid) self.assertEqual(2, self.tracker.order_books[self.trading_pair].last_diff_uid)
async def listen_for_order_book_diffs(self, ev_loop: asyncio.BaseEventLoop, output: asyncio.Queue): while True: try: ws_path: str = "/".join([ f"{convert_to_exchange_trading_pair(trading_pair).lower()}@depth" for trading_pair in self._trading_pairs ]) url = DIFF_STREAM_URL.format(self._domain) stream_url: str = f"{url}/{ws_path}" async with websockets.connect(stream_url) as ws: ws: websockets.WebSocketClientProtocol = ws async for raw_msg in self._inner_messages(ws): msg = ujson.loads(raw_msg) order_book_message: OrderBookMessage = BinanceOrderBook.diff_message_from_exchange( msg, time.time()) output.put_nowait(order_book_message) except asyncio.CancelledError: raise except Exception: self.logger().error( "Unexpected error with WebSocket connection. Retrying after 30 seconds...", exc_info=True) await asyncio.sleep(30.0)
async def listen_for_order_book_diffs(self, ev_loop: asyncio.BaseEventLoop, output: asyncio.Queue): ws = None while True: try: ws = await self._create_websocket_connection() payload = { "method": "SUBSCRIBE", "params": [ f"{binance_utils.convert_to_exchange_trading_pair(trading_pair).lower()}@depth" for trading_pair in self._trading_pairs ], "id": self.DIFF_STREAM_ID } await ws.send_json(payload) async for json_msg in self._iter_messages(ws): if "result" in json_msg: continue order_book_message: OrderBookMessage = BinanceOrderBook.diff_message_from_exchange( json_msg, time.time()) output.put_nowait(order_book_message) except asyncio.CancelledError: raise except Exception: self.logger().error( "Unexpected error with WebSocket connection. Retrying after 30 seconds...", exc_info=True) finally: ws and await ws.close() await self._sleep(30.0)
def test_diff_message_from_exchange(self): diff_msg = BinanceOrderBook.diff_message_from_exchange( msg={ "e": "depthUpdate", "E": 123456789, "s": "COINALPHAHBOT", "U": 1, "u": 2, "b": [["0.0024", "10"]], "a": [["0.0026", "100"]] }, timestamp=1640000000.0, metadata={"trading_pair": "COINALPHA-HBOT"}) self.assertEqual("COINALPHA-HBOT", diff_msg.trading_pair) self.assertEqual(OrderBookMessageType.DIFF, diff_msg.type) self.assertEqual(1640000000.0, diff_msg.timestamp) self.assertEqual(2, diff_msg.update_id) self.assertEqual(1, diff_msg.first_update_id) self.assertEqual(-1, diff_msg.trade_id) self.assertEqual(1, len(diff_msg.bids)) self.assertEqual(0.0024, diff_msg.bids[0].price) self.assertEqual(10.0, diff_msg.bids[0].amount) self.assertEqual(2, diff_msg.bids[0].update_id) self.assertEqual(1, len(diff_msg.asks)) self.assertEqual(0.0026, diff_msg.asks[0].price) self.assertEqual(100.0, diff_msg.asks[0].amount) self.assertEqual(2, diff_msg.asks[0].update_id)
async def listen_for_order_book_diffs(self, ev_loop: asyncio.AbstractEventLoop, output: asyncio.Queue): """ Reads the order diffs events queue. For each event creates a diff message instance and adds it to the output queue :param ev_loop: the event loop the method will run in :param output: a queue to add the created diff messages """ message_queue = self._message_queue[CONSTANTS.DIFF_EVENT_TYPE] while True: try: json_msg = await message_queue.get() if "result" in json_msg: continue trading_pair = await BinanceAPIOrderBookDataSource.trading_pair_associated_to_exchange_symbol( symbol=json_msg["s"], domain=self._domain, api_factory=self._api_factory, throttler=self._throttler, time_synchronizer=self._time_synchronizer) order_book_message: OrderBookMessage = BinanceOrderBook.diff_message_from_exchange( json_msg, time.time(), {"trading_pair": trading_pair}) output.put_nowait(order_book_message) except asyncio.CancelledError: raise except Exception: self.logger().exception( "Unexpected error when processing public order book updates from exchange" )
async def _parse_order_book_diff_message(self, raw_message: Dict[str, Any], message_queue: asyncio.Queue): if "result" not in raw_message: trading_pair = await self._connector.trading_pair_associated_to_exchange_symbol( symbol=raw_message["s"]) order_book_message: OrderBookMessage = BinanceOrderBook.diff_message_from_exchange( raw_message, time.time(), {"trading_pair": trading_pair}) message_queue.put_nowait(order_book_message)
def test_track_single_book_snapshot_message_with_past_diffs(self, mock_utils): # Mocks binance_utils for BinanceOrderBook.diff_message_from_exchange() mock_utils.return_value = self.trading_pair snapshot_msg: OrderBookMessage = BinanceOrderBook.snapshot_message_from_exchange( msg={ "trading_pair": self.trading_pair, "lastUpdateId": 1, "bids": [ ["4.00000000", "431.00000000"] ], "asks": [ ["4.00000200", "12.00000000"] ] }, timestamp=time.time() ) past_diff_msg: OrderBookMessage = BinanceOrderBook.diff_message_from_exchange( msg={ "e": "depthUpdate", "E": 123456789, "s": "BNBBTC", "U": 1, "u": 2, "b": [ [ "0.0024", "10" ] ], "a": [ [ "0.0026", "100" ] ] } ) 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.assertEqual(1, self.tracker.order_books[self.trading_pair].snapshot_uid) self.assertEqual(2, self.tracker.order_books[self.trading_pair].last_diff_uid)