def test_get_last_traded_prices(self, mock_api):
        url = web_utils.rest_url(CONSTANTS.SERVER_TIME_PATH_URL,
                                 domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".",
                                                 r"\.").replace("?", r"\?"))

        response = {"serverTime": 1640000003000}

        mock_api.get(regex_url, body=json.dumps(response))

        url = web_utils.rest_url(path_url=CONSTANTS.TICKER_PRICE_CHANGE_URL,
                                 domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".",
                                                 r"\.").replace("?", r"\?"))
        mock_response: Dict[str, Any] = {
            # Truncated responses
            "lastPrice": "10.0",
        }
        mock_api.get(regex_url, body=json.dumps(mock_response))

        result: Dict[str, Any] = self.async_run_with_timeout(
            self.data_source.get_last_traded_prices(
                trading_pairs=[self.trading_pair], domain=self.domain))
        self.assertTrue(self.trading_pair in result)
        self.assertEqual(10.0, result[self.trading_pair])
コード例 #2
0
    def test_rest_url_main_domain(self):
        path_url = "/TEST_PATH_URL"

        expected_url = f"{CONSTANTS.PERPETUAL_BASE_URL}{CONSTANTS.API_VERSION_V2}{path_url}"
        self.assertEqual(
            expected_url,
            web_utils.rest_url(path_url, api_version=CONSTANTS.API_VERSION_V2))
        self.assertEqual(
            expected_url,
            web_utils.rest_url(path_url, api_version=CONSTANTS.API_VERSION_V2))
    def test_listen_for_order_book_snapshots_logs_exception_error_with_response(
            self, mock_api):
        url = web_utils.rest_url(CONSTANTS.SNAPSHOT_REST_URL,
                                 domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".",
                                                 r"\.").replace("?", r"\?"))

        mock_response = {
            "m": 1,
            "i": 2,
        }
        mock_api.get(regex_url,
                     body=json.dumps(mock_response),
                     callback=self.resume_test_callback)

        msg_queue: asyncio.Queue = asyncio.Queue()

        self.listening_task = self.ev_loop.create_task(
            self.data_source.listen_for_order_book_snapshots(
                self.ev_loop, msg_queue))

        self.async_run_with_timeout(self.resume_test_event.wait())

        self.assertTrue(
            self._is_logged(
                "ERROR",
                "Unexpected error occurred fetching orderbook snapshots. Retrying in 5 seconds..."
            ))
    def test_get_funding_info(self, mock_api):
        self.assertNotIn(self.trading_pair, self.data_source._funding_info)

        url = web_utils.rest_url(CONSTANTS.MARK_PRICE_URL, domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".",
                                                 r"\.").replace("?", r"\?"))

        mock_response = {
            "symbol": self.ex_trading_pair,
            "markPrice": "46382.32704603",
            "indexPrice": "46385.80064948",
            "estimatedSettlePrice": "46510.13598963",
            "lastFundingRate": "0.00010000",
            "interestRate": "0.00010000",
            "nextFundingTime": 1641312000000,
            "time": 1641288825000,
        }
        mock_api.get(regex_url, body=json.dumps(mock_response))

        result = self.async_run_with_timeout(
            self.data_source.get_funding_info(trading_pair=self.trading_pair))

        self.assertIsInstance(result, FundingInfo)
        self.assertEqual(result.trading_pair, self.trading_pair)
        self.assertEqual(result.index_price,
                         Decimal(mock_response["indexPrice"]))
        self.assertEqual(result.mark_price,
                         Decimal(mock_response["markPrice"]))
        self.assertEqual(result.next_funding_utc_timestamp,
                         mock_response["nextFundingTime"])
        self.assertEqual(result.rate,
                         Decimal(mock_response["lastFundingRate"]))
 def test_init_trading_pair_symbols_successful(self, mock_api):
     url = web_utils.rest_url(path_url=CONSTANTS.EXCHANGE_INFO_URL,
                              domain=self.domain)
     regex_url = re.compile(f"^{url}".replace(".",
                                              r"\.").replace("?", r"\?"))
     mock_response: Dict[str, Any] = {
         # Truncated Responses
         "symbols": [
             {
                 "symbol": self.ex_trading_pair,
                 "pair": self.ex_trading_pair,
                 "baseAsset": self.base_asset,
                 "quoteAsset": self.quote_asset,
                 "status": "TRADING",
             },
             {
                 "symbol": "INACTIVEMARKET",
                 "status": "INACTIVE"
             },
         ],
     }
     mock_api.get(regex_url, status=200, body=json.dumps(mock_response))
     self.async_run_with_timeout(
         self.data_source.init_trading_pair_symbols(
             domain=self.domain,
             time_synchronizer=self.data_source._time_synchronizer))
     self.assertEqual(1, len(self.data_source._trading_pair_symbol_map))
コード例 #6
0
    def test_manage_listen_key_task_loop_keep_alive_successful(self, mock_api):
        url = web_utils.rest_url(
            path_url=CONSTANTS.BINANCE_USER_STREAM_ENDPOINT,
            domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".",
                                                 r"\.").replace("?", r"\?"))

        mock_api.put(regex_url,
                     body=ujson.dumps({}),
                     callback=self._mock_responses_done_callback)

        self.data_source._current_listen_key = self.listen_key

        # Simulate LISTEN_KEY_KEEP_ALIVE_INTERVAL reached
        self.data_source._last_listen_key_ping_ts = 0

        self.listening_task = self.ev_loop.create_task(
            self.data_source._manage_listen_key_task_loop())

        self.async_run_with_timeout(self.mock_done_event.wait())

        self.assertTrue(
            self._is_logged("INFO",
                            f"Refreshed listen key {self.listen_key}."))
        self.assertGreater(self.data_source._last_listen_key_ping_ts, 0)
コード例 #7
0
    def test_manage_listen_key_task_loop_keep_alive_failed(self, mock_api):
        url = web_utils.rest_url(
            path_url=CONSTANTS.BINANCE_USER_STREAM_ENDPOINT,
            domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".",
                                                 r"\.").replace("?", r"\?"))

        mock_api.put(regex_url,
                     status=400,
                     body=ujson.dumps(self._error_response()),
                     callback=self._mock_responses_done_callback)

        self.data_source._current_listen_key = self.listen_key

        # Simulate LISTEN_KEY_KEEP_ALIVE_INTERVAL reached
        self.data_source._last_listen_key_ping_ts = 0

        self.listening_task = self.ev_loop.create_task(
            self.data_source._manage_listen_key_task_loop())

        self.async_run_with_timeout(self.mock_done_event.wait())

        self.assertTrue(
            self._is_logged("ERROR", "Error occurred renewing listen key... "))
        self.assertIsNone(self.data_source._current_listen_key)
        self.assertFalse(
            self.data_source._listen_key_initialized_event.is_set())
コード例 #8
0
    def test_listen_for_user_stream_create_websocket_connection_failed(
            self, mock_api, mock_ws):
        url = web_utils.rest_url(
            path_url=CONSTANTS.BINANCE_USER_STREAM_ENDPOINT,
            domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".",
                                                 r"\.").replace("?", r"\?"))

        mock_api.post(regex_url,
                      body=self._successful_get_listen_key_response())

        mock_ws.side_effect = Exception("TEST ERROR.")

        msg_queue = asyncio.Queue()

        self.listening_task = self.ev_loop.create_task(
            self.data_source.listen_for_user_stream(msg_queue))

        try:
            self.async_run_with_timeout(msg_queue.get())
        except asyncio.exceptions.TimeoutError:
            pass

        self.assertTrue(
            self._is_logged(
                "INFO", f"Successfully obtained listen key {self.listen_key}"))
        self.assertTrue(
            self._is_logged(
                "ERROR",
                "Unexpected error while listening to user stream. Retrying after 5 seconds... Error: TEST ERROR.",
            ))
コード例 #9
0
    def test_listen_for_user_stream_iter_message_throws_exception(
            self, mock_api, _, mock_ws):
        url = web_utils.rest_url(
            path_url=CONSTANTS.BINANCE_USER_STREAM_ENDPOINT,
            domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".",
                                                 r"\.").replace("?", r"\?"))

        mock_response = {"listenKey": self.listen_key}
        mock_api.post(regex_url, body=ujson.dumps(mock_response))

        msg_queue: asyncio.Queue = asyncio.Queue()
        mock_ws.return_value = self.mocking_assistant.create_websocket_mock()
        mock_ws.return_value.receive.side_effect = Exception("TEST ERROR")
        mock_ws.return_value.closed = False
        mock_ws.return_value.close.side_effect = Exception

        self.listening_task = self.ev_loop.create_task(
            self.data_source.listen_for_user_stream(msg_queue))

        try:
            self.async_run_with_timeout(msg_queue.get())
        except Exception:
            pass

        self.assertTrue(
            self._is_logged(
                "INFO", f"Successfully obtained listen key {self.listen_key}"))
        self.assertTrue(
            self._is_logged(
                "ERROR",
                "Unexpected error while listening to user stream. Retrying after 5 seconds... Error: TEST ERROR",
            ))
 def test_trading_pair_symbol_map_dictionary_not_initialized(
         self, mock_api):
     BinancePerpetualAPIOrderBookDataSource._trading_pair_symbol_map = {}
     url = web_utils.rest_url(path_url=CONSTANTS.EXCHANGE_INFO_URL,
                              domain=self.domain)
     regex_url = re.compile(f"^{url}".replace(".",
                                              r"\.").replace("?", r"\?"))
     mock_response: Dict[str, Any] = {
         # Truncated Responses
         "symbols": [
             {
                 "symbol": self.ex_trading_pair,
                 "pair": self.ex_trading_pair,
                 "baseAsset": self.base_asset,
                 "quoteAsset": self.quote_asset,
                 "status": "TRADING",
             },
         ]
     }
     mock_api.get(regex_url, status=200, body=json.dumps(mock_response))
     self.async_run_with_timeout(
         self.data_source.trading_pair_symbol_map(
             domain=self.domain,
             time_synchronizer=self.data_source._time_synchronizer))
     self.assertEqual(1, len(self.data_source._trading_pair_symbol_map))
    def test_listen_for_order_book_snapshots_successful(self, mock_api):
        url = web_utils.rest_url(CONSTANTS.SNAPSHOT_REST_URL,
                                 domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".",
                                                 r"\.").replace("?", r"\?"))

        mock_response = {
            "lastUpdateId": 1027024,
            "E": 1589436922972,
            "T": 1589436922959,
            "bids": [["10", "1"]],
            "asks": [["11", "1"]],
        }
        mock_api.get(regex_url, body=json.dumps(mock_response))

        msg_queue: asyncio.Queue = asyncio.Queue()
        self.listening_task = self.ev_loop.create_task(
            self.data_source.listen_for_order_book_snapshots(
                self.ev_loop, msg_queue))

        result = self.async_run_with_timeout(msg_queue.get())

        self.assertIsInstance(result, OrderBookMessage)
        self.assertEqual(OrderBookMessageType.SNAPSHOT, result.type)
        self.assertTrue(result.has_update_id)
        self.assertEqual(result.update_id, 1027024)
        self.assertEqual(self.trading_pair, result.content["trading_pair"])
コード例 #12
0
    def test_rest_url_testnet_domain(self):
        path_url = "/TEST_PATH_URL"

        expected_url = f"{CONSTANTS.TESTNET_BASE_URL}{CONSTANTS.API_VERSION_V2}{path_url}"
        self.assertEqual(
            expected_url,
            web_utils.rest_url(path_url=path_url,
                               domain="testnet",
                               api_version=CONSTANTS.API_VERSION_V2))
コード例 #13
0
    def test_get_listen_key_exception_raised(self, mock_api):
        url = web_utils.rest_url(
            path_url=CONSTANTS.BINANCE_USER_STREAM_ENDPOINT,
            domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".",
                                                 r"\.").replace("?", r"\?"))

        mock_api.post(regex_url,
                      status=400,
                      body=ujson.dumps(self._error_response))

        with self.assertRaises(IOError):
            self.async_run_with_timeout(self.data_source.get_listen_key())
コード例 #14
0
    def test_ping_listen_key_successful(self, mock_api):
        url = web_utils.rest_url(
            path_url=CONSTANTS.BINANCE_USER_STREAM_ENDPOINT,
            domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".",
                                                 r"\.").replace("?", r"\?"))

        mock_api.put(regex_url, body=ujson.dumps({}))

        self.data_source._current_listen_key = self.listen_key
        result: bool = self.async_run_with_timeout(
            self.data_source.ping_listen_key())
        self.assertTrue(result)
コード例 #15
0
    def test_get_listen_key_successful(self, mock_api):
        url = web_utils.rest_url(
            path_url=CONSTANTS.BINANCE_USER_STREAM_ENDPOINT,
            domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".",
                                                 r"\.").replace("?", r"\?"))

        mock_api.post(regex_url,
                      body=self._successful_get_listen_key_response())

        result: str = self.async_run_with_timeout(
            self.data_source.get_listen_key())

        self.assertEqual(self.listen_key, result)
    def test_init_trading_pair_symbols_failure(self, mock_api):
        BinancePerpetualAPIOrderBookDataSource._trading_pair_symbol_map = {}
        url = web_utils.rest_url(path_url=CONSTANTS.EXCHANGE_INFO_URL,
                                 domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".",
                                                 r"\.").replace("?", r"\?"))

        mock_api.get(regex_url, status=400, body=json.dumps(["ERROR"]))

        map = self.async_run_with_timeout(
            self.data_source.trading_pair_symbol_map(
                domain=self.domain,
                time_synchronizer=self.data_source._time_synchronizer))
        self.assertEqual(0, len(map))
    def test_get_funding_info_from_exchange_error_response(self, mock_api):
        url = web_utils.rest_url(CONSTANTS.MARK_PRICE_URL, domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".",
                                                 r"\.").replace("?", r"\?"))

        mock_api.get(regex_url, status=400)

        result = self.async_run_with_timeout(
            self.data_source._get_funding_info_from_exchange(
                self.trading_pair))
        self.assertIsNone(result)
        self._is_logged(
            "ERROR",
            f"Unable to fetch FundingInfo for {self.trading_pair}. Error: None"
        )
    def test_get_snapshot_exception_raised(self, mock_api):
        url = web_utils.rest_url(CONSTANTS.SNAPSHOT_REST_URL,
                                 domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".",
                                                 r"\.").replace("?", r"\?"))
        mock_api.get(regex_url, status=400, body=json.dumps(["ERROR"]))

        with self.assertRaises(IOError) as context:
            self.async_run_with_timeout(
                self.data_source.get_snapshot(
                    trading_pair=self.trading_pair,
                    domain=self.domain,
                    time_synchronizer=self.data_source._time_synchronizer))

        self.assertEqual(
            "Error executing request GET /depth. HTTP status is 400. Error: [\"ERROR\"]",
            str(context.exception))
 def test_get_new_order_book(self, mock_api):
     url = web_utils.rest_url(CONSTANTS.SNAPSHOT_REST_URL,
                              domain=self.domain)
     regex_url = re.compile(f"^{url}".replace(".",
                                              r"\.").replace("?", r"\?"))
     mock_response = {
         "lastUpdateId": 1027024,
         "E": 1589436922972,
         "T": 1589436922959,
         "bids": [["10", "1"]],
         "asks": [["11", "1"]],
     }
     mock_api.get(regex_url, status=200, body=json.dumps(mock_response))
     result = self.async_run_with_timeout(
         self.data_source.get_new_order_book(
             trading_pair=self.trading_pair))
     self.assertIsInstance(result, OrderBook)
     self.assertEqual(1027024, result.snapshot_uid)
    def test_listen_for_order_book_snapshots_cancelled_error_raised(
            self, mock_api):
        url = web_utils.rest_url(CONSTANTS.SNAPSHOT_REST_URL,
                                 domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".",
                                                 r"\.").replace("?", r"\?"))

        mock_api.get(regex_url, exception=asyncio.CancelledError)

        msg_queue: asyncio.Queue = asyncio.Queue()

        with self.assertRaises(asyncio.CancelledError):
            self.listening_task = self.ev_loop.create_task(
                self.data_source.listen_for_order_book_snapshots(
                    self.ev_loop, msg_queue))
            self.async_run_with_timeout(self.listening_task)

        self.assertEqual(0, msg_queue.qsize())
    def test_get_snapshot_successful(self, mock_api):
        url = web_utils.rest_url(CONSTANTS.SNAPSHOT_REST_URL,
                                 domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".",
                                                 r"\.").replace("?", r"\?"))
        mock_response = {
            "lastUpdateId": 1027024,
            "E": 1589436922972,
            "T": 1589436922959,
            "bids": [["10", "1"]],
            "asks": [["11", "1"]],
        }
        mock_api.get(regex_url, status=200, body=json.dumps(mock_response))

        result: Dict[str, Any] = self.async_run_with_timeout(
            self.data_source.get_snapshot(
                trading_pair=self.trading_pair,
                domain=self.domain,
                time_synchronizer=self.data_source._time_synchronizer))
        self.assertEqual(mock_response, result)
コード例 #22
0
    def test_ping_listen_key_failed_log_warning(self, mock_api):
        url = web_utils.rest_url(
            path_url=CONSTANTS.BINANCE_USER_STREAM_ENDPOINT,
            domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".",
                                                 r"\.").replace("?", r"\?"))

        mock_api.put(regex_url,
                     status=400,
                     body=ujson.dumps(self._error_response()))

        self.data_source._current_listen_key = self.listen_key
        result: bool = self.async_run_with_timeout(
            self.data_source.ping_listen_key())

        self.assertTrue(
            self._is_logged(
                "WARNING",
                f"Failed to refresh the listen key {self.listen_key}: {self._error_response()}"
            ))
        self.assertFalse(result)
コード例 #23
0
    def test_listen_for_user_stream_successful(self, mock_api, mock_ws):
        url = web_utils.rest_url(
            path_url=CONSTANTS.BINANCE_USER_STREAM_ENDPOINT,
            domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".",
                                                 r"\.").replace("?", r"\?"))

        mock_api.post(regex_url,
                      body=self._successful_get_listen_key_response())

        mock_ws.return_value = self.mocking_assistant.create_websocket_mock()

        self.mocking_assistant.add_websocket_aiohttp_message(
            mock_ws.return_value, self._simulate_user_update_event())

        msg_queue = asyncio.Queue()
        self.listening_task = self.ev_loop.create_task(
            self.data_source.listen_for_user_stream(msg_queue))

        msg = self.async_run_with_timeout(msg_queue.get())
        self.assertTrue(msg, self._simulate_user_update_event)
        mock_ws.return_value.ping.assert_called()
コード例 #24
0
    def test_listen_for_user_stream_does_not_queue_empty_payload(
            self, mock_api, mock_ws):
        url = web_utils.rest_url(
            path_url=CONSTANTS.BINANCE_USER_STREAM_ENDPOINT,
            domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".",
                                                 r"\.").replace("?", r"\?"))

        mock_api.post(regex_url,
                      body=self._successful_get_listen_key_response())

        mock_ws.return_value = self.mocking_assistant.create_websocket_mock()

        self.mocking_assistant.add_websocket_aiohttp_message(
            mock_ws.return_value, "")

        msg_queue = asyncio.Queue()
        self.listening_task = self.ev_loop.create_task(
            self.data_source.listen_for_user_stream(msg_queue))

        self.mocking_assistant.run_until_all_aiohttp_messages_delivered(
            mock_ws.return_value)

        self.assertEqual(0, msg_queue.qsize())