コード例 #1
0
 def test_trading_pair_convertion(self):
     hbot_trading_pair = "BTC-USDT"
     exchange_trading_pair = "BTC_USDT"
     self.assertEqual(
         exchange_trading_pair,
         utils.convert_to_exchange_trading_pair(hbot_trading_pair))
     self.assertEqual(
         hbot_trading_pair,
         utils.convert_from_exchange_trading_pair(exchange_trading_pair))
コード例 #2
0
 def _format_trading_rules(
         self, symbols_details: Dict[str, Any]) -> Dict[str, TradingRule]:
     """
     Converts json API response into a dictionary of trading rules.
     :param symbols_details: The json API response
     :return A dictionary of trading rules.
     Response Example:
     {
         "code": 1000,
         "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
         "message": "OK",
         "data": {
             "symbols": [
                 {
                     "symbol":"GXC_BTC",
                      "symbol_id":1024,
                      "base_currency":"GXC",
                      "quote_currency":"BTC",
                      "quote_increment":"1.00000000",
                      "base_min_size":"1.00000000",
                      "base_max_size":"10000000.00000000",
                      "price_min_precision":6,
                      "price_max_precision":8,
                      "expiration":"NA",
                      "min_buy_amount":"0.00010000",
                      "min_sell_amount":"0.00010000"
                 },
                 ...
             ]
         }
     }
     """
     result = {}
     for rule in symbols_details["data"]["symbols"]:
         try:
             trading_pair = bitmart_utils.convert_from_exchange_trading_pair(
                 rule["symbol"])
             price_decimals = Decimal(str(rule["price_max_precision"]))
             # E.g. a price decimal of 2 means 0.01 incremental.
             price_step = Decimal("1") / Decimal(
                 str(math.pow(10, price_decimals)))
             result[trading_pair] = TradingRule(
                 trading_pair=trading_pair,
                 min_order_size=Decimal(str(rule["base_min_size"])),
                 max_order_size=Decimal(str(rule["base_max_size"])),
                 min_order_value=Decimal(str(rule["min_buy_amount"])),
                 min_base_amount_increment=Decimal(
                     str(rule["quote_increment"])),
                 min_price_increment=price_step)
         except Exception:
             self.logger().error(
                 f"Error parsing the trading pair rule {rule}. Skipping.",
                 exc_info=True)
     return result
コード例 #3
0
    async def get_open_orders(self) -> List[OpenOrder]:
        if self._trading_pairs is None:
            raise Exception("get_open_orders can only be used when trading_pairs are specified.")

        page_len = 100
        responses = []
        for trading_pair in self._trading_pairs:
            page = 1
            while True:
                response = await self._api_request("get", CONSTANTS.GET_OPEN_ORDERS_PATH_URL,
                                                   {"symbol": bitmart_utils.convert_to_exchange_trading_pair(trading_pair),
                                                    "offset": page,
                                                    "limit": page_len,
                                                    "status": "9"},
                                                   "KEYED")
                responses.append(response)
                count = len(response["data"]["orders"])
                if count < page_len:
                    break
                else:
                    page += 1

        for order in self._in_flight_orders.values():
            await order.get_exchange_order_id()

        ret_val = []
        for response in responses:
            for order in response["data"]["orders"]:
                exchange_order_id = str(order["order_id"])
                tracked_orders = list(self._in_flight_orders.values())
                tracked_order = [o for o in tracked_orders if exchange_order_id == o.exchange_order_id]
                if not tracked_order:
                    continue
                tracked_order = tracked_order[0]
                if order["type"] != "limit":
                    raise Exception(f"Unsupported order type {order['type']}")
                ret_val.append(
                    OpenOrder(
                        client_order_id=tracked_order.client_order_id,
                        trading_pair=bitmart_utils.convert_from_exchange_trading_pair(order["symbol"]),
                        price=Decimal(str(order["price"])),
                        amount=Decimal(str(order["size"])),
                        executed_amount=Decimal(str(order["filled_size"])),
                        status=CONSTANTS.ORDER_STATUS[int(order["status"])],
                        order_type=OrderType.LIMIT,
                        is_buy=True if order["side"].lower() == "buy" else False,
                        time=int(order["create_time"]),
                        exchange_order_id=str(order["order_id"])
                    )
                )
        return ret_val
コード例 #4
0
    async def listen_for_order_book_diffs(self, ev_loop: asyncio.BaseEventLoop,
                                          output: asyncio.Queue):
        """
        Listen for orderbook diffs using websocket book channel(all messages are snapshots)
        """
        while True:
            try:
                ws: websockets.WebSocketClientProtocol = await self._create_websocket_connection(
                )

                for trading_pair in self._trading_pairs:
                    params: Dict[str, Any] = {
                        "op":
                        "subscribe",
                        "args": [
                            f"spot/depth400:{bitmart_utils.convert_to_exchange_trading_pair(trading_pair)}"
                        ]
                    }
                    await ws.send(ujson.dumps(params))

                async for raw_msg in self._inner_messages(ws):
                    messages = ujson.loads(raw_msg)
                    if messages is None:
                        continue
                    if "errorCode" in messages or "data" not in messages:
                        # Error/Unrecognized response from "depth400" channel
                        continue

                    for msg in messages["data"]:  # data is a list
                        msg_timestamp: float = float(msg["ms_t"])
                        t_pair = bitmart_utils.convert_from_exchange_trading_pair(
                            msg["symbol"])

                        snapshot_msg: OrderBookMessage = BitmartOrderBook.snapshot_message_from_exchange(
                            msg=msg,
                            timestamp=msg_timestamp,
                            metadata={"trading_pair": t_pair})
                        output.put_nowait(snapshot_msg)
            except asyncio.CancelledError:
                raise
            except Exception:
                self.logger().network(
                    "Unexpected error with WebSocket connection.",
                    exc_info=True,
                    app_warning_msg=
                    "Unexpected error with WebSocket connection. Retrying in 30 seconds. "
                    "Check network connection.")
                await self._sleep(30.0)
            finally:
                await ws.close()
コード例 #5
0
 async def get_last_traded_prices(
         cls, trading_pairs: List[str]) -> Dict[str, float]:
     throttler = cls._get_throttler_instance()
     async with throttler.execute_task(
             CONSTANTS.GET_LAST_TRADING_PRICES_PATH_URL):
         result = {}
         async with aiohttp.ClientSession() as client:
             async with client.get(
                     f"{CONSTANTS.REST_URL}/{CONSTANTS.GET_LAST_TRADING_PRICES_PATH_URL}",
                     timeout=10) as response:
                 response_json = await response.json()
                 for ticker in response_json["data"]["tickers"]:
                     t_pair = bitmart_utils.convert_from_exchange_trading_pair(
                         ticker["symbol"])
                     if t_pair in trading_pairs and ticker["last_price"]:
                         result[t_pair] = float(ticker["last_price"])
         return result
コード例 #6
0
    async def get_last_traded_prices(cls, trading_pairs: List[str]) -> Dict[str, float]:
        throttler = cls._get_throttler_instance()
        async with throttler.execute_task(CONSTANTS.GET_LAST_TRADING_PRICES_PATH_URL):
            result = {}

            request = RESTRequest(
                method=RESTMethod.GET,
                url=f"{CONSTANTS.REST_URL}/{CONSTANTS.GET_LAST_TRADING_PRICES_PATH_URL}",
            )
            rest_assistant = await build_api_factory().get_rest_assistant()
            response = await rest_assistant.call(request=request, timeout=10)

            response_json = await response.json()
            for ticker in response_json["data"]["tickers"]:
                t_pair = convert_from_exchange_trading_pair(ticker["symbol"])
                if t_pair in trading_pairs and ticker["last_price"]:
                    result[t_pair] = float(ticker["last_price"])
            return result
コード例 #7
0
    async def fetch_trading_pairs() -> List[str]:
        throttler = BitmartAPIOrderBookDataSource._get_throttler_instance()
        async with throttler.execute_task(CONSTANTS.GET_TRADING_PAIRS_PATH_URL):

            request = RESTRequest(
                method=RESTMethod.GET,
                url=f"{CONSTANTS.REST_URL}/{CONSTANTS.GET_TRADING_PAIRS_PATH_URL}",
            )
            rest_assistant = await build_api_factory().get_rest_assistant()
            response = await rest_assistant.call(request=request, timeout=10)

            if response.status == 200:
                try:
                    response_json: Dict[str, Any] = await response.json()
                    return [convert_from_exchange_trading_pair(symbol) for symbol in response_json["data"]["symbols"]]
                except Exception:
                    pass
                    # Do nothing if the request fails -- there will be no autocomplete for bitmart trading pairs
            return []
コード例 #8
0
 async def fetch_trading_pairs() -> List[str]:
     throttler = BitmartAPIOrderBookDataSource._get_throttler_instance()
     async with throttler.execute_task(
             CONSTANTS.GET_TRADING_PAIRS_PATH_URL):
         async with aiohttp.ClientSession() as client:
             async with client.get(
                     f"{CONSTANTS.REST_URL}/{CONSTANTS.GET_TRADING_PAIRS_PATH_URL}",
                     timeout=10) as response:
                 if response.status == 200:
                     from hummingbot.connector.exchange.bitmart.bitmart_utils import \
                         convert_from_exchange_trading_pair
                     try:
                         response_json: Dict[str,
                                             Any] = await response.json()
                         return [
                             convert_from_exchange_trading_pair(symbol)
                             for symbol in response_json["data"]["symbols"]
                         ]
                     except Exception:
                         pass
                         # Do nothing if the request fails -- there will be no autocomplete for bitmart trading pairs
                 return []
コード例 #9
0
    async def listen_for_order_book_diffs(self, ev_loop: asyncio.BaseEventLoop, output: asyncio.Queue):
        """
        Listen for orderbook diffs using websocket book channel(all messages are snapshots)
        """
        while True:
            try:
                ws: WSAssistant = await self._api_factory.get_ws_assistant()
                await ws.connect(ws_url=CONSTANTS.WSS_URL,
                                 message_timeout=self.MESSAGE_TIMEOUT,
                                 ping_timeout=self.PING_TIMEOUT)

                for trading_pair in self._trading_pairs:
                    ws_message: WSRequest = WSRequest({
                        "op": "subscribe",
                        "args": [f"spot/depth400:{convert_to_exchange_trading_pair(trading_pair)}"]
                    })
                    await ws.send(ws_message)

                while True:
                    try:
                        async for raw_msg in ws.iter_messages():
                            messages = decompress_ws_message(raw_msg.data)
                            if messages is None:
                                continue

                            messages = ujson.loads(messages)

                            if "errorCode" in messages.keys() or \
                               "data" not in messages.keys() or \
                               "table" not in messages.keys():
                                continue

                            if messages["table"] != "spot/depth5":
                                # Not an order book message
                                continue

                            for msg in messages["data"]:        # data is a list
                                msg_timestamp: float = float(msg["ms_t"])
                                t_pair = convert_from_exchange_trading_pair(msg["symbol"])

                                snapshot_msg: OrderBookMessage = BitmartOrderBook.snapshot_message_from_exchange(
                                    msg=msg,
                                    timestamp=msg_timestamp,
                                    metadata={"trading_pair": t_pair}
                                )
                                output.put_nowait(snapshot_msg)
                        break
                    except asyncio.exceptions.TimeoutError:
                        # Check whether connection is really dead
                        await ws.ping()
            except asyncio.CancelledError:
                raise
            except asyncio.exceptions.TimeoutError:
                self.logger().warning("WebSocket ping timed out. Going to reconnect...")
                await ws.disconnect()
                await asyncio.sleep(30.0)
            except Exception:
                self.logger().network(
                    "Unexpected error with WebSocket connection.",
                    exc_info=True,
                    app_warning_msg="Unexpected error with WebSocket connection. Retrying in 30 seconds. "
                                    "Check network connection."
                )
                await ws.disconnect()
                await self._sleep(30.0)
            finally:
                await ws.disconnect()