def test_get_last_traded_prices(self, mock_api): BybitAPIOrderBookDataSource._trading_pair_symbol_map[ CONSTANTS.DEFAULT_DOMAIN]["TKN1TKN2"] = "TKN1-TKN2" url1 = web_utils.rest_url(path_url=CONSTANTS.LAST_TRADED_PRICE_PATH, domain=CONSTANTS.DEFAULT_DOMAIN) url1 = f"{url1}?symbol={self.ex_trading_pair}" regex_url = re.compile(f"^{url1}".replace(".", r"\.").replace("?", r"\?")) resp = { "ret_code": 0, "ret_msg": None, "result": { "symbol": self.ex_trading_pair, "price": "50008" }, "ext_code": None, "ext_info": None } mock_api.get(regex_url, body=json.dumps(resp)) url2 = web_utils.rest_url(path_url=CONSTANTS.LAST_TRADED_PRICE_PATH, domain=CONSTANTS.DEFAULT_DOMAIN) url2 = f"{url2}?symbol=TKN1TKN2" regex_url = re.compile(f"^{url2}".replace(".", r"\.").replace("?", r"\?")) resp = { "ret_code": 0, "ret_msg": None, "result": { "symbol": "TKN1TKN2", "price": "2050" }, "ext_code": None, "ext_info": None } mock_api.get(regex_url, body=json.dumps(resp)) ret = self.async_run_with_timeout( coroutine=BybitAPIOrderBookDataSource.get_last_traded_prices( [self.trading_pair, "TKN1-TKN2"])) ticker_requests = [(key, value) for key, value in mock_api.requests.items() if key[1].human_repr().startswith(url1) or key[1].human_repr().startswith(url2)] request_params = ticker_requests[0][1][0].kwargs["params"] self.assertEqual(self.ex_trading_pair, request_params["symbol"]) request_params = ticker_requests[1][1][0].kwargs["params"] self.assertEqual("TKN1TKN2", request_params["symbol"]) self.assertEqual(ret[self.trading_pair], 50008) self.assertEqual(ret["TKN1-TKN2"], 2050)
def test_listen_for_order_book_snapshots_log_exception( self, mock_api, sleep_mock): mock_queue = AsyncMock() mock_queue.get.side_effect = ['ERROR', asyncio.CancelledError] self.ob_data_source._message_queue[ CONSTANTS.SNAPSHOT_EVENT_TYPE] = mock_queue msg_queue: asyncio.Queue = asyncio.Queue() sleep_mock.side_effect = [asyncio.CancelledError] url = web_utils.rest_url(path_url=CONSTANTS.SNAPSHOT_PATH_URL) regex_url = re.compile(f"^{url}".replace(".", r"\.").replace("?", r"\?")) mock_api.get(regex_url, exception=Exception) try: self.async_run_with_timeout( self.ob_data_source.listen_for_order_book_snapshots( self.ev_loop, msg_queue)) except asyncio.CancelledError: pass self.assertTrue( self._is_logged( "ERROR", "Unexpected error when processing public order book updates from exchange" ))
def test_get_snapshot_raises(self, mock_api): url = web_utils.rest_url(path_url=CONSTANTS.SNAPSHOT_PATH_URL) regex_url = re.compile(f"^{url}".replace(".", r"\.").replace("?", r"\?")) mock_api.get(regex_url, status=500) with self.assertRaises(IOError): self.async_run_with_timeout( coroutine=self.ob_data_source.get_snapshot(self.trading_pair))
def test_get_snapshot(self, mock_api): url = web_utils.rest_url(path_url=CONSTANTS.SNAPSHOT_PATH_URL) regex_url = re.compile(f"^{url}".replace(".", r"\.").replace("?", r"\?")) snapshot_data = self._snapshot_response() mock_api.get(regex_url, body=json.dumps(snapshot_data)) ret = self.async_run_with_timeout( coroutine=self.ob_data_source.get_snapshot(self.trading_pair)) self.assertEqual( ret, self._snapshot_response_processed()) # shallow comparison ok
def test_fetch_trading_pairs(self, mock_api): BybitAPIOrderBookDataSource._trading_pair_symbol_map = {} url = web_utils.rest_url(path_url=CONSTANTS.EXCHANGE_INFO_PATH_URL) resp = { "ret_code": 0, "ret_msg": "", "ext_code": None, "ext_info": None, "result": [{ "name": "BTCUSDT", "alias": "BTCUSDT", "baseCurrency": "BTC", "quoteCurrency": "USDT", "basePrecision": "0.000001", "quotePrecision": "0.01", "minTradeQuantity": "0.0001", "minTradeAmount": "10", "minPricePrecision": "0.01", "maxTradeQuantity": "2", "maxTradeAmount": "200", "category": 1 }, { "name": "ETHUSDT", "alias": "ETHUSDT", "baseCurrency": "ETH", "quoteCurrency": "USDT", "basePrecision": "0.0001", "quotePrecision": "0.01", "minTradeQuantity": "0.0001", "minTradeAmount": "10", "minPricePrecision": "0.01", "maxTradeQuantity": "2", "maxTradeAmount": "200", "category": 1 }] } mock_api.get(url, body=json.dumps(resp)) ret = self.async_run_with_timeout( coroutine=BybitAPIOrderBookDataSource.fetch_trading_pairs( domain=self.domain, throttler=self.throttler, time_synchronizer=self.time_synchronnizer, )) self.assertEqual(2, len(ret)) self.assertEqual("BTC-USDT", ret[0]) self.assertEqual("ETH-USDT", ret[1])
def test_fetch_trading_pairs_exception_raised(self, mock_api): BybitAPIOrderBookDataSource._trading_pair_symbol_map = {} url = web_utils.rest_url(path_url=CONSTANTS.EXCHANGE_INFO_PATH_URL) regex_url = re.compile(f"^{url}".replace(".", r"\.").replace("?", r"\?")) mock_api.get(regex_url, exception=Exception) result: Dict[str] = self.async_run_with_timeout( self.ob_data_source.fetch_trading_pairs()) self.assertEqual(0, len(result))
def test_get_new_order_book(self, mock_api): url = web_utils.rest_url(path_url=CONSTANTS.SNAPSHOT_PATH_URL) regex_url = re.compile(f"^{url}".replace(".", r"\.").replace("?", r"\?")) resp = self._snapshot_response() mock_api.get(regex_url, body=json.dumps(resp)) ret = self.async_run_with_timeout( coroutine=self.ob_data_source.get_new_order_book( self.trading_pair)) bid_entries = list(ret.bid_entries()) ask_entries = list(ret.ask_entries()) self.assertEqual(1, len(bid_entries)) self.assertEqual(50005.12, bid_entries[0].price) self.assertEqual(403.0416, bid_entries[0].amount) self.assertEqual(int(resp["result"]["time"]), bid_entries[0].update_id) self.assertEqual(1, len(ask_entries)) self.assertEqual(50006.34, ask_entries[0].price) self.assertEqual(0.2297, ask_entries[0].amount) self.assertEqual(int(resp["result"]["time"]), ask_entries[0].update_id)
def test_listen_for_order_book_snapshots_successful_rest( self, mock_api, _): mock_queue = AsyncMock() mock_queue.get.side_effect = asyncio.TimeoutError self.ob_data_source._message_queue[ CONSTANTS.SNAPSHOT_EVENT_TYPE] = mock_queue msg_queue: asyncio.Queue = asyncio.Queue() url = web_utils.rest_url(path_url=CONSTANTS.SNAPSHOT_PATH_URL) regex_url = re.compile(f"^{url}".replace(".", r"\.").replace("?", r"\?")) snapshot_data = self._snapshot_response() mock_api.get(regex_url, body=json.dumps(snapshot_data)) self.listening_task = self.ev_loop.create_task( self.ob_data_source.listen_for_order_book_snapshots( self.ev_loop, msg_queue)) msg: OrderBookMessage = self.async_run_with_timeout(msg_queue.get()) self.assertEqual(int(snapshot_data["result"]["time"]), msg.update_id)