def __init__(self, ascend_ex_api_key: str, ascend_ex_secret_key: str, trading_pairs: Optional[List[str]] = None, trading_required: bool = True ): """ :param ascend_ex_api_key: The API key to connect to private AscendEx APIs. :param ascend_ex_secret_key: The API secret. :param trading_pairs: The market trading pairs which to track order book data. :param trading_required: Whether actual trading is needed. """ super().__init__() self._trading_required = trading_required self._trading_pairs = trading_pairs self._throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS) self._order_book_tracker = AscendExOrderBookTracker(self._throttler, trading_pairs=trading_pairs) self._ascend_ex_auth = AscendExAuth(ascend_ex_api_key, ascend_ex_secret_key) self._user_stream_tracker = AscendExUserStreamTracker(self._throttler, self._ascend_ex_auth, trading_pairs) self._ev_loop = asyncio.get_event_loop() self._shared_client = None self._poll_notifier = asyncio.Event() self._last_timestamp = 0 self._in_flight_orders = {} # Dict[client_order_id:str, AscendExInFlightOrder] self._order_not_found_records = {} # Dict[client_order_id:str, count:int] self._trading_rules = {} # Dict[trading_pair:str, AscendExTradingRule] self._status_polling_task = None self._user_stream_event_listener_task = None self._trading_rules_polling_task = None self._last_poll_timestamp = 0 self._account_group = None # required in order to make post requests self._account_uid = None # required in order to produce deterministic order ids self._throttler = AsyncThrottler(rate_limits=CONSTANTS.RATE_LIMITS)
def setUp(self) -> None: super().setUp() self.throttler = AsyncThrottler(rate_limits=self.rate_limits) self._req_counters: Dict[str, int] = { limit.limit_id: 0 for limit in self.rate_limits }
def __init__(self, wazirx_auth: WazirxAuth): super().__init__() self._wazirx_auth: WazirxAuth = wazirx_auth self._last_recv_time: float = 0 self._auth_successful_event = asyncio.Event() self._throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS) self._shared_http_client = None
def __init__(self, wazirx_api_key: str, wazirx_secret_key: str, trading_pairs: Optional[List[str]] = None, trading_required: bool = True): """ :param wazirx_api_key: The API key to connect to private Wazirx APIs. :param wazirx_secret_key: The API secret. :param trading_pairs: The market trading pairs which to track order book data. :param trading_required: Whether actual trading is needed. """ super().__init__() self._trading_required = trading_required self._trading_pairs = trading_pairs self._wazirx_auth = WazirxAuth(wazirx_api_key, wazirx_secret_key) self._order_book_tracker = WazirxOrderBookTracker( trading_pairs=trading_pairs) self._user_stream_tracker = WazirxUserStreamTracker( self._wazirx_auth, trading_pairs) self._ev_loop = asyncio.get_event_loop() self._shared_client = None self._poll_notifier = asyncio.Event() self._last_timestamp = 0 self._in_flight_orders = { } # Dict[client_order_id:str, WazirxInFlightOrder] self._order_not_found_records = { } # Dict[client_order_id:str, count:int] self._trading_rules = {} # Dict[trading_pair:str, TradingRule] self._status_polling_task = None self._user_stream_event_listener_task = None self._trading_rules_polling_task = None self._last_poll_timestamp = 0 self._throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS)
def __init__(self, mexc_api_key: str, mexc_secret_key: str, poll_interval: float = 5.0, order_book_tracker_data_source_type: OrderBookTrackerDataSourceType = OrderBookTrackerDataSourceType.EXCHANGE_API, trading_pairs: Optional[List[str]] = None, trading_required: bool = True): super().__init__() self._throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS) self._shared_client = aiohttp.ClientSession() self._async_scheduler = AsyncCallScheduler(call_interval=0.5) self._data_source_type = order_book_tracker_data_source_type self._ev_loop = asyncio.get_event_loop() self._mexc_auth = MexcAuth(api_key=mexc_api_key, secret_key=mexc_secret_key) self._in_flight_orders = {} self._last_poll_timestamp = 0 self._last_timestamp = 0 self._order_book_tracker = MexcOrderBookTracker( throttler=self._throttler, trading_pairs=trading_pairs, shared_client=self._shared_client) self._poll_notifier = asyncio.Event() self._poll_interval = poll_interval self._status_polling_task = None self._trading_required = trading_required self._trading_rules = {} self._trading_rules_polling_task = None self._user_stream_tracker = MexcUserStreamTracker(throttler=self._throttler, mexc_auth=self._mexc_auth, trading_pairs=trading_pairs, shared_client=self._shared_client) self._user_stream_tracker_task = None self._user_stream_event_listener_task = None
def setUp(self) -> None: super().setUp() self.throttler = AsyncThrottler(rate_limits=self.rate_limits) self._req_counters: Dict[str, int] = { limit.limit_id: 0 for limit in self.rate_limits } self.client_config_map = ClientConfigAdapter(ClientConfigMap())
def __init__(self, client_config_map: "ClientConfigAdapter", ndax_uid: str, ndax_api_key: str, ndax_secret_key: str, ndax_account_name: str, trading_pairs: Optional[List[str]] = None, trading_required: bool = True, domain: Optional[str] = None): """ :param ndax_uid: User ID of the account :param ndax_api_key: The API key to connect to private NDAX APIs. :param ndax_secret_key: The API secret. :param ndax_account_name: The name of the account associated to the user account. :param trading_pairs: The market trading pairs which to track order book data. :param trading_required: Whether actual trading is needed. """ super().__init__(client_config_map) self._trading_required = trading_required self._trading_pairs = trading_pairs self._auth = NdaxAuth(uid=ndax_uid, api_key=ndax_api_key, secret_key=ndax_secret_key, account_name=ndax_account_name) self._throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS) self._shared_client = aiohttp.ClientSession() self._set_order_book_tracker( NdaxOrderBookTracker(throttler=self._throttler, shared_client=self._shared_client, trading_pairs=trading_pairs, domain=domain)) self._user_stream_tracker = NdaxUserStreamTracker( throttler=self._throttler, shared_client=self._shared_client, auth_assistant=self._auth, domain=domain) self._domain = domain self._ev_loop = asyncio.get_event_loop() self._poll_notifier = asyncio.Event() self._last_timestamp = 0 self._in_flight_orders = {} self._order_not_found_records = { } # Dict[client_order_id:str, count:int] self._trading_rules = {} # Dict[trading_pair:str, TradingRule] self._last_poll_timestamp = 0 self._status_polling_task = None self._user_stream_tracker_task = None self._user_stream_event_listener_task = None self._trading_rules_polling_task = None self._account_id = None
def setUp(self) -> None: super().setUp() self.mocking_assistant = NetworkMockingAssistant() self.throttler = AsyncThrottler( build_rate_limits_by_tier(self.api_tier)) self.data_source = KrakenAPIOrderBookDataSource( self.throttler, trading_pairs=[self.trading_pair])
def setUp(self) -> None: super().setUp() self.ev_loop = asyncio.get_event_loop() self.base_asset = "BTC" self.quote_asset = "USDT" self.trading_pair = f"{self.base_asset}-{self.quote_asset}" self.ex_trading_pair = f"{self.base_asset}/{self.quote_asset}" self.log_records = [] self.listening_task = None self.async_task: Optional[asyncio.Task] = None self.throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS) self.api_factory = build_api_factory(throttler=self.throttler) self.data_source = AscendExAPIOrderBookDataSource( api_factory=self.api_factory, throttler=self.throttler, trading_pairs=[self.trading_pair]) self.data_source.logger().setLevel(1) self.data_source.logger().addHandler(self) self.mocking_assistant = NetworkMockingAssistant() self.resume_test_event = asyncio.Event() AscendExAPIOrderBookDataSource._trading_pair_symbol_map = bidict( {self.ex_trading_pair: f"{self.base_asset}-{self.quote_asset}"})
def setUp(self) -> None: super().setUp() self.log_records = [] self.listening_task: Optional[asyncio.Task] = None self.mocking_assistant = NetworkMockingAssistant() self.throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS) self.mock_time_provider = MagicMock() self.mock_time_provider.time.return_value = 1000 self.auth = KucoinAuth( self.api_key, self.api_passphrase, self.api_secret_key, time_provider=self.mock_time_provider) client_config_map = ClientConfigAdapter(ClientConfigMap()) self.connector = KucoinExchange( client_config_map=client_config_map, kucoin_api_key="", kucoin_passphrase="", kucoin_secret_key="", trading_pairs=[], trading_required=False) self.data_source = KucoinAPIUserStreamDataSource( auth=self.auth, trading_pairs=[self.trading_pair], connector=self.connector, api_factory=self.connector._web_assistants_factory) self.data_source.logger().setLevel(1) self.data_source.logger().addHandler(self)
def setUpClass(cls): cls.ev_loop: asyncio.AbstractEventLoop = asyncio.get_event_loop() cls.throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS) cls.order_book_tracker: GateIoOrderBookTracker = GateIoOrderBookTracker( cls.throttler, cls.trading_pairs) cls.order_book_tracker.start() cls.ev_loop.run_until_complete(cls.wait_til_tracker_ready())
def test_rest_assistant_call_with_pre_and_post_processing(self, mocked_api): url = "https://www.test.com/url" resp = {"one": 1} pre_processor_ran = False post_processor_ran = False mocked_api.get(url, body=json.dumps(resp).encode()) class PreProcessor(RESTPreProcessorBase): async def pre_process(self, request: RESTRequest) -> RESTRequest: nonlocal pre_processor_ran pre_processor_ran = True return request class PostProcessor(RESTPostProcessorBase): async def post_process(self, response: RESTResponse) -> RESTResponse: nonlocal post_processor_ran post_processor_ran = True return response pre_processors = [PreProcessor()] post_processors = [PostProcessor()] connection = RESTConnection(aiohttp.ClientSession()) assistant = RESTAssistant( connection=connection, throttler=AsyncThrottler(rate_limits=[]), rest_pre_processors=pre_processors, rest_post_processors=post_processors) req = RESTRequest(method=RESTMethod.GET, url=url) ret = self.async_run_with_timeout(assistant.call(req)) ret_json = self.async_run_with_timeout(ret.json()) self.assertEqual(resp, ret_json) self.assertTrue(pre_processor_ran) self.assertTrue(post_processor_ran)
def test_sending_messages_increment_message_number(self, mock_ws): sent_messages = [] throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS) mock_ws.return_value = self.mocking_assistant.create_websocket_mock() mock_ws.return_value.send_json.side_effect = lambda sent_message: sent_messages.append( sent_message) adaptor = NdaxWebSocketAdaptor(throttler, websocket=mock_ws.return_value) payload = {} self.async_run_with_timeout( adaptor.send_request(endpoint_name=CONSTANTS.WS_PING_REQUEST, payload=payload, limit_id=CONSTANTS.WS_PING_ID)) self.async_run_with_timeout( adaptor.send_request(endpoint_name=CONSTANTS.WS_PING_REQUEST, payload=payload, limit_id=CONSTANTS.WS_PING_ID)) self.async_run_with_timeout( adaptor.send_request(endpoint_name=CONSTANTS.WS_ORDER_BOOK_CHANNEL, payload=payload)) self.assertEqual(3, len(sent_messages)) message = sent_messages[0] self.assertEqual(1, message.get('i')) message = sent_messages[1] self.assertEqual(2, message.get('i')) message = sent_messages[2] self.assertEqual(3, message.get('i'))
def setUp(self) -> None: super().setUp() self.log_records = [] self.listening_task: Optional[asyncio.Task] = None self.mocking_assistant = NetworkMockingAssistant() self.throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS) self.mock_time_provider = MagicMock() self.mock_time_provider.time.return_value = 1000 self.auth = KucoinAuth(self.api_key, self.api_passphrase, self.api_secret_key, time_provider=self.mock_time_provider) self.time_synchronizer = TimeSynchronizer() self.time_synchronizer.add_time_offset_ms_sample(0) self.api_factory = web_utils.build_api_factory( throttler=self.throttler, time_synchronizer=self.time_synchronizer, auth=self.auth) self.data_source = KucoinAPIUserStreamDataSource( throttler=self.throttler, api_factory=self.api_factory) self.data_source.logger().setLevel(1) self.data_source.logger().addHandler(self)
def test_send_subscription_message(self, ws_connect_mock): ws_connect_mock.return_value = self.mocking_assistant.create_websocket_mock( ) throttler = AsyncThrottler(Constants.RATE_LIMITS) websocket = CoinzoomWebsocket(throttler=throttler) message = {Constants.WS_SUB["TRADES"]: {'symbol': "BTC/USDT"}} self.async_run_with_timeout(websocket.connect()) self.async_run_with_timeout(websocket.subscribe(message)) self.async_run_with_timeout(websocket.unsubscribe(message)) sent_requests = self.mocking_assistant.text_messages_sent_through_websocket( ws_connect_mock.return_value) sent_subscribe_message = json.loads(sent_requests[0]) expected_subscribe_message = { "TradeSummaryRequest": { "action": "subscribe", "symbol": "BTC/USDT" } } self.assertEquals(expected_subscribe_message, sent_subscribe_message) sent_unsubscribe_message = json.loads(sent_requests[0]) expected_unsubscribe_message = { "TradeSummaryRequest": { "action": "subscribe", "symbol": "BTC/USDT" } } self.assertEquals(expected_unsubscribe_message, sent_unsubscribe_message)
def setUp(self) -> None: super().setUp() self.throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS) self.auth = KucoinAuth(self.api_key, self.api_passphrase, self.api_secret_key) self.ob_data_source = KucoinAPIOrderBookDataSource( self.throttler, [self.trading_pair], self.auth)
def setUp(self) -> None: super().setUp() self.log_records = [] self.listening_task: Optional[asyncio.Task] = None self.mocking_assistant = NetworkMockingAssistant() self.throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS) self.mock_time_provider = MagicMock() self.mock_time_provider.time.return_value = 1000 self.auth = GateIoAuth(api_key=self.api_key, secret_key=self.api_secret_key, time_provider=self.mock_time_provider) self.time_synchronizer = TimeSynchronizer() self.time_synchronizer.add_time_offset_ms_sample(0) client_config_map = ClientConfigAdapter(ClientConfigMap()) self.connector = GateIoExchange(client_config_map=client_config_map, gate_io_api_key="", gate_io_secret_key="", trading_pairs=[], trading_required=False) self.connector._web_assistants_factory._auth = self.auth self.data_source = GateIoAPIUserStreamDataSource( self.auth, trading_pairs=[self.trading_pair], connector=self.connector, api_factory=self.connector._web_assistants_factory) self.data_source.logger().setLevel(1) self.data_source.logger().addHandler(self) self.connector._set_trading_pair_symbol_map( bidict({self.ex_trading_pair: self.trading_pair}))
def test_get_ws_assistant(self): factory = WebAssistantsFactory(throttler=AsyncThrottler( rate_limits=[])) ws_assistant = self.async_run_with_timeout(factory.get_ws_assistant()) self.assertIsInstance(ws_assistant, WSAssistant)
def test_send_subscription_message(self, request_id_mock, ws_connect_mock): request_id_mock.return_value = 1234567899 ws_connect_mock.return_value = self.mocking_assistant.create_websocket_mock( ) throttler = AsyncThrottler(Constants.RATE_LIMITS) websocket = AltmarketsWebsocket(throttler=throttler) message = [Constants.WS_SUB["TRADES"].format(trading_pair="btcusdt")] self.async_run_with_timeout(websocket.connect()) self.async_run_with_timeout(websocket.subscribe(message)) self.async_run_with_timeout(websocket.unsubscribe(message)) sent_requests = self.mocking_assistant.text_messages_sent_through_websocket( ws_connect_mock.return_value) sent_subscribe_message = json.loads(sent_requests[0]) expected_subscribe_message = { "event": "subscribe", "id": 1234567899, "streams": ['btcusdt.trades'] } self.assertEquals(expected_subscribe_message, sent_subscribe_message) sent_unsubscribe_message = json.loads(sent_requests[1]) expected_unsubscribe_message = { "event": "unsubscribe", "id": 1234567899, "streams": ['btcusdt.trades'] } self.assertEquals(expected_unsubscribe_message, sent_unsubscribe_message)
async def api_call_with_retries(request: CoinflexRESTRequest, rest_assistant: RESTAssistant, throttler: AsyncThrottler, logger: logging.Logger = None, try_count: int = 0) -> Dict[str, Any]: async with throttler.execute_task(limit_id=request.throttler_limit_id): http_status, resp, request_errors = await rest_response_with_errors(rest_assistant, request) if isinstance(resp, dict): _extract_error_from_response(resp) if request_errors or resp is None: if try_count < CONSTANTS.API_MAX_RETRIES and not request.disable_retries: try_count += 1 time_sleep = retry_sleep_time(try_count) suppress_msgs = ['Forbidden'] err_msg = (f"Error fetching data from {request.url}. HTTP status is {http_status}. " f"Retrying in {time_sleep:.0f}s. {resp or ''}") if (resp is not None and resp not in suppress_msgs) or try_count > 1: if logger: logger.network(err_msg) else: print(err_msg) elif logger: logger.debug(err_msg, exc_info=True) await asyncio.sleep(time_sleep) return await api_call_with_retries(request=request, rest_assistant=rest_assistant, throttler=throttler, logger=logger, try_count=try_count) else: raise CoinflexAPIError({"errors": resp, "status": http_status}) return resp
def setUp(self) -> None: super().setUp() self.rest_assistant = self.async_run_with_timeout( web_utils.build_api_factory().get_rest_assistant()) self.logger.setLevel(1) self.logger.addHandler(self) self.log_records = [] self.throttler = AsyncThrottler(rate_limits=CONSTANTS.RATE_LIMITS)
def test_close(self): throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS) ws = AsyncMock() adaptor = NdaxWebSocketAdaptor(throttler, websocket=ws) asyncio.get_event_loop().run_until_complete(adaptor.close()) self.assertEquals(1, ws.close.await_count)
def setUp(self) -> None: super().setUp() self.throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS) self.auth = KucoinAuth(self.api_key, self.api_passphrase, self.api_secret_key) self.data_source = KucoinAPIUserStreamDataSource( self.throttler, self.auth) self.mocking_assistant = NetworkMockingAssistant()
def setUp(self) -> None: super().setUp() self.mocking_assistant = NetworkMockingAssistant() altmarkets_auth = AltmarketsAuth(api_key="someKey", secret_key="someSecret") self.data_source = AltmarketsAPIUserStreamDataSource( AsyncThrottler(Constants.RATE_LIMITS), altmarkets_auth=altmarkets_auth, trading_pairs=[self.trading_pair])
def __init__(self, auth: Optional[AltmarketsAuth] = None, throttler: Optional[AsyncThrottler] = None): self._auth: Optional[AltmarketsAuth] = auth self._isPrivate = True if self._auth is not None else False self._WS_URL = Constants.WS_PRIVATE_URL if self._isPrivate else Constants.WS_PUBLIC_URL self._client: Optional[websockets.WebSocketClientProtocol] = None self._is_subscribed = False self._throttler = throttler or AsyncThrottler(Constants.RATE_LIMITS)
def setUpClass(cls) -> None: super().setUpClass() cls.base_asset = "COINALPHA" cls.quote_asset = "HBOT" cls.trading_pair = f"{cls.base_asset}-{cls.quote_asset}" cls.api_key = "testKey" cls.api_secret_key = "testSecretKey" cls.username = "******" cls.throttler = AsyncThrottler(Constants.RATE_LIMITS)
def test_close(self, mock_ws): throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS) mock_ws.return_value = self.mocking_assistant.create_websocket_mock() adaptor = NdaxWebSocketAdaptor(throttler, websocket=mock_ws.return_value) asyncio.get_event_loop().run_until_complete(adaptor.close()) self.assertEquals(1, mock_ws.return_value.close.await_count)
def setUp(self) -> None: super().setUp() self.mocking_assistant = NetworkMockingAssistant() self.throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS) not_a_real_secret = "kQH5HW/8p1uGOVjbgWA7FunAmGO8lsSUXNsu3eow76sz84Q18fWxnyRzBHCd3pd5nE9qa99HAZtuZuj6F1huXg==" kraken_auth = KrakenAuth(api_key="someKey", secret_key=not_a_real_secret) self.data_source = KrakenAPIUserStreamDataSource( self.throttler, kraken_auth)
def test_close(self, mock_ws): throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS) mock_ws.return_value = self.mocking_assistant.create_websocket_mock() adaptor = NdaxWebSocketAdaptor(throttler, websocket=mock_ws.return_value) self.async_run_with_timeout(adaptor.close()) self.assertEquals(1, mock_ws.return_value.close.await_count)
def test_receive_message(self): throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS) ws = AsyncMock() ws.recv.return_value = 'test message' adaptor = NdaxWebSocketAdaptor(throttler, websocket=ws) received_message = asyncio.get_event_loop().run_until_complete(adaptor.recv()) self.assertEqual('test message', received_message)