Exemplo n.º 1
0
    async def _update_order_status(self):
        """
        Calls REST API to get status update for each in-flight order.
        """
        last_tick = int(self._last_poll_timestamp /
                        CONSTANTS.UPDATE_ORDER_STATUS_INTERVAL)
        current_tick = (0 if math.isnan(self.current_timestamp) else int(
            self.current_timestamp / CONSTANTS.UPDATE_ORDER_STATUS_INTERVAL))

        if current_tick > last_tick and len(self._in_flight_orders) > 0:
            tracked_orders = list(self._in_flight_orders.values())
            tasks = []
            for tracked_order in tracked_orders:
                try:
                    exchange_order_id = await tracked_order.get_exchange_order_id(
                    )
                except asyncio.TimeoutError:
                    self.logger().network(
                        f"Skipped order status update for {tracked_order.client_order_id} "
                        "- waiting for exchange order id.")
                    continue
                trading_pair = convert_to_exchange_trading_pair(
                    tracked_order.trading_pair)
                tasks.append(
                    self._api_request(
                        "GET",
                        CONSTANTS.ORDER_STATUS_PATH_URL.format(
                            id=exchange_order_id),
                        params={'currency_pair': trading_pair},
                        is_auth_required=True,
                        limit_id=CONSTANTS.ORDER_STATUS_LIMIT_ID))
            self.logger().debug(
                f"Polling for order status updates of {len(tasks)} orders.")
            responses = await safe_gather(*tasks, return_exceptions=True)
            for response, tracked_order in zip(responses, tracked_orders):
                client_order_id = tracked_order.client_order_id
                if isinstance(response, GateIoAPIError):
                    if response.error_label == 'ORDER_NOT_FOUND':
                        self._order_not_found_records[client_order_id] = \
                            self._order_not_found_records.get(client_order_id, 0) + 1
                        if self._order_not_found_records[
                                client_order_id] < self.ORDER_NOT_EXIST_CONFIRMATION_COUNT:
                            # Wait until the order not found error have repeated a few times before actually treating
                            # it as failed. See: https://github.com/CoinAlpha/hummingbot/issues/601
                            continue
                        self.trigger_event(
                            MarketEvent.OrderFailure,
                            MarketOrderFailureEvent(self.current_timestamp,
                                                    client_order_id,
                                                    tracked_order.order_type))
                        self.stop_tracking_order(client_order_id)
                    else:
                        continue
                elif "id" not in response:
                    self.logger().info(
                        f"_update_order_status id not in resp: {response}")
                    continue
                else:
                    self._process_order_message(response)
Exemplo n.º 2
0
 async def _execute_cancel(self, trading_pair: str, order_id: str) -> str:
     """
     Executes order cancellation process by first calling cancel-order API. The API result doesn't confirm whether
     the cancellation is successful, it simply states it receives the request.
     :param trading_pair: The market trading pair (Unused during cancel on Gate.io)
     :param order_id: The internal order id
     order.last_state to change to CANCELED
     """
     order_was_cancelled = False
     try:
         tracked_order = self._in_flight_orders.get(order_id)
         if tracked_order is None:
             raise ValueError(
                 f"Failed to cancel order - {order_id}. Order not found.")
         if tracked_order.exchange_order_id is None:
             await tracked_order.get_exchange_order_id()
         ex_order_id = tracked_order.exchange_order_id
         await self._api_request(
             "DELETE",
             Constants.ENDPOINT["ORDER_DELETE"].format(id=ex_order_id),
             params={
                 'currency_pair':
                 convert_to_exchange_trading_pair(trading_pair)
             },
             is_auth_required=True)
         order_was_cancelled = True
     except asyncio.CancelledError:
         raise
     except (asyncio.TimeoutError, GateIoAPIError) as e:
         if isinstance(e, asyncio.TimeoutError):
             err_msg = 'Order not tracked.'
             err_lbl = 'ORDER_NOT_FOUND'
         else:
             err_msg = e.error_message
             err_lbl = e.error_label
         self._order_not_found_records[
             order_id] = self._order_not_found_records.get(order_id, 0) + 1
         if err_lbl == 'ORDER_NOT_FOUND' and \
                 self._order_not_found_records[order_id] >= self.ORDER_NOT_EXIST_CANCEL_COUNT:
             order_was_cancelled = True
     if order_was_cancelled:
         self.logger().info(
             f"Successfully cancelled order {order_id} on {Constants.EXCHANGE_NAME}."
         )
         self.stop_tracking_order(order_id)
         self.trigger_event(
             MarketEvent.OrderCancelled,
             OrderCancelledEvent(self.current_timestamp, order_id))
         tracked_order.cancelled_event.set()
         return CancellationResult(order_id, True)
     else:
         self.logger().network(
             f"Failed to cancel order {order_id}: {err_msg}",
             exc_info=True,
             app_warning_msg=
             f"Failed to cancel the order {order_id} on {Constants.EXCHANGE_NAME}. "
             f"Check API key and network connection.")
         return CancellationResult(order_id, False)
Exemplo n.º 3
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
        """
        if not order_type.is_limit_type():
            raise Exception(f"Unsupported order type: {order_type}")
        trading_rule = self._trading_rules[trading_pair]

        amount = self.quantize_order_amount(trading_pair, amount)
        price = self.quantize_order_price(trading_pair, price)
        if amount < trading_rule.min_order_size:
            self.logger().warning(
                f"{trade_type.name.title()} order amount {amount} is lower than the minimum order size "
                f"{trading_rule.min_order_size}.")
        else:
            order_type_str = order_type.name.lower().split("_")[0]
            api_params = {
                "text": order_id,
                "currency_pair":
                convert_to_exchange_trading_pair(trading_pair),
                "side": trade_type.name.lower(),
                "type": order_type_str,
                "price": f"{price:f}",
                "amount": f"{amount:f}",
            }
            self.start_tracking_order(order_id, None, trading_pair, trade_type,
                                      price, amount, order_type)
            try:
                order_result = await self._api_request(
                    "POST", CONSTANTS.ORDER_CREATE_PATH_URL, api_params, True)
                if order_result.get('status') in {
                        "cancelled", "expired", "failed"
                }:
                    raise GateIoAPIError({
                        'label': 'ORDER_REJECTED',
                        'message': 'Order rejected.'
                    })
                else:
                    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)
                        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 GateIoAPIError as e:
                error_reason = e.error_message
                self.stop_tracking_order(order_id)
                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}."
                     ))
                self.trigger_event(
                    MarketEvent.OrderFailure,
                    MarketOrderFailureEvent(self.current_timestamp, order_id,
                                            order_type))
Exemplo n.º 4
0
    async def _update_order_status(self):
        """
        Calls REST API to get status update for each in-flight order.
        """

        tracked_orders: List[GateIoInFlightOrder] = list(
            self._in_flight_orders.values())

        order_status_tasks = []
        order_trade_tasks = []

        for tracked_order in tracked_orders:
            try:
                exchange_order_id = await tracked_order.get_exchange_order_id()
            except asyncio.TimeoutError:
                self.logger().network(
                    f"Skipped order status update for {tracked_order.client_order_id} "
                    "- waiting for exchange order id.")
                continue
            trading_pair = convert_to_exchange_trading_pair(
                tracked_order.trading_pair)

            params = {
                "currency_pair": trading_pair,
                "order_id": exchange_order_id
            }
            order_trade_request = GateIORESTRequest(
                method=RESTMethod.GET,
                endpoint=CONSTANTS.MY_TRADES_PATH_URL,
                params=params,
                is_auth_required=True,
                throttler_limit_id=CONSTANTS.MY_TRADES_PATH_URL,
            )
            params = {"currency_pair": trading_pair}
            order_status_request = GateIORESTRequest(
                method=RESTMethod.GET,
                endpoint=CONSTANTS.ORDER_STATUS_PATH_URL.format(
                    id=exchange_order_id),
                params=params,
                is_auth_required=True,
                throttler_limit_id=CONSTANTS.ORDER_STATUS_LIMIT_ID,
            )

            order_status_tasks.append(
                asyncio.create_task(self._api_request(order_status_request)))
            order_trade_tasks.append(
                asyncio.create_task(self._api_request(order_trade_request)))
        self.logger().debug(
            f"Polling for order updates of {len(tracked_orders)} orders.")

        # Process order trades first before processing order statuses
        trade_responses = await safe_gather(*order_trade_tasks,
                                            return_exceptions=True)
        for response, tracked_order in zip(trade_responses, tracked_orders):
            if not isinstance(response, GateIoAPIError):
                if len(response) > 0:
                    for trade_fills in response:
                        self._process_trade_message(
                            trade_fills, tracked_order.client_order_id)
            else:
                self.logger().warning(
                    f"Failed to fetch trade updates for order {tracked_order.client_order_id}. "
                    f"Response: {response}")
                if response.error_label == 'ORDER_NOT_FOUND':
                    self.stop_tracking_order_exceed_not_found_limit(
                        tracked_order=tracked_order)

        status_responses = await safe_gather(*order_status_tasks,
                                             return_exceptions=True)
        for response, tracked_order in zip(status_responses, tracked_orders):
            if not isinstance(response, GateIoAPIError):
                self._process_order_message(response)
            else:
                self.logger().warning(
                    f"Failed to fetch order status updates for order {tracked_order.client_order_id}. "
                    f"Response: {response}")
                if response.error_label == 'ORDER_NOT_FOUND':
                    self.stop_tracking_order_exceed_not_found_limit(
                        tracked_order=tracked_order)