async def get_order_book_data( trading_pair: str, throttler: Optional[AsyncThrottler] = None) -> Dict[str, any]: """ Retrieves the JSON order book data of the specified trading pair using the exchange's REST API. :param trading_pair: Specified trading pair. :param throttler: Optional AsyncThrottler used to throttle the API request. """ throttler = throttler or CryptoComAPIOrderBookDataSource._get_throttler_instance( ) async with aiohttp.ClientSession() as client: async with throttler.execute_task( CONSTANTS.GET_ORDER_BOOK_PATH_URL): url = crypto_com_utils.get_rest_url( CONSTANTS.GET_ORDER_BOOK_PATH_URL) params = { "depth": 150, "instrument_name": crypto_com_utils.convert_to_exchange_trading_pair( trading_pair), } orderbook_response = await client.get(url=url, params=params) if orderbook_response.status != 200: raise IOError( f"Error fetching OrderBook for {trading_pair} at {CONSTANTS.EXCHANGE_NAME}. " f"HTTP status is {orderbook_response.status}.") orderbook_data: List[Dict[str, Any]] = await safe_gather( orderbook_response.json()) orderbook_data = orderbook_data[0]["result"]["data"][0] return orderbook_data
async def fetch_trading_pairs( throttler: Optional[AsyncThrottler] = None) -> List[str]: """ Retrieves active trading pairs using the exchange's REST API. :param throttler: Optional AsyncThrottler used to throttle the API request """ throttler = throttler or CryptoComAPIOrderBookDataSource._get_throttler_instance( ) async with aiohttp.ClientSession() as client: async with throttler.execute_task(CONSTANTS.GET_TICKER_PATH_URL): url = crypto_com_utils.get_rest_url( path_url=CONSTANTS.GET_TICKER_PATH_URL) async with client.get(url=url, timeout=10) as response: if response.status == 200: try: data: Dict[str, Any] = await response.json() return [ crypto_com_utils. convert_from_exchange_trading_pair(item["i"]) for item in data["result"]["data"] ] except Exception: pass # Do nothing if the request fails -- there will be no autocomplete for kucoin trading pairs return []
def test_get_last_trade_prices(self, mock_api): url = crypto_com_utils.get_rest_url( path_url=CONSTANTS.GET_TICKER_PATH_URL) regex_url = re.compile(f"^{url}") expected_last_traded_price = 1.0 mock_responses = { "code": 0, "method": "public/get-ticker", "result": { "data": [ { # Truncated Response "i": self.ex_trading_pair, "a": expected_last_traded_price, } ] }, } mock_api.get(regex_url, body=ujson.dumps(mock_responses)) result = self.async_run_with_timeout( self.data_source.get_last_traded_prices( trading_pairs=[self.trading_pair])) self.assertEqual(result[self.trading_pair], expected_last_traded_price)
def test_get_new_order_book(self, mock_api): url = crypto_com_utils.get_rest_url( path_url=CONSTANTS.GET_ORDER_BOOK_PATH_URL) regex_url = re.compile(f"^{url}") snapshot_timestamp = 1634731570152 mock_response = { "code": 0, "method": "public/get-book", "result": { "instrument_name": self.ex_trading_pair, "depth": 150, "data": [{ "bids": [ [999.00, 1.0, 1], ], "asks": [ [1000.00, 1.0, 1], ], "t": snapshot_timestamp, }], }, } mock_api.get(regex_url, body=ujson.dumps(mock_response)) result = self.async_run_with_timeout( self.data_source.get_new_order_book(self.trading_pair)) self.assertIsInstance(result, OrderBook) self.assertEqual(snapshot_timestamp, result.snapshot_uid)
async def _api_request(self, method: str, path_url: str, params: Dict[str, Any] = {}, is_auth_required: bool = False) -> Dict[str, Any]: """ Sends an aiohttp request and waits for a response. :param method: The HTTP method, e.g. get or post :param path_url: The path url or the API end point :param is_auth_required: Whether an authentication is required, when True the function will add encrypted signature to the request. :returns A response in json format. """ async with self._throttler.execute_task(path_url): url = crypto_com_utils.get_rest_url(path_url) client = await self._http_client() if is_auth_required: request_id = crypto_com_utils.RequestId.generate_request_id() data = {"params": params} params = self._crypto_com_auth.generate_auth_dict( path_url, request_id, crypto_com_utils.get_ms_timestamp(), data) headers = self._crypto_com_auth.get_headers() else: headers = {"Content-Type": "application/json"} if method == "get": response = await client.get(url, headers=headers) elif method == "post": post_json = json.dumps(params) response = await client.post(url, data=post_json, headers=headers) else: raise NotImplementedError try: parsed_response = json.loads(await response.text()) except Exception as e: raise IOError( f"Error parsing data from {url}. Error: {str(e)}") if response.status != 200: raise IOError( f"Error fetching data from {url}. HTTP status is {response.status}. " f"Message: {parsed_response}") if parsed_response["code"] != 0: raise IOError( f"{url} API call failed, response: {parsed_response}") return parsed_response
def test_listen_for_order_book_snapshots_successful(self, mock_api): url = crypto_com_utils.get_rest_url( path_url=CONSTANTS.GET_ORDER_BOOK_PATH_URL) regex_url = re.compile(f"^{url}") mock_response = { "code": 0, "method": "public/get-book", "result": { "instrument_name": self.ex_trading_pair, "depth": 150, "data": [{ "bids": [ [999.00, 1.0, 1], ], "asks": [ [1000.00, 1.0, 1], ], "t": 1634731570152, }], }, } mock_api.get(regex_url, body=ujson.dumps(mock_response)) order_book_messages = asyncio.Queue() self.async_task = self.ev_loop.create_task( self.data_source.listen_for_order_book_snapshots( ev_loop=self.ev_loop, output=order_book_messages)) order_book_message = self.async_run_with_timeout( order_book_messages.get()) self.assertTrue(order_book_messages.empty()) self.assertEqual(1634731570152, order_book_message.update_id) self.assertEqual(1634731570152, order_book_message.timestamp) self.assertEqual(999.00, order_book_message.bids[0].price) self.assertEqual(1000.00, order_book_message.asks[0].price)
async def get_last_traded_prices( cls, trading_pairs: List[str], throttler: Optional[AsyncThrottler] = None) -> Dict[str, float]: result = {} throttler = throttler or cls._get_throttler_instance() async with aiohttp.ClientSession() as client: async with throttler.execute_task(CONSTANTS.GET_TICKER_PATH_URL): resp = await client.get( crypto_com_utils.get_rest_url( path_url=CONSTANTS.GET_TICKER_PATH_URL)) resp_json = await resp.json() for t_pair in trading_pairs: last_trade = [ o["a"] for o in resp_json["result"]["data"] if o["i"] == crypto_com_utils. convert_to_exchange_trading_pair(t_pair) ] if last_trade and last_trade[0] is not None: result[t_pair] = last_trade[0] return result
def test_fetch_trading_pairs(self, mock_api): url = crypto_com_utils.get_rest_url( path_url=CONSTANTS.GET_TICKER_PATH_URL) regex_url = re.compile(f"^{url}") mock_response = { "code": 0, "method": "public/get-ticker", "result": { "data": [ { # Truncated Response "i": self.ex_trading_pair, "a": 1.0, } ] }, } mock_api.get(regex_url, body=ujson.dumps(mock_response)) result = self.async_run_with_timeout( self.data_source.fetch_trading_pairs()) self.assertTrue(self.trading_pair in result)