async def _subscribe_channels(self, ws: WSAssistant):
     try:
         for pair in self._trading_pairs:
             subscribe_orderbook_request: WSJSONRequest = WSJSONRequest({
                 "type":
                 "subscribe",
                 "channel":
                 self.ORDERBOOK_CHANNEL,
                 "id":
                 pair,
             })
             subscribe_trade_request: WSJSONRequest = WSJSONRequest({
                 "type":
                 "subscribe",
                 "channel":
                 self.TRADE_CHANNEL,
                 "id":
                 pair,
             })
             await ws.send(subscribe_orderbook_request)
             await ws.send(subscribe_trade_request)
         self.logger().info(
             "Subscribed to public orderbook and trade channels...")
     except asyncio.CancelledError:
         raise
     except Exception:
         self.logger().error(
             "Unexpected error occurred subscribing to order book trading and delta streams...",
             exc_info=True)
         raise
    async def _subscribe_channels(self, ws: WSAssistant):
        """
        Subscribes to the trade events and diff orders events through the provided websocket connection.
        :param ws: the websocket assistant used to connect to the exchange
        """
        try:
            trade_params = []
            depth_params = []
            for trading_pair in self._trading_pairs:
                symbol = await self._connector.exchange_symbol_associated_to_pair(
                    trading_pair=trading_pair)
                trade_params.append(f"{symbol.lower()}@trade")
                depth_params.append(f"{symbol.lower()}@depth@100ms")
            payload = {"method": "SUBSCRIBE", "params": trade_params, "id": 1}
            subscribe_trade_request: WSJSONRequest = WSJSONRequest(
                payload=payload)

            payload = {"method": "SUBSCRIBE", "params": depth_params, "id": 2}
            subscribe_orderbook_request: WSJSONRequest = WSJSONRequest(
                payload=payload)

            await ws.send(subscribe_trade_request)
            await ws.send(subscribe_orderbook_request)

            self.logger().info(
                "Subscribed to public order book and trade channels...")
        except asyncio.CancelledError:
            raise
        except Exception:
            self.logger().error(
                "Unexpected error occurred subscribing to order book trading and delta streams...",
                exc_info=True)
            raise
    def test_ws_assistant_authenticates(self, send_mock):
        class Auth(AuthBase):
            async def rest_authenticate(self, request: RESTRequest) -> RESTRequest:
                pass

            async def ws_authenticate(self, request: WSRequest) -> WSRequest:
                request.payload["authenticated"] = True
                return request

        ws_assistant = WSAssistant(connection=self.ws_connection, auth=Auth())
        sent_requests = []
        send_mock.side_effect = lambda r: sent_requests.append(r)
        payload = {"one": 1}
        req = WSJSONRequest(payload)
        auth_req = WSJSONRequest(payload, is_auth_required=True)

        self.async_run_with_timeout(ws_assistant.send(req))
        self.async_run_with_timeout(ws_assistant.send(auth_req))

        sent_request = sent_requests[0]
        auth_sent_request = sent_requests[1]
        expected = {"one": 1}
        auth_expected = {"one": 1, "authenticated": True}

        self.assertEqual(expected, sent_request.payload)
        self.assertEqual(auth_expected, auth_sent_request.payload)
    async def _subscribe_channels(self, ws: WSAssistant):
        try:
            symbols = ",".join([await self._connector.exchange_symbol_associated_to_pair(trading_pair=pair)
                                for pair in self._trading_pairs])

            trades_payload = {
                "id": web_utils.next_message_id(),
                "type": "subscribe",
                "topic": f"/market/match:{symbols}",
                "privateChannel": False,
                "response": False,
            }
            subscribe_trade_request: WSJSONRequest = WSJSONRequest(payload=trades_payload)

            order_book_payload = {
                "id": web_utils.next_message_id(),
                "type": "subscribe",
                "topic": f"/market/level2:{symbols}",
                "privateChannel": False,
                "response": False,
            }
            subscribe_orderbook_request: WSJSONRequest = WSJSONRequest(payload=order_book_payload)

            await ws.send(subscribe_trade_request)
            await ws.send(subscribe_orderbook_request)

            self._last_ws_message_sent_timestamp = self._time()
            self.logger().info("Subscribed to public order book and trade channels...")
        except asyncio.CancelledError:
            raise
        except Exception:
            self.logger().exception("Unexpected error occurred subscribing to order book trading and delta streams...")
            raise
    async def listen_for_user_stream(self, ev_loop: asyncio.BaseEventLoop,
                                     output: asyncio.Queue):
        ws = None
        while True:
            try:
                expires = int(time.time()) + 25
                url = web_utils.wss_url("", self._domain)
                # # establish initial connection to websocket
                ws: WSAssistant = await self._get_ws_assistant()
                await ws.connect(ws_url=url)

                # # send auth request
                API_KEY = self._auth.api_key
                signature = await self._auth.generate_ws_signature(str(expires)
                                                                   )
                auth_payload = {
                    "op": "authKeyExpires",
                    "args": [API_KEY, expires, signature]
                }

                auth_request: WSJSONRequest = WSJSONRequest(
                    payload=auth_payload, is_auth_required=False)
                await ws.send(auth_request)
                # await ws.ping()  # to update last_recv_timestamp

                # # send subscribe
                # position - Updates on your positions
                # order - Live updates on your orders
                # margin - Updates on your current account balance and margin requirements
                # wallet - Bitcoin address balance data, including total deposits & withdrawals
                subscribe_payload = {
                    "op": "subscribe",
                    "args": ["position", "order", "margin", "wallet"]
                }
                subscribe_request: WSJSONRequest = WSJSONRequest(
                    payload=subscribe_payload, is_auth_required=False)
                await ws.send(subscribe_request)

                async for msg in ws.iter_messages():
                    if len(msg.data) > 0:
                        output.put_nowait(msg.data)

            except asyncio.CancelledError:
                raise
            except Exception as e:
                self.logger().error(
                    f"Unexpected error while listening to user stream. Retrying after 5 seconds... "
                    f"Error: {e}",
                    exc_info=True,
                )
            finally:
                # Make sure no background task is leaked.
                ws and await ws.disconnect()
                await self._sleep(5)
示例#6
0
    async def _subscribe_channels(self, websocket_assistant: WSAssistant):
        """
        Subscribes to order events and balance events.

        :param websocket_assistant: the websocket assistant used to connect to the exchange
        """
        try:
            symbols = [
                await self._connector.exchange_symbol_associated_to_pair(
                    trading_pair=trading_pair)
                for trading_pair in self._trading_pairs
            ]

            orders_change_payload = {
                "time": int(self._time()),
                "channel": CONSTANTS.USER_ORDERS_ENDPOINT_NAME,
                "event": "subscribe",
                "payload": symbols
            }
            subscribe_order_change_request: WSJSONRequest = WSJSONRequest(
                payload=orders_change_payload, is_auth_required=True)

            trades_payload = {
                "time": int(self._time()),
                "channel": CONSTANTS.USER_TRADES_ENDPOINT_NAME,
                "event": "subscribe",
                "payload": symbols
            }
            subscribe_trades_request: WSJSONRequest = WSJSONRequest(
                payload=trades_payload, is_auth_required=True)

            balance_payload = {
                "time": int(self._time()),
                "channel": CONSTANTS.USER_BALANCE_ENDPOINT_NAME,
                "event": "subscribe",  # "unsubscribe" for unsubscription
            }
            subscribe_balance_request: WSJSONRequest = WSJSONRequest(
                payload=balance_payload, is_auth_required=True)

            await websocket_assistant.send(subscribe_order_change_request)
            await websocket_assistant.send(subscribe_trades_request)
            await websocket_assistant.send(subscribe_balance_request)

            self.logger().info(
                "Subscribed to private order changes and balance updates channels..."
            )
        except asyncio.CancelledError:
            raise
        except Exception:
            self.logger().exception(
                "Unexpected error occurred subscribing to user streams...")
            raise
    async def _subscribe_channels(self, ws: WSAssistant):
        """
        Subscribes to the trade events and diff orders events through the provided websocket connection.
        :param ws: the websocket assistant used to connect to the exchange
        """
        try:
            for trading_pair in self._trading_pairs:
                symbol = await self.exchange_symbol_associated_to_pair(
                    trading_pair=trading_pair,
                    domain=self._domain,
                    api_factory=self._api_factory,
                    throttler=self._throttler,
                    time_synchronizer=self._time_synchronizer)
                trade_payload = {
                    "topic": "trade",
                    "event": "sub",
                    "symbol": symbol,
                    "params": {
                        "binary": False
                    }
                }
                subscribe_trade_request: WSJSONRequest = WSJSONRequest(
                    payload=trade_payload)

                depth_payload = {
                    "topic": "diffDepth",
                    "event": "sub",
                    "symbol": symbol,
                    "params": {
                        "binary": False
                    }
                }
                subscribe_orderbook_request: WSJSONRequest = WSJSONRequest(
                    payload=depth_payload)

                await ws.send(subscribe_trade_request)
                await ws.send(subscribe_orderbook_request)

                self.logger().info(
                    f"Subscribed to public order book and trade channels of {trading_pair}..."
                )
        except asyncio.CancelledError:
            raise
        except Exception:
            self.logger().error(
                "Unexpected error occurred subscribing to order book trading and delta streams...",
                exc_info=True)
            raise
    async def _connected_websocket_assistant(self) -> WSAssistant:
        """
        Creates an instance of WSAssistant connected to the exchange
        """

        ws: WSAssistant = await self._get_ws_assistant()
        await ws.connect(ws_url=CONSTANTS.WSS_PRIVATE_URL,
                         ping_timeout=CONSTANTS.WS_PING_TIMEOUT)

        payload = {
            "op": "login",
            "args": self._auth.websocket_login_parameters()
        }

        login_request: WSJSONRequest = WSJSONRequest(payload=payload)

        async with self._api_factory.throttler.execute_task(
                limit_id=CONSTANTS.WS_SUBSCRIBE):
            await ws.send(login_request)

        response: WSResponse = await ws.receive()
        message = response.data
        if "errorCode" in message or "error_code" in message or message.get(
                "event") != "login":
            self.logger().error(
                "Error authenticating the private websocket connection")
            raise IOError(
                f"Private websocket connection authentication failed ({message})"
            )

        return ws
 async def _authenticate_connection(self, ws: WSAssistant):
     """
     Sends the authentication message.
     :param ws: the websocket assistant used to connect to the exchange
     """
     auth_message: WSJSONRequest = WSJSONRequest(payload=self._auth.generate_ws_authentication_message())
     await ws.send(auth_message)
示例#10
0
    async def _subscribe_channels(self, ws: WSAssistant):
        """
        Subscribes to the trade events and diff orders events through the provided websocket connection.
        :param ws: the websocket assistant used to connect to the exchange
        """
        try:
            trade_params = []
            depth_params = []
            for trading_pair in self._trading_pairs:
                symbol = await self.convert_to_exchange_trading_pair(
                    hb_trading_pair=trading_pair,
                    domain=self._domain,
                    api_factory=self._api_factory,
                    throttler=self._throttler)
                trade_params.append(f"trade:{symbol}")
                depth_params.append(f"depth:{symbol}")

            payload: Dict[str, str] = {
                "op": "subscribe",
                "args": trade_params + depth_params,
            }
            subscribe_request: WSJSONRequest = WSJSONRequest(payload=payload)

            await ws.send(subscribe_request)

            self.logger().info(
                "Subscribed to public order book and trade channels...")
        except asyncio.CancelledError:
            raise
        except Exception:
            self.logger().error(
                "Unexpected error occurred subscribing to order book trading and delta streams...",
                exc_info=True)
            raise
    def test_send_when_disconnected_raises(self):
        request = WSJSONRequest(payload={"one": 1})

        with self.assertRaises(RuntimeError) as e:
            self.async_run_with_timeout(self.ws_connection.send(request))

        self.assertEqual("WS is not connected.", str(e.exception))
    async def _subscribe_channels(self, websocket_assistant: WSAssistant):
        try:
            symbols = [
                await self._connector.exchange_symbol_associated_to_pair(
                    trading_pair=trading_pair)
                for trading_pair in self._trading_pairs
            ]

            payload = {
                "op":
                "subscribe",
                "args": [
                    f"{CONSTANTS.PRIVATE_ORDER_PROGRESS_CHANNEL_NAME}:{symbol}"
                    for symbol in symbols
                ]
            }
            subscribe_request: WSJSONRequest = WSJSONRequest(payload=payload)

            async with self._api_factory.throttler.execute_task(
                    limit_id=CONSTANTS.WS_SUBSCRIBE):
                await websocket_assistant.send(subscribe_request)
            self.logger().info(
                "Subscribed to private account and orders channels...")
        except asyncio.CancelledError:
            raise
        except Exception:
            self.logger().exception(
                "Unexpected error occurred subscribing to order book trading and delta streams..."
            )
            raise
示例#13
0
    async def _connected_websocket_assistant(self) -> WSAssistant:
        """
        Creates an instance of WSAssistant connected to the exchange
        """

        ws: WSAssistant = await self._get_ws_assistant()
        async with self._api_factory.throttler.execute_task(
                limit_id=CONSTANTS.WS_CONNECTION_LIMIT_ID):
            await ws.connect(
                ws_url=CONSTANTS.OKX_WS_URI_PRIVATE,
                message_timeout=CONSTANTS.SECONDS_TO_WAIT_TO_RECEIVE_MESSAGE)

        payload = {
            "op": "login",
            "args": [self._auth.websocket_login_parameters()]
        }

        login_request: WSJSONRequest = WSJSONRequest(payload=payload)

        async with self._api_factory.throttler.execute_task(
                limit_id=CONSTANTS.WS_LOGIN_LIMIT_ID):
            await ws.send(login_request)

        response: WSResponse = await ws.receive()
        message = response.data
        if message.get("event") != "login":
            self.logger().error(
                "Error authenticating the private websocket connection")
            raise IOError("Private websocket connection authentication failed")

        return ws
    async def listen_for_user_stream(self, output: asyncio.Queue):
        ws = None
        while True:
            try:
                ws: WSAssistant = await self._get_ws_assistant()
                await ws.connect(
                    ws_url=web_utils.websocket_url(domain=self._domain),
                    ping_timeout=CONSTANTS.HEARTBEAT_TIME_INTERVAL)
                await ws.send(WSJSONRequest({}, is_auth_required=True))
                await self._subscribe_channels(ws)
                await ws.ping()  # to update last_recv_timestamp

                async for ws_response in ws.iter_messages():
                    data = ws_response.data
                    event_type = data.get("event")
                    if event_type == "subscribe" and data.get("channel"):
                        self._subscribed_channels.append(data.get("channel"))
                        self.logger().info(
                            f"Subscribed to private channel - {data.get('channel')}..."
                        )
                    elif len(data) > 0:
                        output.put_nowait(data)
            except asyncio.CancelledError:
                raise
            except Exception as e:
                self.logger().error(
                    f"Unexpected error while listening to user stream. Retrying after 5 seconds... "
                    f"Error: {e}",
                    exc_info=True,
                )
            finally:
                # Make sure no background task is leaked.
                ws and await ws.disconnect()
                self._subscribed_channels = []
                await self._sleep(5)
    async def _subscribe_to_order_book_streams(self) -> WSAssistant:
        url = web_utils.wss_url("", self._domain)
        ws: WSAssistant = await self._get_ws_assistant()
        await ws.connect(ws_url=url)

        stream_channels = [
            "trade",
            "orderBookL2",
        ]
        for channel in stream_channels:
            params = []
            for trading_pair in self._trading_pairs:
                symbol = await self.convert_to_exchange_trading_pair(
                    hb_trading_pair=trading_pair,
                    domain=self._domain,
                    throttler=self._throttler)
                params.append(f"{channel}:{symbol}")
            payload = {
                "op": "subscribe",
                "args": params,
            }
            subscribe_request: WSJSONRequest = WSJSONRequest(
                payload=payload, is_auth_required=False)
            await ws.send(subscribe_request)

        return ws
示例#16
0
    def test_no_auth_added_to_wsrequest(self):
        payload = {"param1": "value_param_1"}
        request = WSJSONRequest(payload=payload, is_auth_required=True)

        self.async_run_with_timeout(self.auth.ws_authenticate(request))

        self.assertEqual(payload, request.payload)
示例#17
0
    async def listen_for_user_stream(self, output: asyncio.Queue):
        ws = None
        while True:
            try:
                self.logger().info(f"Connecting to {CONSTANTS.DYDX_WS_URL}")
                ws: WSAssistant = await self._get_ws_assistant()
                await ws.connect(ws_url=CONSTANTS.DYDX_WS_URL,
                                 ping_timeout=self.HEARTBEAT_INTERVAL)

                auth_params = self._dydx_auth.get_ws_auth_params()
                auth_request: WSJSONRequest = WSJSONRequest(auth_params)
                await ws.send(auth_request)
                self.logger().info("Authenticated user stream...")

                async for ws_response in ws.iter_messages():
                    data = ws_response.data
                    if data.get("type", "") in ["subscribed", "channel_data"]:
                        output.put_nowait(data)
            except asyncio.CancelledError:
                raise
            except Exception:
                self.logger().error(
                    "Unexpected error with dydx WebSocket connection. "
                    "Retrying after 30 seconds...",
                    exc_info=True)
            finally:
                # Make sure no background tasks is leaked
                ws and await ws.disconnect()
                await self._sleep(30.0)
示例#18
0
    async def listen_for_user_stream(self, output: asyncio.Queue):
        while True:
            try:
                # Initialize Websocket Connection
                self.logger().info(f"Connecting to {CONSTANTS.WS_PRIVATE_URL}")
                await self._get_ws_assistant()
                await self._ws_assistant.connect(
                    ws_url=CONSTANTS.WS_PRIVATE_URL,
                    ping_timeout=self.HEARTBEAT_INTERVAL)

                await self._authenticate_client()
                await self._subscribe_channels(
                    websocket_assistant=self._ws_assistant)

                async for ws_response in self._ws_assistant.iter_messages():
                    data = ws_response.data
                    if data["action"] == "ping":
                        pong_request = WSJSONRequest(payload={
                            "action": "pong",
                            "data": data["data"]
                        })
                        await self._ws_assistant.send(request=pong_request)
                        continue
                    output.put_nowait(data)

            except asyncio.CancelledError:
                raise
            except Exception:
                self.logger().error(
                    "Unexpected error with Huobi WebSocket connection. "
                    "Retrying after 30 seconds...",
                    exc_info=True)
            finally:
                self._ws_assistant and await self._ws_assistant.disconnect()
                await self._sleep(30.0)
示例#19
0
    async def _subscribe_to_order_book_streams(self) -> WSAssistant:
        url = f"{web_utils.wss_url(CONSTANTS.PUBLIC_WS_ENDPOINT, self._domain)}"
        ws: WSAssistant = await self._api_factory.get_ws_assistant()
        await ws.connect(ws_url=url,
                         ping_timeout=CONSTANTS.HEARTBEAT_TIME_INTERVAL)

        stream_id_channel_pairs = [
            (CONSTANTS.DIFF_STREAM_ID, "@depth"),
            (CONSTANTS.TRADE_STREAM_ID, "@aggTrade"),
            (CONSTANTS.FUNDING_INFO_STREAM_ID, "@markPrice"),
        ]
        for stream_id, channel in stream_id_channel_pairs:
            params = []
            for trading_pair in self._trading_pairs:
                symbol = await self.convert_to_exchange_trading_pair(
                    hb_trading_pair=trading_pair,
                    domain=self._domain,
                    throttler=self._throttler,
                    api_factory=self._api_factory,
                    time_synchronizer=self._time_synchronizer)
                params.append(f"{symbol.lower()}{channel}")
            payload = {
                "method": "SUBSCRIBE",
                "params": params,
                "id": stream_id,
            }
            subscribe_request: WSJSONRequest = WSJSONRequest(payload)
            await ws.send(subscribe_request)

        return ws
    async def listen_for_subscriptions(self):
        ws = None
        while True:
            try:
                ws: WSAssistant = await self._get_ws_assistant()
                await ws.connect(ws_url=CONSTANTS.WS_PUBLIC_URL, ping_timeout=self.HEARTBEAT_INTERVAL)
                await self._subscribe_channels(ws)

                async for ws_response in ws.iter_messages():
                    data = ws_response.data
                    if "subbed" in data:
                        continue
                    if "ping" in data:
                        ping_request = WSJSONRequest(payload={
                            "pong": data["ping"]
                        })
                        await ws.send(request=ping_request)
                    channel = data.get("ch", "")
                    if channel.endswith(self.TRADE_CHANNEL_SUFFIX):
                        self._message_queue[self.TRADE_CHANNEL_SUFFIX].put_nowait(data)
                    if channel.endswith(self.ORDERBOOK_CHANNEL_SUFFIX):
                        self._message_queue[self.ORDERBOOK_CHANNEL_SUFFIX].put_nowait(data)
            except asyncio.CancelledError:
                raise
            except Exception:
                self.logger().error(
                    "Unexpected error occurred when listening to order book streams. Retrying in 5 seconds...",
                    exc_info=True,
                )
                await self._sleep(5.0)
            finally:
                ws and await ws.disconnect()
示例#21
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()
示例#22
0
 async def listen_for_order_book_diffs(self,
                                       ev_loop: asyncio.AbstractEventLoop,
                                       output: asyncio.Queue):
     """
     *required
     Subscribe to diff channel via web socket, and keep the connection open for incoming messages
     :param ev_loop: ev_loop to execute this function in
     :param output: an async queue where the incoming messages are stored
     """
     while True:
         try:
             trading_pairs: List[str] = self._trading_pairs
             ws_assistant = await self._web_assistants_factory.get_ws_assistant(
             )
             await ws_assistant.connect(
                 CONSTANTS.WS_URL,
                 message_timeout=CONSTANTS.WS_MESSAGE_TIMEOUT)
             subscribe_payload = {
                 "type": "subscribe",
                 "product_ids": trading_pairs,
                 "channels": [CONSTANTS.FULL_CHANNEL_NAME]
             }
             subscribe_request = WSJSONRequest(payload=subscribe_payload)
             await ws_assistant.subscribe(subscribe_request)
             async for msg in self._iter_messages(ws_assistant):
                 msg_type: str = msg.get("type", None)
                 if msg_type is None:
                     raise ValueError(
                         f"Coinbase Pro Websocket message does not contain a type - {msg}"
                     )
                 elif msg_type == "error":
                     raise ValueError(
                         f"Coinbase Pro Websocket received error message - {msg['message']}"
                     )
                 elif msg_type in ["open", "match", "change", "done"]:
                     if msg_type == "done" and "price" not in msg:
                         # done messages with no price are completed market orders which can be ignored
                         continue
                     order_book_message: OrderBookMessage = CoinbaseProOrderBook.diff_message_from_exchange(
                         msg)
                     output.put_nowait(order_book_message)
                 elif msg_type in ["received", "activate", "subscriptions"]:
                     # these messages are not needed to track the order book
                     continue
                 else:
                     raise ValueError(
                         f"Unrecognized Coinbase Pro Websocket message received - {msg}"
                     )
         except asyncio.CancelledError:
             raise
         except Exception:
             self.logger().network(
                 "Unexpected error with WebSocket connection.",
                 exc_info=True,
                 app_warning_msg=
                 f"Unexpected error with WebSocket connection."
                 f" Retrying in {CONSTANTS.REST_API_LIMIT_COOLDOWN} seconds."
                 f" Check network connection.")
             await self._sleep(CONSTANTS.WS_RECONNECT_COOLDOWN)
 async def _handle_ping_message(self, ws: aiohttp.ClientWebSocketResponse):
     """
     Responds with pong to a ping message send by a server to keep a websocket connection alive
     """
     async with self._throttler.execute_task(CONSTANTS.PONG_ENDPOINT_NAME):
         payload = {"op": "pong"}
         pong_request: WSJSONRequest = WSJSONRequest(payload)
         await ws.send(pong_request)
    def test_ws_authenticate(self):
        request: WSJSONRequest = WSJSONRequest(
            payload={"TEST": "SOME_TEST_PAYLOAD"},
            throttler_limit_id="TEST_LIMIT_ID",
            is_auth_required=True)

        signed_request: WSJSONRequest = self.async_run_with_timeout(
            self.auth.ws_authenticate(request))

        self.assertEqual(request, signed_request)
示例#25
0
    async def _subscribe_channels(self, ws: WSAssistant):
        """
        Subscribes to the trade events and diff orders events through the provided websocket connection.

        :param ws: the websocket assistant used to connect to the exchange
        """
        try:
            for trading_pair in self._trading_pairs:
                symbol = await self._connector.exchange_symbol_associated_to_pair(
                    trading_pair=trading_pair)

                trades_payload = {
                    "time": int(self._time()),
                    "channel": CONSTANTS.TRADES_ENDPOINT_NAME,
                    "event": "subscribe",
                    "payload": [symbol]
                }
                subscribe_trade_request: WSJSONRequest = WSJSONRequest(
                    payload=trades_payload)

                order_book_payload = {
                    "time": int(self._time()),
                    "channel": CONSTANTS.ORDERS_UPDATE_ENDPOINT_NAME,
                    "event": "subscribe",
                    "payload": [symbol, "100ms"]
                }
                subscribe_orderbook_request: WSJSONRequest = WSJSONRequest(
                    payload=order_book_payload)

                await ws.send(subscribe_trade_request)
                await ws.send(subscribe_orderbook_request)

                self.logger().info(
                    "Subscribed to public order book and trade channels...")
        except asyncio.CancelledError:
            raise
        except Exception:
            self.logger().error(
                "Unexpected error occurred subscribing to order book data streams."
            )
            raise
 async def _subscribe_channels(self, ws: WSAssistant):
     try:
         for trading_pair in self._trading_pairs:
             subscribe_orderbook_request: WSJSONRequest = WSJSONRequest({
                 "sub": f"market.{convert_to_exchange_trading_pair(trading_pair)}.depth.step0",
                 "id": convert_to_exchange_trading_pair(trading_pair)
             })
             subscribe_trade_request: WSJSONRequest = WSJSONRequest({
                 "sub": f"market.{convert_to_exchange_trading_pair(trading_pair)}.trade.detail",
                 "id": convert_to_exchange_trading_pair(trading_pair)
             })
             await ws.send(subscribe_orderbook_request)
             await ws.send(subscribe_trade_request)
         self.logger().info("Subscribed to public orderbook and trade channels...")
     except asyncio.CancelledError:
         raise
     except Exception:
         self.logger().error(
             "Unexpected error occurred subscribing to order book trading and delta streams...", exc_info=True
         )
         raise
    async def _subscribe_channels(self, websocket_assistant: WSAssistant):
        """
        Subscribes to order events and balance events.

        :param ws: the websocket assistant used to connect to the exchange
        """
        try:
            orders_change_payload = {
                "id": web_utils.next_message_id(),
                "type": "subscribe",
                "topic": "/spotMarket/tradeOrders",
                "privateChannel": True,
                "response": False,
            }
            subscribe_order_change_request: WSJSONRequest = WSJSONRequest(
                payload=orders_change_payload)

            balance_payload = {
                "id": web_utils.next_message_id(),
                "type": "subscribe",
                "topic": "/account/balance",
                "privateChannel": True,
                "response": False,
            }
            subscribe_balance_request: WSJSONRequest = WSJSONRequest(
                payload=balance_payload)

            await websocket_assistant.send(subscribe_order_change_request)
            await websocket_assistant.send(subscribe_balance_request)

            self._last_ws_message_sent_timestamp = self._time()
            self.logger().info(
                "Subscribed to private order changes and balance updates channels..."
            )
        except asyncio.CancelledError:
            raise
        except Exception:
            self.logger().exception(
                "Unexpected error occurred subscribing to user streams...")
            raise
    def test_send(self, ws_connect_mock):
        ws_connect_mock.return_value = self.mocking_assistant.create_websocket_mock(
        )
        self.async_run_with_timeout(self.ws_connection.connect(self.ws_url))
        request = WSJSONRequest(payload={"one": 1})

        self.async_run_with_timeout(self.ws_connection.send(request))

        json_msgs = self.mocking_assistant.json_messages_sent_through_websocket(
            ws_connect_mock.return_value)

        self.assertEqual(1, len(json_msgs))
        self.assertEqual(request.payload, json_msgs[0])
    def test_subscribe(self, send_mock):
        sent_requests = []
        send_mock.side_effect = lambda r: sent_requests.append(r)
        payload = {"one": 1}
        request = WSJSONRequest(payload)

        self.async_run_with_timeout(self.ws_assistant.subscribe(request))

        self.assertEqual(1, len(sent_requests))

        sent_request = sent_requests[0]

        self.assertNotEqual(id(request), id(sent_request))  # has been cloned
        self.assertEqual(request, sent_request)
 async def _process_websocket_messages(self, websocket_assistant: WSAssistant):
     while True:
         try:
             seconds_until_next_ping = self._ping_interval - (self._time() - self._last_ws_message_sent_timestamp)
             await asyncio.wait_for(super()._process_websocket_messages(websocket_assistant=websocket_assistant),
                                    timeout=seconds_until_next_ping)
         except asyncio.TimeoutError:
             payload = {
                 "id": web_utils.next_message_id(),
                 "type": "ping",
             }
             ping_request = WSJSONRequest(payload=payload)
             self._last_ws_message_sent_timestamp = self._time()
             await websocket_assistant.send(request=ping_request)