def test_track_single_book_apply_snapshot(self): snapshot_data = [ NdaxOrderBookEntry(*[ 93617617, 1, 1626788175000, 0, 37800.0, 1, 37750.0, 1, 0.015, 0 ]), NdaxOrderBookEntry(*[ 93617617, 1, 1626788175000, 0, 37800.0, 1, 37751.0, 1, 0.015, 1 ]) ] snapshot_msg = NdaxOrderBook.snapshot_message_from_exchange( msg={"data": snapshot_data}, timestamp=1626788175000, metadata={ "trading_pair": self.trading_pair, "instrument_id": self.instrument_id }) self.simulate_queue_order_book_messages(snapshot_msg) with self.assertRaises(asyncio.TimeoutError): # Allow 5 seconds for tracker to process some messages. self.tracking_task = self.ev_loop.create_task( asyncio.wait_for( self.tracker._track_single_book(self.trading_pair), 2.0)) self.ev_loop.run_until_complete(self.tracking_task) self.assertEqual( 0, self.tracker.order_books[self.trading_pair].snapshot_uid)
def test_get_order_book_data(self, mock_api): self.mocking_assistant.configure_http_request_mock(mock_api) self.simulate_trading_pair_ids_initialized() mock_response: List[List[Any]] = [ # mdUpdateId, accountId, actionDateTime, actionType, lastTradePrice, orderId, price, productPairCode, quantity, side [93617617, 1, 1626788175416, 0, 37813.22, 1, 37750.6, 1, 0.014698, 0] ] self.mocking_assistant.add_http_response(mock_api, 200, mock_response) results = self.ev_loop.run_until_complete( asyncio.gather(self.data_source.get_order_book_data(self.trading_pair))) result = results[0] self.assertTrue("data" in result) self.assertGreaterEqual(len(result["data"]), 0) self.assertEqual(NdaxOrderBookEntry(*mock_response[0]), result["data"][0])
async def get_order_book_data( self, trading_pair: str, domain: Optional[str] = None, throttler: Optional[AsyncThrottler] = None) -> Dict[str, any]: """Retrieves entire orderbook snapshot of the specified trading pair via the REST API. Args: trading_pair (str): Trading pair of the particular orderbook. domain (str): The label of the variant of the connector that is being used. throttler (AsyncThrottler): API-requests throttler to use. Returns: Dict[str, any]: Parsed API Response. """ if not len(self._trading_pair_id_map) > 0: await self.init_trading_pair_ids(domain) params = { "OMSId": 1, "InstrumentId": self._trading_pair_id_map[trading_pair], "Depth": 200, } throttler = throttler or self._get_throttler_instance() async with throttler.execute_task(CONSTANTS.ORDER_BOOK_URL): async with self._shared_client.get( f"{ndax_utils.rest_api_url(domain) + CONSTANTS.ORDER_BOOK_URL}", params=params) as response: status = response.status if status != 200: raise IOError( f"Error fetching OrderBook for {trading_pair} at {CONSTANTS.ORDER_BOOK_URL}. " f"HTTP {status}. Response: {await response.json()}") response_ls: List[Any] = await response.json() orderbook_entries: List[NdaxOrderBookEntry] = [ NdaxOrderBookEntry(*entry) for entry in response_ls ] return { "data": orderbook_entries, "timestamp": int(time.time() * 1e3) }
def test_delete_sell_order_book_entry_always_has_zero_amount(self): entries = [ NdaxOrderBookEntry(mdUpdateId=1, accountId=1, actionDateTime=1627935956059, actionType=2, lastTradePrice=42211.51, orderId=1, price=41508.19, productPairCode=5, quantity=1.5, side=1) ] content = {"data": entries} message = NdaxOrderBookMessage(message_type=OrderBookMessageType.DIFF, content=content, timestamp=time.time()) asks = message.asks self.assertEqual(1, len(asks)) self.assertEqual(41508.19, asks[0].price) self.assertEqual(0.0, asks[0].amount) self.assertEqual(1, asks[0].update_id)
async def listen_for_order_book_diffs(self, ev_loop: asyncio.BaseEventLoop, output: asyncio.Queue): """ Listen for orderbook diffs using WebSocket API. """ if not len(self._trading_pair_id_map) > 0: await self.init_trading_pair_ids(self._domain, self._throttler, self._shared_client) while True: try: ws_adaptor: NdaxWebSocketAdaptor = await self._create_websocket_connection( ) for trading_pair in self._trading_pairs: payload = { "OMSId": 1, "Symbol": convert_to_exchange_trading_pair(trading_pair), "Depth": 200 } async with self._throttler.execute_task( CONSTANTS.WS_ORDER_BOOK_CHANNEL): await ws_adaptor.send_request( endpoint_name=CONSTANTS.WS_ORDER_BOOK_CHANNEL, payload=payload) async for raw_msg in ws_adaptor.iter_messages(): payload = NdaxWebSocketAdaptor.payload_from_raw_message( raw_msg) msg_event: str = NdaxWebSocketAdaptor.endpoint_from_raw_message( raw_msg) if msg_event in [ CONSTANTS.WS_ORDER_BOOK_CHANNEL, CONSTANTS.WS_ORDER_BOOK_L2_UPDATE_EVENT ]: msg_data: List[NdaxOrderBookEntry] = [ NdaxOrderBookEntry(*entry) for entry in payload ] msg_timestamp: int = int(time.time() * 1e3) msg_product_code: int = msg_data[0].productPairCode content = {"data": msg_data} msg_trading_pair: Optional[str] = None for trading_pair, instrument_id in self._trading_pair_id_map.items( ): if msg_product_code == instrument_id: msg_trading_pair = trading_pair break if msg_trading_pair: metadata = { "trading_pair": msg_trading_pair, "instrument_id": msg_product_code, } order_book_message = None if msg_event == CONSTANTS.WS_ORDER_BOOK_CHANNEL: order_book_message: NdaxOrderBookMessage = NdaxOrderBook.snapshot_message_from_exchange( msg=content, timestamp=msg_timestamp, metadata=metadata) elif msg_event == CONSTANTS.WS_ORDER_BOOK_L2_UPDATE_EVENT: order_book_message: NdaxOrderBookMessage = NdaxOrderBook.diff_message_from_exchange( msg=content, timestamp=msg_timestamp, metadata=metadata) self._last_traded_prices[ order_book_message. trading_pair] = order_book_message.last_traded_price await output.put(order_book_message) except asyncio.CancelledError: raise except Exception: self.logger().network( "Unexpected error with WebSocket connection.", exc_info=True, app_warning_msg= "Unexpected error with WebSocket connection. Retrying in 30 seconds. " "Check network connection.") if ws_adaptor: await ws_adaptor.close() await self._sleep(30.0)