Beispiel #1
0
    def test_convert_to_exchange_trading_pair(self):
        # Test (1) Regular asset
        self.assertEqual(self.trading_pair,
                         convert_to_exchange_trading_pair(self.trading_pair))

        # Test (2) Matching asset
        matching_asset, asset_name = next(iter(NAME_TO_ASSET_MAPPING.items()))

        trading_pair = f"{matching_asset}-{self.quote_asset}"
        expected_trading_pair = f"{asset_name}-{self.quote_asset}"

        self.assertEqual(expected_trading_pair,
                         convert_to_exchange_trading_pair(trading_pair))
Beispiel #2
0
    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
Beispiel #3
0
 async def _collect_and_decode_messages_loop(self, stream_type: StreamType,
                                             task_index: int,
                                             output: asyncio.Queue):
     while True:
         try:
             kucoin_msg_iterator: KucoinWSConnectionIterator = KucoinWSConnectionIterator(
                 stream_type,
                 self._tasks[stream_type][task_index].trading_pairs,
                 self._throttler)
             self._tasks[stream_type][
                 task_index].message_iterator = kucoin_msg_iterator
             async for raw_msg in kucoin_msg_iterator:
                 msg_type: str = raw_msg.get("type", "")
                 if msg_type in {"ack", "welcome", "pong"}:
                     pass
                 elif msg_type == "message":
                     if stream_type == StreamType.Depth:
                         order_book_message: OrderBookMessage = KucoinOrderBook.diff_message_from_exchange(
                             raw_msg)
                     else:
                         trading_pair: str = convert_to_exchange_trading_pair(
                             raw_msg["data"]["symbol"])
                         data = raw_msg["data"]
                         order_book_message: OrderBookMessage = \
                             KucoinOrderBook.trade_message_from_exchange(
                                 data,
                                 metadata={"trading_pair": trading_pair}
                             )
                     output.put_nowait(order_book_message)
                 elif msg_type == "error":
                     self.logger().error(
                         f"WS error message from Kucoin: {raw_msg}")
                 else:
                     self.logger().warning(
                         f"Unrecognized message type from Kucoin: {msg_type}. "
                         f"Message = {raw_msg}.")
         except asyncio.CancelledError:
             raise
         except asyncio.TimeoutError:
             self.logger().error(
                 "Timeout error with WebSocket connection. Retrying after 5 seconds...",
                 exc_info=True)
             await asyncio.sleep(5.0)
         except Exception:
             self.logger().error(
                 "Unexpected exception with WebSocket connection. Retrying after 5 seconds...",
                 exc_info=True)
             await asyncio.sleep(5.0)
         finally:
             if stream_type in self._tasks:
                 if task_index in self._tasks:
                     self._tasks[stream_type][
                         task_index].message_iterator = None
Beispiel #4
0
    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
Beispiel #5
0
 async def update_subscription(
     cls,
     ws: websockets.WebSocketClientProtocol,
     stream_type: StreamType,
     trading_pairs: Set[str],
     subscribe: bool,
     throttler: Optional[AsyncThrottler] = None,
 ):
     trading_pairs = {
         convert_to_exchange_trading_pair(t)
         for t in trading_pairs
     }
     it = iter(trading_pairs)
     trading_pair_chunks: List[Tuple[str]] = list(
         iter(lambda: tuple(islice(it, 100)), ()))
     subscribe_requests: List[Dict[str, Any]] = []
     if stream_type == StreamType.Depth:
         for trading_pair_chunk in trading_pair_chunks:
             market_str: str = ",".join(sorted(trading_pair_chunk))
             subscribe_requests.append({
                 "id":
                 int(time.time()),
                 "type":
                 "subscribe" if subscribe else "unsubscribe",
                 "topic":
                 f"/market/level2:{market_str}",
                 "response":
                 True
             })
     else:
         for trading_pair_chunk in trading_pair_chunks:
             market_str: str = ",".join(sorted(trading_pair_chunk))
             subscribe_requests.append({
                 "id":
                 int(time.time()),
                 "type":
                 "subscribe" if subscribe else "unsubscribe",
                 "topic":
                 f"/market/match:{market_str}",
                 "privateChannel":
                 False,
                 "response":
                 True
             })
     throttler = throttler or cls._get_throttler_instance()
     for i, subscribe_request in enumerate(subscribe_requests):
         async with throttler.execute_task(CONSTANTS.WS_REQUEST_LIMIT_ID):
             await ws.send(json.dumps(subscribe_request))
    async def update_subscription(ws: websockets.WebSocketClientProtocol,
                                  stream_type: StreamType,
                                  trading_pairs: Set[str], subscribe: bool):
        # Kucoin has a limit of 100 subscription per 10 seconds
        trading_pairs = {
            convert_to_exchange_trading_pair(t)
            for t in trading_pairs
        }
        it = iter(trading_pairs)
        trading_pair_chunks: List[Tuple[str]] = list(
            iter(lambda: tuple(islice(it, 100)), ()))
        subscribe_requests: List[Dict[str, Any]] = []
        if stream_type == StreamType.Depth:
            for trading_pair_chunk in trading_pair_chunks:
                market_str: str = ",".join(sorted(trading_pair_chunk))
                subscribe_requests.append({
                    "id":
                    int(time.time()),
                    "type":
                    "subscribe" if subscribe else "unsubscribe",
                    "topic":
                    f"/market/level2:{market_str}",
                    "response":
                    True
                })
        else:
            for trading_pair_chunk in trading_pair_chunks:
                market_str: str = ",".join(sorted(trading_pair_chunk))
                subscribe_requests.append({
                    "id":
                    int(time.time()),
                    "type":
                    "subscribe" if subscribe else "unsubscribe",
                    "topic":
                    f"/market/match:{market_str}",
                    "privateChannel":
                    False,
                    "response":
                    True
                })
        for i, subscribe_request in enumerate(subscribe_requests):
            await ws.send(json.dumps(subscribe_request))
            if i != len(subscribe_requests) - 1:  # only sleep between requests
                await asyncio.sleep(10)

        await asyncio.sleep(0.2)  # watch out for the rate limit
    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
Beispiel #8
0
 async def update_subscription(self, stream_type: StreamType,
                               trading_pairs: Set[str], subscribe: bool):
     trading_pairs = {
         convert_to_exchange_trading_pair(t)
         for t in trading_pairs
     }
     it = iter(trading_pairs)
     trading_pair_chunks: List[Tuple[str]] = list(
         iter(lambda: tuple(islice(it, 100)), ()))
     subscribe_requests: List[Dict[str, Any]] = []
     if stream_type == StreamType.Depth:
         for trading_pair_chunk in trading_pair_chunks:
             market_str: str = ",".join(sorted(trading_pair_chunk))
             subscribe_requests.append({
                 "id":
                 int(time.time()),
                 "type":
                 "subscribe" if subscribe else "unsubscribe",
                 "topic":
                 f"/market/level2:{market_str}",
                 "response":
                 True
             })
     else:
         for trading_pair_chunk in trading_pair_chunks:
             market_str: str = ",".join(sorted(trading_pair_chunk))
             subscribe_requests.append({
                 "id":
                 int(time.time()),
                 "type":
                 "subscribe" if subscribe else "unsubscribe",
                 "topic":
                 f"/market/match:{market_str}",
                 "privateChannel":
                 False,
                 "response":
                 True
             })
     for i, subscribe_request in enumerate(subscribe_requests):
         async with self._throttler.execute_task(
                 CONSTANTS.WS_REQUEST_LIMIT_ID):
             await self._websocket.send_json(subscribe_request)