def setUp(self) -> None: super().setUp() self.api_key = "testApiKey" self.passphrase = "testPassphrase" self.secret_key = "testSecretKey" self.mock_time_provider = MagicMock() self.mock_time_provider.time.return_value = 1000 self.auth = KucoinAuth( api_key=self.api_key, passphrase=self.passphrase, secret_key=self.secret_key, time_provider=self.mock_time_provider, )
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)
async def get_snapshot( cls, client: aiohttp.ClientSession, trading_pair: str, auth: KucoinAuth = None, throttler: Optional[AsyncThrottler] = None, ) -> Dict[str, Any]: throttler = throttler or cls._get_throttler_instance() params: Dict = { "symbol": convert_to_exchange_trading_pair(trading_pair) } if auth is not None: url = CONSTANTS.BASE_PATH_URL + CONSTANTS.SNAPSHOT_PATH_URL limit_id = CONSTANTS.SNAPSHOT_PATH_URL else: url = CONSTANTS.BASE_PATH_URL + CONSTANTS.SNAPSHOT_NO_AUTH_PATH_URL limit_id = CONSTANTS.SNAPSHOT_NO_AUTH_PATH_URL path_url = f"{URL(url).path}?{urlencode(params)}" headers = auth.add_auth_to_params("get", path_url) if auth else None async with throttler.execute_task(limit_id): async with client.get(url, params=params, headers=headers) as response: response: aiohttp.ClientResponse = response if response.status != 200: raise IOError( f"Error fetching Kucoin market snapshot for {trading_pair}. " f"HTTP status is {response.status}.") data: Dict[str, Any] = await response.json() return data
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 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.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 setUpClass(cls): cls.ev_loop: asyncio.BaseEventLoop = asyncio.get_event_loop() cls.kucoin_auth = KucoinAuth(conf.kucoin_api_key, conf.kucoin_passphrase, conf.kucoin_secret_key) cls.user_stream_tracker: KucoinUserStreamTracker = KucoinUserStreamTracker( kucoin_auth=cls.kucoin_auth) cls.user_stream_tracker_task: asyncio.Task = safe_ensure_future( cls.user_stream_tracker.start())
async def get_snapshot(client: aiohttp.ClientSession, trading_pair: str, auth: KucoinAuth) -> Dict[str, Any]: params: Dict = {"symbol": convert_to_exchange_trading_pair(trading_pair)} path_url = f"/api/v3/market/orderbook/level2?{urlencode(params)}" headers = auth.add_auth_to_params("get", path_url) async with client.get(SNAPSHOT_REST_URL, params=params, headers=headers) as response: response: aiohttp.ClientResponse = response if response.status != 200: raise IOError(f"Error fetching Kucoin market snapshot for {trading_pair}. " f"HTTP status is {response.status}.") data: Dict[str, Any] = await response.json() return data
def __init__(self, kucoin_api_key: str, kucoin_passphrase: str, kucoin_secret_key: str, trading_pairs: Optional[List[str]] = None, trading_required: bool = True, domain: str = CONSTANTS.DEFAULT_DOMAIN): self._domain = domain self._time_synchronizer = TimeSynchronizer() super().__init__() self._auth = KucoinAuth( api_key=kucoin_api_key, passphrase=kucoin_passphrase, secret_key=kucoin_secret_key, time_provider=self._time_synchronizer) self._throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS) self._api_factory = web_utils.build_api_factory( throttler=self._throttler, time_synchronizer=self._time_synchronizer, domain=self._domain, auth=self._auth) self._last_poll_timestamp = 0 self._last_timestamp = 0 self._trading_pairs = trading_pairs self._order_book_tracker = OrderBookTracker( data_source=KucoinAPIOrderBookDataSource( trading_pairs=trading_pairs, domain=self._domain, api_factory=self._api_factory, throttler=self._throttler, time_synchronizer=self._time_synchronizer), trading_pairs=trading_pairs, domain=self._domain) self._user_stream_tracker = UserStreamTracker( data_source=KucoinAPIUserStreamDataSource( domain=self._domain, api_factory=self._api_factory, throttler=self._throttler)) self._poll_notifier = asyncio.Event() 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._trading_fees_polling_task = None self._trading_required = trading_required self._trading_rules = {} self._trading_fees = {} self._order_tracker: ClientOrderTracker = ClientOrderTracker(connector=self)
async def get_snapshot(client: aiohttp.ClientSession, trading_pair: str, auth: KucoinAuth = None) -> Dict[str, Any]: params: Dict = { "symbol": convert_to_exchange_trading_pair(trading_pair) } url = SNAPSHOT_REST_URL if auth else SNAPSHOT_REST_URL_NO_AUTH path_url = f"{URL(url).path}?{urlencode(params)}" headers = auth.add_auth_to_params("get", path_url) if auth else None async with client.get(url, params=params, headers=headers) as response: response: aiohttp.ClientResponse = response if response.status != 200: raise IOError( f"Error fetching Kucoin market snapshot for {trading_pair}. " f"HTTP status is {response.status}.") data: Dict[str, Any] = await response.json() return data
class KucoinAuthTests(TestCase): def setUp(self) -> None: super().setUp() self.api_key = "testApiKey" self.passphrase = "testPassphrase" self.secret_key = "testSecretKey" self.mock_time_provider = MagicMock() self.mock_time_provider.time.return_value = 1000 self.auth = KucoinAuth( api_key=self.api_key, passphrase=self.passphrase, secret_key=self.secret_key, time_provider=self.mock_time_provider, ) def async_run_with_timeout(self, coroutine: Awaitable, timeout: int = 1): ret = asyncio.get_event_loop().run_until_complete( asyncio.wait_for(coroutine, timeout)) return ret def _sign(self, message: str, key: str) -> str: signed_message = base64.b64encode( hmac.new(key.encode("utf-8"), message.encode("utf-8"), hashlib.sha256).digest()) return signed_message.decode("utf-8") def test_add_auth_headers_to_get_request_without_params(self): request = RESTRequest(method=RESTMethod.GET, url="https://test.url/api/endpoint", is_auth_required=True, throttler_limit_id="/api/endpoint") self.async_run_with_timeout(self.auth.rest_authenticate(request)) self.assertEqual(self.api_key, request.headers["KC-API-KEY"]) self.assertEqual("1000000", request.headers["KC-API-TIMESTAMP"]) self.assertEqual("2", request.headers["KC-API-KEY-VERSION"]) expected_signature = self._sign("1000000" + "GET" + request.throttler_limit_id, key=self.secret_key) self.assertEqual(expected_signature, request.headers["KC-API-SIGN"]) expected_passphrase = self._sign(self.passphrase, key=self.secret_key) self.assertEqual(expected_passphrase, request.headers["KC-API-PASSPHRASE"]) self.assertEqual(CONSTANTS.HB_PARTNER_ID, request.headers["KC-API-PARTNER"]) expected_partner_signature = self._sign( "1000000" + CONSTANTS.HB_PARTNER_ID + self.api_key, key=CONSTANTS.HB_PARTNER_KEY) self.assertEqual(expected_partner_signature, request.headers["KC-API-PARTNER-SIGN"]) def test_add_auth_headers_to_get_request_with_params(self): request = RESTRequest(method=RESTMethod.GET, url="https://test.url/api/endpoint", params={ "param_z": "value_param_z", "param_a": "value_param_a" }, is_auth_required=True, throttler_limit_id="/api/endpoint") self.async_run_with_timeout(self.auth.rest_authenticate(request)) self.assertEqual(self.api_key, request.headers["KC-API-KEY"]) self.assertEqual("1000000", request.headers["KC-API-TIMESTAMP"]) self.assertEqual("2", request.headers["KC-API-KEY-VERSION"]) full_endpoint = f"{request.throttler_limit_id}?param_a=value_param_a¶m_z=value_param_z" expected_signature = self._sign("1000000" + "GET" + full_endpoint, key=self.secret_key) self.assertEqual(expected_signature, request.headers["KC-API-SIGN"]) expected_passphrase = self._sign(self.passphrase, key=self.secret_key) self.assertEqual(expected_passphrase, request.headers["KC-API-PASSPHRASE"]) self.assertEqual(CONSTANTS.HB_PARTNER_ID, request.headers["KC-API-PARTNER"]) expected_partner_signature = self._sign( "1000000" + CONSTANTS.HB_PARTNER_ID + self.api_key, key=CONSTANTS.HB_PARTNER_KEY) self.assertEqual(expected_partner_signature, request.headers["KC-API-PARTNER-SIGN"]) def test_add_auth_headers_to_post_request(self): body = {"param_z": "value_param_z", "param_a": "value_param_a"} request = RESTRequest(method=RESTMethod.POST, url="https://test.url/api/endpoint", data=json.dumps(body), is_auth_required=True, throttler_limit_id="/api/endpoint") self.async_run_with_timeout(self.auth.rest_authenticate(request)) self.assertEqual(self.api_key, request.headers["KC-API-KEY"]) self.assertEqual("1000000", request.headers["KC-API-TIMESTAMP"]) self.assertEqual("2", request.headers["KC-API-KEY-VERSION"]) expected_signature = self._sign( "1000000" + "POST" + request.throttler_limit_id + json.dumps(body), key=self.secret_key) self.assertEqual(expected_signature, request.headers["KC-API-SIGN"]) expected_passphrase = self._sign(self.passphrase, key=self.secret_key) self.assertEqual(expected_passphrase, request.headers["KC-API-PASSPHRASE"]) self.assertEqual(CONSTANTS.HB_PARTNER_ID, request.headers["KC-API-PARTNER"]) expected_partner_signature = self._sign( "1000000" + CONSTANTS.HB_PARTNER_ID + self.api_key, key=CONSTANTS.HB_PARTNER_KEY) self.assertEqual(expected_partner_signature, request.headers["KC-API-PARTNER-SIGN"]) def test_no_auth_added_to_wsrequest(self): payload = {"param1": "value_param_1"} request = WSRequest(payload=payload, is_auth_required=True) self.async_run_with_timeout(self.auth.ws_authenticate(request)) self.assertEqual(payload, request.payload)
def authenticator(self): return KucoinAuth(api_key=self.kucoin_api_key, passphrase=self.kucoin_passphrase, secret_key=self.kucoin_secret_key, time_provider=self._time_synchronizer)