Example #1
0
 async def pre_process(self, request: RESTRequest) -> RESTRequest:
     if request.headers is None:
         request.headers = {}
     request.headers["Content-Type"] = ("application/json" if request.method
                                        == RESTMethod.POST else
                                        "application/x-www-form-urlencoded")
     return request
Example #2
0
    async def rest_authenticate(self, request: RESTRequest) -> RESTRequest:
        if request.method == RESTMethod.POST:
            request.data = self.add_auth_to_params(request.data)
        else:
            request.params = self.add_auth_to_params(request.params)

        request.headers = {"X-MBX-APIKEY": self._api_key}

        return request
    async def rest_authenticate(self, request: RESTRequest) -> RESTRequest:
        payload: Optional[str] = None
        if request.params is not None:
            payload = urlencode(dict(request.params.items()))
            request.params["signature"] = self.generate_signature_from_payload(payload=payload)
        if request.data is not None:
            payload = urlencode(dict(request.data.items()))
            request.data["signature"] = self.generate_signature_from_payload(payload=payload)

        request.headers = {"X-MBX-APIKEY": self._api_key}

        return request
 async def pre_process(self, request: RESTRequest) -> RESTRequest:
     if request.headers is None:
         request.headers = {}
     # Generates generic headers required by AscendEx
     headers_generic = {}
     headers_generic["Accept"] = "application/json"
     headers_generic["Content-Type"] = "application/json"
     # Headers signature to identify user as an HB liquidity provider.
     request.headers = dict(
         list(headers_generic.items()) + list(request.headers.items()) +
         list(get_hb_id_headers().items()))
     return request
 async def rest_authenticate(self, request: RESTRequest) -> RESTRequest:
     """
     Adds the server time and the signature to the request, required for authenticated interactions. It also adds
     the required parameter in the request header.
     :param request: the request to be configured for authenticated interaction
     """
     request.params = self.add_auth_to_params(params=request.params)
     headers = {}
     if request.headers is not None:
         headers.update(request.headers)
     request.headers = headers
     return request
Example #6
0
    async def _api_request(self,
                           method: str,
                           path_url: str,
                           params: Optional[Dict[str, Any]] = None,
                           auth_type: str = None) -> Dict[str, Any]:
        """
        Sends an aiohttp request and waits for a response.
        :param method: The HTTP method, e.g. get or post
        :param path_url: The path url or the API end point
        :param params: Request parameters
        :param auth_type: Type of Authorization header to send in request, from {"SIGNED", "KEYED", None}
        :returns A response in json format.
        """
        params = params or {}
        async with self._throttler.execute_task(path_url):
            url = f"{CONSTANTS.REST_URL}/{path_url}"

            headers = self._bitmart_auth.get_headers(
                bitmart_utils.get_ms_timestamp(), params, auth_type)

            if method == "get":
                request = RESTRequest(method=RESTMethod.GET,
                                      url=url,
                                      headers=headers,
                                      params=params)
                rest_assistant = await self._get_rest_assistant()
                response = await rest_assistant.call(request=request)
            elif method == "post":
                post_json = json.dumps(params)
                request = RESTRequest(method=RESTMethod.POST,
                                      url=url,
                                      headers=headers,
                                      data=post_json)
                rest_assistant = await self._get_rest_assistant()
                response = await rest_assistant.call(request=request)
            else:
                raise NotImplementedError

            try:
                parsed_response = json.loads(await response.text())
            except Exception as e:
                raise IOError(
                    f"Error parsing data from {url}. Error: {str(e)}")
            if response.status != 200:
                raise IOError(
                    f"Error calling {url}. HTTP status is {response.status}. "
                    f"Message: {parsed_response['message']}")
            if int(parsed_response["code"]) != 1000:
                raise IOError(
                    f"{url} API call failed, error message: {parsed_response['message']}"
                )
            return parsed_response
Example #7
0
    async def get_snapshot(
            trading_pair: str,
            limit: int = 1000,
            domain: str = CONSTANTS.DOMAIN,
            throttler: Optional[AsyncThrottler] = None,
            api_factory: WebAssistantsFactory = None
    ) -> Dict[str, Any]:
        ob_source_cls = BinancePerpetualAPIOrderBookDataSource
        try:
            api_factory = api_factory or utils.build_api_factory()
            rest_assistant = await api_factory.get_rest_assistant()

            params = {"symbol": await ob_source_cls.convert_to_exchange_trading_pair(
                hb_trading_pair=trading_pair,
                domain=domain,
                throttler=throttler)}
            if limit != 0:
                params.update({"limit": str(limit)})
            url = utils.rest_url(CONSTANTS.SNAPSHOT_REST_URL, domain)
            throttler = throttler or ob_source_cls._get_throttler_instance()
            async with throttler.execute_task(limit_id=CONSTANTS.SNAPSHOT_REST_URL):
                request = RESTRequest(
                    method=RESTMethod.GET,
                    url=url,
                    params=params,
                )
                response = await rest_assistant.call(request=request)
                if response.status != 200:
                    raise IOError(f"Error fetching Binance market snapshot for {trading_pair}.")
                data: Dict[str, Any] = await response.json()
                return data
        except asyncio.CancelledError:
            raise
        except Exception:
            raise
Example #8
0
    async def _init_trading_pair_symbols(
            cls,
            domain: str = "com",
            api_factory: Optional[WebAssistantsFactory] = None,
            throttler: Optional[AsyncThrottler] = None):
        """
        Initialize mapping of trade symbols in exchange notation to trade symbols in client notation
        """
        mapping = bidict()

        local_api_factory = api_factory or build_api_factory()
        rest_assistant = await local_api_factory.get_rest_assistant()
        local_throttler = throttler or cls._get_throttler_instance()
        url = binance_utils.public_rest_url(
            path_url=CONSTANTS.EXCHANGE_INFO_PATH_URL, domain=domain)
        request = RESTRequest(method=RESTMethod.GET, url=url)

        try:
            async with local_throttler.execute_task(
                    limit_id=CONSTANTS.EXCHANGE_INFO_PATH_URL):
                response: RESTResponse = await rest_assistant.call(
                    request=request)
                if response.status == 200:
                    data = await response.json()
                    for symbol_data in filter(
                            binance_utils.is_exchange_information_valid,
                            data["symbols"]):
                        mapping[symbol_data[
                            "symbol"]] = f"{symbol_data['baseAsset']}-{symbol_data['quoteAsset']}"
        except Exception as ex:
            cls.logger().error(
                f"There was an error requesting exchange info ({str(ex)})")

        cls._trading_pair_symbol_map[domain] = mapping
 async def rest_authenticate(self, request: RESTRequest) -> RESTRequest:
     headers = {}
     if request.headers is not None:
         headers.update(request.headers)
     headers.update(self._get_auth_headers(request))
     request.headers = headers
     return request
Example #10
0
    async def get_all_mid_prices(domain="com") -> Dict[str, Decimal]:
        """
        Returns the mid price of all trading pairs, obtaining the information from the exchange. This functionality is
        required by the market price strategy.
        :param domain: Domain to use for the connection with the exchange (either "com" or "us"). Default value is "com"
        :return: Dictionary with the trading pair as key, and the mid price as value
        """
        local_api_factory = build_api_factory()
        rest_assistant = await local_api_factory.get_rest_assistant()
        throttler = BinanceAPIOrderBookDataSource._get_throttler_instance()

        url = binance_utils.public_rest_url(
            path_url=CONSTANTS.TICKER_PRICE_CHANGE_PATH_URL, domain=domain)
        request = RESTRequest(method=RESTMethod.GET, url=url)

        async with throttler.execute_task(
                limit_id=CONSTANTS.TICKER_PRICE_CHANGE_PATH_URL):
            resp: RESTResponse = await rest_assistant.call(request=request)
            resp_json = await resp.json()

        ret_val = {}
        for record in resp_json:
            try:
                pair = await BinanceAPIOrderBookDataSource.trading_pair_associated_to_exchange_symbol(
                    symbol=record["symbol"], domain=domain)
                ret_val[pair] = ((Decimal(record.get("bidPrice", "0")) +
                                  Decimal(record.get("askPrice", "0"))) /
                                 Decimal("2"))
            except KeyError:
                # Ignore results for pairs that are not tracked
                continue
        return ret_val
Example #11
0
    def test_rest_authenticate(self):
        now = 1234567890.000
        mock_time_provider = MagicMock()
        mock_time_provider.time.return_value = now

        params = {
            "symbol": "LTCBTC",
            "side": "BUY",
            "type": "LIMIT",
            "timeInForce": "GTC",
            "quantity": 1,
            "price": "0.1",
        }
        full_params = copy(params)

        auth = BinanceAuth(api_key=self._api_key, secret_key=self._secret, time_provider=mock_time_provider)
        request = RESTRequest(method=RESTMethod.GET, params=params, is_auth_required=True)
        configured_request = self.async_run_with_timeout(auth.rest_authenticate(request))

        full_params.update({"timestamp": 1234567890000})
        encoded_params = "&".join([f"{key}={value}" for key, value in full_params.items()])
        expected_signature = hmac.new(
            self._secret.encode("utf-8"),
            encoded_params.encode("utf-8"),
            hashlib.sha256).hexdigest()
        self.assertEqual(now * 1e3, configured_request.params["timestamp"])
        self.assertEqual(expected_signature, configured_request.params["signature"])
        self.assertEqual({"X-MBX-APIKEY": self._api_key}, configured_request.headers)
    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)
    async def get_auth_token(self) -> str:
        api_auth: Dict[str, Any] = self._kraken_auth.generate_auth_dict(
            uri=CONSTANTS.GET_TOKEN_PATH_URL)

        url = f"{CONSTANTS.BASE_URL}{CONSTANTS.GET_TOKEN_PATH_URL}"

        request = RESTRequest(method=RESTMethod.POST,
                              url=url,
                              headers=api_auth["headers"],
                              data=api_auth["postDict"])
        rest_assistant = await self._get_rest_assistant()

        async with self._throttler.execute_task(CONSTANTS.GET_TOKEN_PATH_URL):
            response = await rest_assistant.call(request=request, timeout=100)
            if response.status != 200:
                raise IOError(
                    f"Error fetching Kraken user stream listen key. HTTP status is {response.status}."
                )

            try:
                response_json: Dict[str, Any] = await response.json()
            except Exception:
                raise IOError(f"Error parsing data from {url}.")

            err = response_json["error"]
            if "EAPI:Invalid nonce" in err:
                self.logger().error(
                    f"Invalid nonce error from {url}. " +
                    "Please ensure your Kraken API key nonce window is at least 10, "
                    + "and if needed reset your API key.")
                raise IOError({"error": response_json})

            return response_json["result"]["token"]
Example #14
0
    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"])
Example #15
0
    async def get_snapshot(self,
                           trading_pair: str,
                           limit: int = 1000) -> Dict[str, Any]:
        """
        Retrieves a copy of the full order book from the exchange, for a particular trading pair.
        :param trading_pair: the trading pair for which the order book will be retrieved
        :param limit: the depth of the order book to retrieve
        :return: the response from the exchange (JSON dictionary)
        """
        rest_assistant = await self._get_rest_assistant()
        params = {
            "symbol":
            await self.exchange_symbol_associated_to_pair(
                trading_pair=trading_pair,
                domain=self._domain,
                api_factory=self._api_factory,
                throttler=self._throttler)
        }
        if limit != 0:
            params["limit"] = str(limit)

        url = binance_utils.public_rest_url(
            path_url=CONSTANTS.SNAPSHOT_PATH_URL, domain=self._domain)
        request = RESTRequest(method=RESTMethod.GET, url=url, params=params)

        async with self._throttler.execute_task(
                limit_id=CONSTANTS.SNAPSHOT_PATH_URL):
            response: RESTResponse = await rest_assistant.call(request=request)
            if response.status != 200:
                raise IOError(
                    f"Error fetching market snapshot for {trading_pair}. "
                    f"Response: {response}.")
            data = await response.json()

        return data
Example #16
0
    async def get_order_book_data(trading_pair: str) -> Dict[str, any]:
        """
        Get whole orderbook
        """
        throttler = BitmartAPIOrderBookDataSource._get_throttler_instance()
        async with throttler.execute_task(CONSTANTS.GET_ORDER_BOOK_PATH_URL):

            request = RESTRequest(
                method=RESTMethod.GET,
                url=f"{CONSTANTS.REST_URL}/{CONSTANTS.GET_ORDER_BOOK_PATH_URL}?size=200&symbol="
                    f"{convert_to_exchange_trading_pair(trading_pair)}",
            )
            rest_assistant = await build_api_factory().get_rest_assistant()
            response = await rest_assistant.call(request=request, timeout=10)

            if response.status != 200:
                raise IOError(
                    f"Error fetching OrderBook for {trading_pair} at {CONSTANTS.EXCHANGE_NAME}. "
                    f"HTTP status is {response.status}."
                )

            orderbook_data: Dict[str, Any] = await response.json()
            orderbook_data = orderbook_data["data"]

            return orderbook_data
Example #17
0
    async def fetch_trading_pairs(cls,
                                  throttler: Optional[AsyncThrottler] = None
                                  ) -> List[str]:
        throttler = throttler or cls._get_throttler_instance()
        try:
            async with throttler.execute_task(CONSTANTS.ASSET_PAIRS_PATH_URL):
                url = f"{CONSTANTS.BASE_URL}{CONSTANTS.ASSET_PAIRS_PATH_URL}"
                request = RESTRequest(method=RESTMethod.GET, url=url)
                rest_assistant = await build_api_factory(
                    throttler=throttler).get_rest_assistant()
                response = await rest_assistant.call(request, timeout=5)

                if response.status == 200:
                    data: Dict[str, Any] = await response.json()
                    raw_pairs = data.get("result", [])
                    converted_pairs: List[str] = []
                    for pair, details in raw_pairs.items():
                        if "." not in pair:
                            try:
                                wsname = details[
                                    "wsname"]  # pair in format BASE/QUOTE
                                converted_pairs.append(
                                    convert_from_exchange_trading_pair(wsname))
                            except IOError:
                                pass
                    return [item for item in converted_pairs]
        except Exception:
            pass
            # Do nothing if the request fails -- there will be no autocomplete for kraken trading pairs
        return []
Example #18
0
    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&param_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"])
    async def _init_trading_pair_symbols(
            cls,
            api_factory: Optional[WebAssistantsFactory] = None,
            throttler: Optional[AsyncThrottler] = None):
        """
        Initialize mapping of trade symbols in exchange notation to trade symbols in client notation
        """
        mapping = bidict()

        throttler = throttler or cls._get_throttler_instance()
        api_factory = api_factory or build_api_factory(throttler=throttler)
        rest_assistant = await api_factory.get_rest_assistant()

        url = f"{CONSTANTS.REST_URL}/{CONSTANTS.PRODUCTS_PATH_URL}"
        request = RESTRequest(method=RESTMethod.GET, url=url)

        try:
            async with throttler.execute_task(
                    limit_id=CONSTANTS.PRODUCTS_PATH_URL):
                response: RESTResponse = await rest_assistant.call(
                    request=request)
                if response.status == 200:
                    data: Dict[str, Dict[str, Any]] = await response.json()
                    for symbol_data in data["data"]:
                        mapping[symbol_data[
                            "symbol"]] = f"{symbol_data['baseAsset']}-{symbol_data['quoteAsset']}"
        except Exception as ex:
            cls.logger().error(
                f"There was an error requesting exchange info ({str(ex)})")

        cls._trading_pair_symbol_map = mapping
Example #20
0
    async def listen_for_user_stream(self, output: asyncio.Queue):
        """
        *required
        Subscribe to user stream via web socket, and keep the connection open for incoming messages

        :param output: an async queue where the incoming messages are stored
        """

        ws = None
        while True:
            try:
                rest_assistant = await self._api_factory.get_rest_assistant()
                url = f"{CONSTANTS.REST_URL}/{CONSTANTS.INFO_PATH_URL}"
                request = RESTRequest(method=RESTMethod.GET,
                                      url=url,
                                      endpoint_url=CONSTANTS.INFO_PATH_URL,
                                      is_auth_required=True)

                async with self._throttler.execute_task(
                        CONSTANTS.INFO_PATH_URL):
                    response: RESTResponse = await rest_assistant.call(
                        request=request)

                info = await response.json()
                accountGroup = info.get("data").get("accountGroup")
                headers = self._ascend_ex_auth.get_auth_headers(
                    CONSTANTS.STREAM_PATH_URL)
                payload = {
                    "op": CONSTANTS.SUB_ENDPOINT_NAME,
                    "ch": "order:cash"
                }

                ws: WSAssistant = await self._get_ws_assistant()
                url = f"{get_ws_url_private(accountGroup)}/{CONSTANTS.STREAM_PATH_URL}"
                await ws.connect(ws_url=url,
                                 ws_headers=headers,
                                 ping_timeout=self.HEARTBEAT_PING_INTERVAL)

                subscribe_request: WSJSONRequest = WSJSONRequest(payload)
                async with self._throttler.execute_task(
                        CONSTANTS.SUB_ENDPOINT_NAME):
                    await ws.send(subscribe_request)

                async for raw_msg in ws.iter_messages():
                    msg = raw_msg.data
                    if msg is None:
                        continue
                    self._last_recv_time = time.time()
                    output.put_nowait(msg)
            except asyncio.CancelledError:
                raise
            except Exception:
                self.logger().error(
                    "Unexpected error with AscendEx WebSocket connection. "
                    "Retrying after 30 seconds...",
                    exc_info=True)
                await self._sleep(30.0)
            finally:
                ws and await ws.disconnect()
async def api_request(path: str,
                      api_factory: Optional[WebAssistantsFactory] = None,
                      throttler: Optional[AsyncThrottler] = None,
                      time_synchronizer: Optional[TimeSynchronizer] = None,
                      domain: str = CONSTANTS.DEFAULT_DOMAIN,
                      params: Optional[Dict[str, Any]] = None,
                      data: Optional[Dict[str, Any]] = None,
                      method: RESTMethod = RESTMethod.GET,
                      is_auth_required: bool = False,
                      return_err: bool = False,
                      limit_id: Optional[str] = None,
                      timeout: Optional[float] = None,
                      headers: Dict[str, Any] = {}):
    throttler = throttler or create_throttler()
    time_synchronizer = time_synchronizer or TimeSynchronizer()

    # If api_factory is not provided a default one is created
    # The default instance has no authentication capabilities and all authenticated requests will fail
    api_factory = api_factory or build_api_factory(
        throttler=throttler,
        time_synchronizer=time_synchronizer,
        domain=domain,
    )
    rest_assistant = await api_factory.get_rest_assistant()

    local_headers = {"Content-Type": "application/x-www-form-urlencoded"}
    local_headers.update(headers)
    url = rest_url(path, domain=domain)

    request = RESTRequest(method=method,
                          url=url,
                          params=params,
                          data=data,
                          headers=local_headers,
                          is_auth_required=is_auth_required,
                          throttler_limit_id=limit_id if limit_id else path)

    async with throttler.execute_task(limit_id=limit_id if limit_id else path):
        response = await rest_assistant.call(request=request, timeout=timeout)
        if response.status != 200:
            if return_err:
                error_response = await response.json()
                return error_response
            else:
                error_response = await response.text()
                if error_response is not None and "ret_code" in error_response and "ret_msg" in error_response:
                    raise IOError(
                        f"The request to Bybit failed. Error: {error_response}. Request: {request}"
                    )
                else:
                    raise IOError(
                        f"Error executing request {method.name} {path}. "
                        f"HTTP status is {response.status}. "
                        f"Error: {error_response}")

        return await response.json()
Example #22
0
    async def rest_authenticate(self, request: RESTRequest) -> RESTRequest:
        """
        Adds the server time and the signature to the request, required for authenticated interactions. It also adds
        the required parameter in the request header.
        :param request: the request to be configured for authenticated interaction
        """
        if request.method == RESTMethod.POST:
            request.data = self.add_auth_to_params(
                params=json.loads(request.data))
        else:
            request.params = self.add_auth_to_params(params=request.params)

        headers = {}
        if request.headers is not None:
            headers.update(request.headers)
        headers.update(self.header_for_authentication())
        request.headers = headers

        return request
    def test_binance_perpetual_rest_pre_processor_post_request(self):
        request: RESTRequest = RESTRequest(
            method=RESTMethod.POST,
            url="/TEST_URL",
        )

        result_request: RESTRequest = self.async_run_with_timeout(self.pre_processor.pre_process(request))

        self.assertIn("Content-Type", result_request.headers)
        self.assertEqual(result_request.headers["Content-Type"], "application/json")
Example #24
0
 async def rest_auth(self, path_url: str) -> Dict[Any, Any]:
     """REST private GET request"""
     url = web_utils.private_rest_url(path_url=path_url, domain=self.domain)
     headers = {"Content-Type": "application/x-www-form-urlencoded"}
     request = RESTRequest(method=RESTMethod.GET,
                           url=url,
                           headers=headers,
                           is_auth_required=True)
     client = await self.api_factory.get_rest_assistant()
     response: RESTResponse = await client.call(request)
     return await response.json()
Example #25
0
    async def _update_trading_rules(self):
        request = RESTRequest(
            method=RESTMethod.GET,
            url=f"{CONSTANTS.REST_URL}/{CONSTANTS.GET_TRADING_RULES_PATH_URL}",
        )
        rest_assistant = await self._get_rest_assistant()
        response = await rest_assistant.call(request=request)

        symbols_details: Dict[str, Any] = await response.json()
        self._trading_rules.clear()
        self._trading_rules = self._format_trading_rules(symbols_details)
    def test_bitmex_perpetual_rest_pre_processor_non_post_request(self):
        request: RESTRequest = RESTRequest(
            method=RESTMethod.GET,
            url="/TEST_URL",
        )

        result_request: RESTRequest = self.async_run_with_timeout(
            self.pre_processor.pre_process(request))

        self.assertIn("Content-Type", result_request.headers)
        self.assertEqual(result_request.headers["Content-Type"],
                         "application/x-www-form-urlencoded")
Example #27
0
    async def rest_authenticate(self, request: RESTRequest) -> RESTRequest:

        request_params = self.add_auth_to_params(params=request.params)
        if request.method == RESTMethod.POST:
            request.data = payload.JsonPayload(dict(request_params),
                                               dumps=ujson.dumps)
            request.params = None
        else:
            request.params = request_params

        headers = {}
        if request.headers is not None:
            headers.update(request.headers)
        endpoint = str(urlsplit(request.url).path)
        signature = self._generate_signature(method=request.method.name,
                                             endpoint=endpoint,
                                             params=request_params)
        headers.update(self.header_for_authentication(signature))

        request.headers = headers
        return request
Example #28
0
    def test_rest_authenticate_no_parameters_provided(self):
        request: RESTRequest = RESTRequest(method=RESTMethod.GET,
                                           url="/TEST_PATH_URL",
                                           is_auth_required=True)

        signed_request: RESTRequest = self.async_run_with_timeout(
            self.auth.rest_authenticate(request))

        self.assertIn("X-MBX-APIKEY", signed_request.headers)
        self.assertEqual(signed_request.headers["X-MBX-APIKEY"], self.api_key)
        self.assertIsNone(signed_request.params)
        self.assertIsNone(signed_request.data)
    def test_rest_assistant_authenticates(self, mocked_call):
        url = "https://www.test.com/url"
        resp = {"one": 1}
        call_request: Optional[RESTRequest] = None
        auth_header = {"authenticated": True}

        async def register_request_and_return(request: RESTRequest):
            nonlocal call_request
            call_request = request
            return resp

        mocked_call.side_effect = register_request_and_return

        class AuthDummy(AuthBase):
            async def rest_authenticate(self,
                                        request: RESTRequest) -> RESTRequest:
                request.headers = auth_header
                return request

            async def ws_authenticate(self, request: WSRequest) -> WSRequest:
                pass

        connection = RESTConnection(aiohttp.ClientSession())
        assistant = RESTAssistant(connection, auth=AuthDummy())
        req = RESTRequest(method=RESTMethod.GET, url=url)
        auth_req = RESTRequest(method=RESTMethod.GET,
                               url=url,
                               is_auth_required=True)

        self.async_run_with_timeout(assistant.call(req))

        self.assertIsNotNone(call_request)
        self.assertIsNone(call_request.headers)

        self.async_run_with_timeout(assistant.call(auth_req))

        self.assertIsNotNone(call_request)
        self.assertIsNotNone(call_request.headers)
        self.assertEqual(call_request.headers, auth_header)
    async def _get_last_traded_price(cls, trading_pair: str,
                                     throttler: AsyncThrottler) -> float:
        url = (f"{CONSTANTS.BASE_URL}{CONSTANTS.TICKER_PATH_URL}"
               f"?pair={convert_to_exchange_trading_pair(trading_pair)}")

        request = RESTRequest(method=RESTMethod.GET, url=url)
        rest_assistant = await build_api_factory().get_rest_assistant()

        async with throttler.execute_task(CONSTANTS.TICKER_PATH_URL):
            resp = await rest_assistant.call(request)
        resp_json = await resp.json()
        record = list(resp_json["result"].values())[0]
        return float(record["c"][0])