async def _authenticate(self, ws: NdaxWebSocketAdaptor): """ Authenticates user to websocket """ try: auth_payload: Dict[ str, Any] = self._auth_assistant.get_ws_auth_payload() async with self._throttler.execute_task( CONSTANTS.AUTHENTICATE_USER_ENDPOINT_NAME): await ws.send_request( CONSTANTS.AUTHENTICATE_USER_ENDPOINT_NAME, auth_payload) auth_resp = await ws.receive() auth_payload: Dict[str, Any] = ws.payload_from_raw_message( auth_resp.data) if not auth_payload["Authenticated"]: self.logger().error(f"Response: {auth_payload}", exc_info=True) raise Exception( "Could not authenticate websocket connection with NDAX") auth_user = auth_payload.get("User") self._account_id = auth_user.get("AccountId") self._oms_id = auth_user.get("OMSId") except asyncio.CancelledError: raise except Exception as ex: self.logger().error( f"Error occurred when authenticating to user stream ({ex})", exc_info=True) raise
def test_get_payload_from_raw_received_message(self, mock_ws): throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS) mock_ws.return_value = self.mocking_assistant.create_websocket_mock() payload = {"Key1": True, "Key2": "Value2"} message = {"m": 1, "i": 1, "n": "Endpoint", "o": json.dumps(payload)} raw_message = json.dumps(message) adaptor = NdaxWebSocketAdaptor(throttler, websocket=mock_ws.return_value) extracted_payload = adaptor.payload_from_raw_message( raw_message=raw_message) self.assertEqual(payload, extracted_payload)
def test_listening_process_authenticates_and_subscribes_to_events( self, ws_connect_mock): messages = asyncio.Queue() ws_connect_mock.return_value = self.mocking_assistant.create_websocket_mock( ) initial_last_recv_time = self.data_source.last_recv_time self.listening_task = asyncio.get_event_loop().create_task( self.data_source.listen_for_user_stream(asyncio.get_event_loop(), messages)) # Add the authentication response for the websocket self.mocking_assistant.add_websocket_aiohttp_message( ws_connect_mock.return_value, self._authentication_response(True)) # Add a dummy message for the websocket to read and include in the "messages" queue self.mocking_assistant.add_websocket_aiohttp_message( ws_connect_mock.return_value, json.dumps('dummyMessage')) first_received_message = asyncio.get_event_loop().run_until_complete( messages.get()) self.assertEqual('dummyMessage', first_received_message) self.assertTrue( self._is_logged('INFO', "Authenticating to User Stream...")) self.assertTrue( self._is_logged('INFO', "Successfully authenticated to User Stream.")) self.assertTrue( self._is_logged('INFO', "Successfully subscribed to user events.")) sent_messages = self.mocking_assistant.json_messages_sent_through_websocket( ws_connect_mock.return_value) self.assertEqual(2, len(sent_messages)) authentication_request = sent_messages[0] subscription_request = sent_messages[1] self.assertEqual( CONSTANTS.AUTHENTICATE_USER_ENDPOINT_NAME, NdaxWebSocketAdaptor.endpoint_from_raw_message( json.dumps(authentication_request))) self.assertEqual( CONSTANTS.SUBSCRIBE_ACCOUNT_EVENTS_ENDPOINT_NAME, NdaxWebSocketAdaptor.endpoint_from_raw_message( json.dumps(subscription_request))) subscription_payload = NdaxWebSocketAdaptor.payload_from_raw_message( json.dumps(subscription_request)) expected_payload = {"AccountId": self.account_id, "OMSId": self.oms_id} self.assertEqual(expected_payload, subscription_payload) self.assertGreater(self.data_source.last_recv_time, initial_last_recv_time)
def test_get_payload_from_raw_received_message(self): throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS) ws = AsyncMock() payload = {"Key1": True, "Key2": "Value2"} message = {"m": 1, "i": 1, "n": "Endpoint", "o": json.dumps(payload)} raw_message = json.dumps(message) adaptor = NdaxWebSocketAdaptor(throttler, websocket=ws) extracted_payload = adaptor.payload_from_raw_message(raw_message=raw_message) self.assertEqual(payload, extracted_payload)
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)