async def listen_for_order_book_diffs(self, ev_loop: asyncio.BaseEventLoop,
                                          output: asyncio.Queue):
        while True:
            try:
                trading_pairs: List[str] = self._trading_pairs
                async with websockets.connect(Constants.EXCHANGE_WS_URI) as ws:
                    ws: websockets.WebSocketClientProtocol = ws
                    for trading_pair in trading_pairs:
                        subscribe_request: Dict[str, Any] = {
                            "event":
                            "subscribe",
                            "streams": [
                                stream.format(trading_pair=
                                              convert_to_exchange_trading_pair(
                                                  trading_pair))
                                for stream in Constants.WS_OB_SUBSCRIBE_STREAMS
                            ]
                        }
                        await ws.send(json.dumps(subscribe_request))

                    async for raw_msg in self._inner_messages(ws):
                        # Altmarkets's data value for id is a large int too big for ujson to parse
                        msg: Dict[str, Any] = json.loads(raw_msg)
                        if "ping" in raw_msg:
                            await ws.send(
                                f'{{"op":"pong","timestamp": {str(msg["ping"])}}}'
                            )
                        elif "subscribed" in raw_msg:
                            pass
                        elif ".ob-inc" in raw_msg:
                            # msg_key = list(msg.keys())[0]
                            trading_pair = list(msg.keys())[0].split(".")[0]
                            order_book_message: OrderBookMessage = AltmarketsOrderBook.diff_message_from_exchange(
                                msg[f"{trading_pair}.ob-inc"],
                                metadata={"trading_pair": trading_pair})
                            output.put_nowait(order_book_message)
                        elif ".ob-snap" in raw_msg:
                            # msg_key = list(msg.keys())[0]
                            trading_pair = list(msg.keys())[0].split(".")[0]
                            order_book_message: OrderBookMessage = AltmarketsOrderBook.snapshot_message_from_exchange(
                                msg[f"{trading_pair}.ob-snap"],
                                metadata={"trading_pair": trading_pair})
                            output.put_nowait(order_book_message)
                        else:
                            # Debug log output for pub WS messages
                            self.logger().info(
                                f"OB: Unrecognized message received from Altmarkets websocket: {msg}"
                            )
            except asyncio.CancelledError:
                raise
            except Exception:
                self.logger().error(
                    "Unexpected error with WebSocket connection. Retrying after 30 seconds...",
                    exc_info=True)
                await asyncio.sleep(Constants.MESSAGE_TIMEOUT)
 def setUpClass(cls) -> None:
     super().setUpClass()
     cls.ev_loop = asyncio.get_event_loop()
     cls.base_asset = "HBOT"
     cls.quote_asset = "USDT"
     cls.trading_pair = f"{cls.base_asset}-{cls.quote_asset}"
     cls.exchange_trading_pair = convert_to_exchange_trading_pair(
         cls.trading_pair)
     cls.api_key = "testKey"
     cls.api_secret_key = "testSecretKey"
     cls.username = "******"
     cls.throttler = AsyncThrottler(Constants.RATE_LIMITS)
 async def get_last_traded_prices(
         cls, trading_pairs: List[str]) -> Dict[str, float]:
     results = dict()
     # Altmarkets rate limit is 100 https requests per 10 seconds
     random.seed()
     randSleep = (random.randint(1, 9) + random.randint(1, 9)) / 10
     await asyncio.sleep(0.5 + randSleep)
     async with aiohttp.ClientSession() as client:
         resp = await client.get(Constants.EXCHANGE_ROOT_API +
                                 Constants.TICKER_URI)
         resp_json = await resp.json()
         for trading_pair in trading_pairs:
             resp_record = [
                 resp_json[symbol] for symbol in list(resp_json.keys())
                 if symbol == convert_to_exchange_trading_pair(trading_pair)
             ][0]['ticker']
             results[trading_pair] = float(resp_record["last"])
     return results
 async def get_snapshot(client: aiohttp.ClientSession,
                        trading_pair: str) -> Dict[str, Any]:
     # when type is set to "step0", the default value of "depth" is 150
     # params: Dict = {"symbol": trading_pair, "type": "step0"}
     # Altmarkets rate limit is 100 https requests per 10 seconds
     random.seed()
     randSleep = (random.randint(1, 9) + random.randint(1, 9)) / 10
     await asyncio.sleep(0.5 + randSleep)
     async with client.get(
             Constants.EXCHANGE_ROOT_API + Constants.DEPTH_URI.format(
                 trading_pair=convert_to_exchange_trading_pair(
                     trading_pair))) as response:
         response: aiohttp.ClientResponse = response
         if response.status != 200:
             raise IOError(
                 f"Error fetching Altmarkets market snapshot for {trading_pair}. "
                 f"HTTP status is {response.status}.")
         api_data = await response.read()
         data: Dict[str, Any] = json.loads(api_data)
         return data
示例#5
0
    async def _create_order(self, trade_type: TradeType, order_id: str,
                            trading_pair: str, amount: Decimal,
                            order_type: OrderType, price: Decimal):
        """
        Calls create-order API end point to place an order, starts tracking the order and triggers order created event.
        :param trade_type: BUY or SELL
        :param order_id: Internal order id (also called client_order_id)
        :param trading_pair: The market to place order
        :param amount: The order amount (in base token value)
        :param order_type: The order type
        :param price: The order price
        """
        trading_rule = self._trading_rules[trading_pair]

        try:
            amount = self.quantize_order_amount(trading_pair, amount)
            price = self.quantize_order_price(
                trading_pair, s_decimal_0 if math.isnan(price) else price)
            if amount < trading_rule.min_order_size:
                raise ValueError(
                    f"Buy order amount {amount} is lower than the minimum order size "
                    f"{trading_rule.min_order_size}.")
            order_type_str = order_type.name.lower().split("_")[0]
            api_params = {
                "market": convert_to_exchange_trading_pair(trading_pair),
                "side": trade_type.name.lower(),
                "ord_type": order_type_str,
                # "price": f"{price:f}",
                "client_id": order_id,
                "volume": f"{amount:f}",
            }
            if order_type is not OrderType.MARKET:
                api_params['price'] = f"{price:f}"
            # if order_type is OrderType.LIMIT_MAKER:
            #     api_params["postOnly"] = "true"
            self.start_tracking_order(order_id, None, trading_pair, trade_type,
                                      price, amount, order_type)

            order_result = await self._api_request(
                "POST",
                Constants.ENDPOINT["ORDER_CREATE"],
                params=api_params,
                is_auth_required=True,
                limit_id=Constants.RL_ID_ORDER_CREATE,
                disable_retries=True)
            exchange_order_id = str(order_result["id"])
            tracked_order = self._in_flight_orders.get(order_id)
            if tracked_order is not None:
                self.logger().info(
                    f"Created {order_type.name} {trade_type.name} order {order_id} for "
                    f"{amount} {trading_pair}.")
                tracked_order.update_exchange_order_id(exchange_order_id)
            else:
                raise Exception('Order not tracked.')
            if trade_type is TradeType.BUY:
                event_tag = MarketEvent.BuyOrderCreated
                event_cls = BuyOrderCreatedEvent
            else:
                event_tag = MarketEvent.SellOrderCreated
                event_cls = SellOrderCreatedEvent
            self.trigger_event(
                event_tag,
                event_cls(self.current_timestamp, order_type, trading_pair,
                          amount, price, order_id, exchange_order_id))
        except asyncio.CancelledError:
            raise
        except Exception as e:
            if isinstance(e, AltmarketsAPIError):
                error_reason = e.error_payload.get('error', {}).get(
                    'message', e.error_payload.get('errors'))
            else:
                error_reason = e
            if error_reason and "upstream connect error" not in str(
                    error_reason):
                self.stop_tracking_order(order_id)
                self.trigger_event(
                    MarketEvent.OrderFailure,
                    MarketOrderFailureEvent(self.current_timestamp, order_id,
                                            order_type))
            else:
                self._order_not_created_records[order_id] = 0
            self.logger().network(
                f"Error submitting {trade_type.name} {order_type.name} order to {Constants.EXCHANGE_NAME} for "
                f"{amount} {trading_pair} {price} - {error_reason}.",
                exc_info=True,
                app_warning_msg=
                (f"Error submitting order to {Constants.EXCHANGE_NAME} - {error_reason}."
                 ))