コード例 #1
0
    async def cancel_all(self, timeout_seconds: float):
        """
        Cancels all in-flight orders and waits for cancellation results.
        Used by bot's top level stop and exit commands (cancelling outstanding orders on exit)
        :param timeout_seconds: The timeout at which the operation will be canceled.
        :returns List of CancellationResult which indicates whether each order is successfully cancelled.
        """
        incomplete_orders = [o for o in self._in_flight_orders.values() if not o.is_done]
        tasks = [self._execute_cancel(o.trading_pair, o.client_order_id, True) for o in incomplete_orders]
        order_id_set = set([o.client_order_id for o in incomplete_orders])
        successful_cancellations = []
        try:
            async with timeout(timeout_seconds):
                results = await safe_gather(*tasks, return_exceptions=True)
                for result in results:
                    if result is not None and not isinstance(result, Exception):
                        order_id_set.remove(result)
                        successful_cancellations.append(CancellationResult(result, True))
        except Exception:
            self.logger().error("Cancel all failed.", exc_info=True)
            self.logger().network(
                "Unexpected error cancelling orders.",
                exc_info=True,
                app_warning_msg="Failed to cancel order on Probit. Check API key and network connection."
            )

        failed_cancellations = [CancellationResult(oid, False) for oid in order_id_set]
        return successful_cancellations + failed_cancellations
コード例 #2
0
    async def cancel_all(self, timeout_seconds: float) -> List[CancellationResult]:
        """
        Cancels all currently active orders. The cancellations are performed in parallel tasks.

        :param timeout_seconds: the maximum time (in seconds) the cancel logic should run

        :return: a list of CancellationResult instances, one for each of the orders to be cancelled
        """
        incomplete_orders = [o for o in self.in_flight_orders.values() if not o.is_done]
        tasks = [self._execute_cancel(o.trading_pair, o.client_order_id) for o in incomplete_orders]
        order_id_set = set([o.client_order_id for o in incomplete_orders])
        successful_cancellations = []

        try:
            async with timeout(timeout_seconds):
                cancellation_results = await safe_gather(*tasks, return_exceptions=True)
                for cr in cancellation_results:
                    if isinstance(cr, Exception):
                        continue
                    if cr is not None:
                        client_order_id = cr
                        order_id_set.remove(client_order_id)
                        successful_cancellations.append(CancellationResult(client_order_id, True))
        except Exception:
            self.logger().network(
                "Unexpected error canceling orders.",
                exc_info=True,
                app_warning_msg="Failed to cancel order. Check API key and network connection."
            )

        failed_cancellations = [CancellationResult(oid, False) for oid in order_id_set]
        return successful_cancellations + failed_cancellations
コード例 #3
0
    async def cancel_all(self, timeout_seconds: float):
        """
        Cancels all in-flight orders and waits for cancellation results.
        Used by bot's top level stop and exit commands (cancelling outstanding orders on exit)
        :param timeout_seconds: The timeout at which the operation will be canceled.
        :returns List of CancellationResult which indicates whether each order is successfully cancelled.
        """
        cancellation_results = []
        try:
            await self._api_request(
                "delete",
                "cash/order/all",
                {},
                True,
                force_auth_path_url="order/all"
            )

            open_orders = await self.get_open_orders()

            for cl_order_id, tracked_order in self._in_flight_orders.copy().items():
                open_order = [o for o in open_orders if o.client_order_id == cl_order_id]
                if not open_order:
                    cancellation_results.append(CancellationResult(cl_order_id, True))
                    self.trigger_event(MarketEvent.OrderCancelled,
                                       OrderCancelledEvent(self.current_timestamp, cl_order_id))
                    self.stop_tracking_order(cl_order_id)
                else:
                    cancellation_results.append(CancellationResult(cl_order_id, False))
        except Exception:
            self.logger().network(
                "Failed to cancel all orders.",
                exc_info=True,
                app_warning_msg="Failed to cancel all orders on AscendEx. Check API key and network connection."
            )
        return cancellation_results
コード例 #4
0
    async def cancel_all(self, timeout_sec: float) -> List[CancellationResult]:
        """
        Cancels all in-flight orders and waits for cancellation results.
        Used by bot's top level stop and exit commands (cancelling outstanding orders on exit)
        :param timeout_sec: The timeout at which the operation will be canceled.
        :returns List of CancellationResult which indicates whether each order is successfully cancelled.
        """

        # Note: NDAX's CancelOrder endpoint simply indicates if the cancel requests has been succesfully received.
        cancellation_results = []
        tracked_orders = self.in_flight_orders
        try:
            for order in tracked_orders.values():
                self.cancel(trading_pair=order.trading_pair,
                            order_id=order.client_order_id)

            open_orders = await self.get_open_orders()

            for client_oid, tracked_order in tracked_orders.items():
                matched_order = [o for o in open_orders if o.client_order_id == client_oid]
                if not matched_order:
                    cancellation_results.append(CancellationResult(client_oid, True))
                    self.trigger_event(MarketEvent.OrderCancelled,
                                       OrderCancelledEvent(self.current_timestamp, client_oid))
                else:
                    cancellation_results.append(CancellationResult(client_oid, False))

        except Exception as ex:
            self.logger().network(
                f"Failed to cancel all orders ({ex})",
                exc_info=True,
                app_warning_msg="Failed to cancel all orders on NDAX. Check API key and network connection."
            )
        return cancellation_results
コード例 #5
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)
コード例 #6
0
    async def _execute_cancel(self, trading_pair: str, order_id: str) -> CancellationResult:
        """
        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 AltMarkets.io)
        :param order_id: The internal order id
        order.last_state to change to CANCELED
        """
        order_state, errors_found = None, {}
        try:
            tracked_order = self._in_flight_orders.get(order_id)
            if tracked_order is None:
                self.logger().warning(f"Failed to cancel order {order_id}. Order not found in inflight orders.")
            elif not tracked_order.is_local:
                if tracked_order.exchange_order_id is None:
                    try:
                        async with timeout(6):
                            await tracked_order.get_exchange_order_id()
                    except Exception:
                        order_state = "reject"
                exchange_order_id = tracked_order.exchange_order_id
                response = await self._api_request("POST",
                                                   Constants.ENDPOINT["ORDER_DELETE"].format(id=exchange_order_id),
                                                   is_auth_required=True,
                                                   limit_id=Constants.RL_ID_ORDER_DELETE)
                if isinstance(response, dict):
                    order_state = response.get("state", None)
        except asyncio.CancelledError:
            raise
        except asyncio.TimeoutError:
            self.logger().info(f"The order {order_id} could not be cancelled due to a timeout."
                               " The action will be retried later.")
            errors_found = {"message": "Timeout during order cancellation"}
        except AltmarketsAPIError as e:
            errors_found = e.error_payload.get('errors', e.error_payload)
            if isinstance(errors_found, dict):
                order_state = errors_found.get("state", None)
            if order_state is None or 'market.order.invaild_id_or_uuid' in errors_found:
                self._order_not_found_records[order_id] = self._order_not_found_records.get(order_id, 0) + 1

        if order_state in Constants.ORDER_STATES['CANCEL_WAIT'] or \
                self._order_not_found_records.get(order_id, 0) >= self.ORDER_NOT_EXIST_CANCEL_COUNT:
            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:
            if not tracked_order or not tracked_order.is_local:
                err_msg = errors_found.get('message', errors_found) if isinstance(errors_found, dict) else errors_found
                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)
コード例 #7
0
    async def cancel_all(self, timeout_seconds: float):
        """
        Cancels all in-flight orders and waits for cancellation results.
        Used by bot's top level stop and exit commands (cancelling outstanding orders on exit)
        :param timeout_seconds: The timeout at which the operation will be canceled.
        :returns List of CancellationResult which indicates whether each order is successfully cancelled.
        """
        if self._trading_pairs is None:
            raise Exception(
                "cancel_all can only be used when trading_pairs are specified."
            )
        tracked_orders: Dict[
            str,
            CryptoComInFlightOrder] = self._in_flight_orders.copy().items()
        cancellation_results = []
        try:
            tasks = []

            for _, order in tracked_orders:
                api_params = {
                    "instrument_name":
                    crypto_com_utils.convert_to_exchange_trading_pair(
                        order.trading_pair),
                    "order_id":
                    order.exchange_order_id,
                }
                tasks.append(
                    self._api_request(method="post",
                                      path_url=CONSTANTS.CANCEL_ORDER_PATH_URL,
                                      params=api_params,
                                      is_auth_required=True))

            await safe_gather(*tasks)

            open_orders = await self.get_open_orders()
            for cl_order_id, tracked_order in tracked_orders:
                open_order = [
                    o for o in open_orders if o.client_order_id == cl_order_id
                ]
                if not open_order:
                    cancellation_results.append(
                        CancellationResult(cl_order_id, True))
                    self.trigger_event(
                        MarketEvent.OrderCancelled,
                        OrderCancelledEvent(self.current_timestamp,
                                            cl_order_id))
                    self.stop_tracking_order(cl_order_id)
                else:
                    cancellation_results.append(
                        CancellationResult(cl_order_id, False))
        except Exception:
            self.logger().network(
                "Failed to cancel all orders.",
                exc_info=True,
                app_warning_msg=
                "Failed to cancel all orders on Crypto.com. Check API key and network connection."
            )
        return cancellation_results
コード例 #8
0
    def test_limit_buy_and_sell_and_cancel_all(self):
        symbol: str = self.base_token_symbol + "-" + self.quote_token_symbol
        current_price: Decimal = self.market.get_price(symbol, True)
        amount = Decimal("0.001")
        expires = int(time.time() + 60 * 3)
        quantized_amount: Decimal = self.market.quantize_order_amount(
            symbol, amount)
        buy_order_id = self.market.buy(symbol=symbol,
                                       amount=amount,
                                       order_type=OrderType.LIMIT,
                                       price=current_price -
                                       Decimal("0.2") * current_price,
                                       expiration_ts=expires)
        [buy_order_opened_event] = self.run_parallel(
            self.market_logger.wait_for(BuyOrderCreatedEvent))
        self.assertEqual(buy_order_id, buy_order_opened_event.order_id)
        self.assertEqual(float(quantized_amount),
                         float(buy_order_opened_event.amount))
        self.assertEqual(
            self.base_token_symbol + "-" + self.quote_token_symbol,
            buy_order_opened_event.symbol)
        self.assertEqual(OrderType.LIMIT, buy_order_opened_event.type)

        # Reset the logs
        self.market_logger.clear()

        current_price: Decimal = self.market.get_price(symbol, False)
        sell_order_id = self.market.sell(symbol=symbol,
                                         amount=amount,
                                         order_type=OrderType.LIMIT,
                                         price=current_price +
                                         Decimal("0.2") * current_price,
                                         expiration_ts=expires)
        [sell_order_opened_event] = self.run_parallel(
            self.market_logger.wait_for(SellOrderCreatedEvent))
        self.assertEqual(sell_order_id, sell_order_opened_event.order_id)
        self.assertEqual(float(quantized_amount),
                         float(sell_order_opened_event.amount))
        self.assertEqual(
            self.base_token_symbol + "-" + self.quote_token_symbol,
            sell_order_opened_event.symbol)
        self.assertEqual(OrderType.LIMIT, sell_order_opened_event.type)

        [cancellation_results, order_cancelled_event] = self.run_parallel(
            self.market.cancel_all(60 * 3),
            self.market_logger.wait_for(OrderCancelledEvent))
        self.assertEqual(cancellation_results[0],
                         CancellationResult(buy_order_id, True))
        self.assertEqual(cancellation_results[1],
                         CancellationResult(sell_order_id, True))

        # Wait for the order book source to also register the cancellation
        self.assertTrue(
            (buy_order_opened_event.order_id == order_cancelled_event.order_id
             or sell_order_opened_event.order_id
             == order_cancelled_event.order_id))
        # Reset the logs
        self.market_logger.clear()
コード例 #9
0
    async def cancel_all(self, timeout_seconds: float):
        """
        Cancels all in-flight orders and waits for cancellation results.
        Used by bot's top level stop and exit commands (cancelling outstanding orders on exit)
        :param timeout_seconds: The timeout at which the operation will be canceled.
        :returns List of CancellationResult which indicates whether each order is successfully cancelled.
        """
        cancellation_results = []
        try:
            tracked_orders: Dict[
                str, AscendExInFlightOrder] = self._in_flight_orders.copy()

            api_params = {
                "orders": [{
                    'id':
                    ascend_ex_utils.uuid32(),
                    "orderId":
                    await order.get_exchange_order_id(),
                    "symbol":
                    ascend_ex_utils.convert_to_exchange_trading_pair(
                        order.trading_pair),
                    "time":
                    int(time.time() * 1e3)
                } for order in tracked_orders.values()]
            }

            await self._api_request(method="delete",
                                    path_url=CONSTANTS.ORDER_BATCH_PATH_URL,
                                    data=api_params,
                                    is_auth_required=True,
                                    force_auth_path_url="order/batch")

            open_orders = await self.get_open_orders()

            for cl_order_id, tracked_order in tracked_orders.items():
                open_order = [
                    o for o in open_orders if o.client_order_id == cl_order_id
                ]
                if not open_order:
                    cancellation_results.append(
                        CancellationResult(cl_order_id, True))
                    self.trigger_event(
                        MarketEvent.OrderCancelled,
                        OrderCancelledEvent(self.current_timestamp,
                                            cl_order_id))
                    self.stop_tracking_order(cl_order_id)
                else:
                    cancellation_results.append(
                        CancellationResult(cl_order_id, False))
        except Exception:
            self.logger().network(
                "Failed to cancel all orders.",
                exc_info=True,
                app_warning_msg=
                "Failed to cancel all orders on AscendEx. Check API key and network connection."
            )
        return cancellation_results
コード例 #10
0
    async def _execute_cancel(self, trading_pair: str, order_id: str) -> CancellationResult:
        """
        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 CoinZoom)
        :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 not tracked_order.is_local:
                if tracked_order.exchange_order_id is None:
                    await tracked_order.get_exchange_order_id()
                ex_order_id = tracked_order.exchange_order_id
                api_params = {
                    "orderId": ex_order_id,
                    "symbol": convert_to_exchange_trading_pair(trading_pair)
                }
                await self._api_request("POST",
                                        Constants.ENDPOINT["ORDER_DELETE"],
                                        api_params,
                                        is_auth_required=True)
                order_was_cancelled = True
        except asyncio.CancelledError:
            raise
        except asyncio.TimeoutError:
            self.logger().info(f"The order {order_id} could not be cancelled due to a timeout."
                               " The action will be retried later.")
            err = {"message": "Timeout during order cancellation"}
        except CoinzoomAPIError as e:
            err = e.error_payload.get('error', e.error_payload)
            self.logger().error(f"Order Cancel API Error: {err}")
            # CoinZoom doesn't report any error if the order wasn't found so we can only handle API failures here.
            self._order_not_found_records[order_id] = self._order_not_found_records.get(order_id, 0) + 1
            if 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:
            if not tracked_order.is_local:
                self.logger().network(
                    f"Failed to cancel order {order_id}: {err.get('message', str(err))}",
                    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)
コード例 #11
0
ファイル: k2_exchange.py プロジェクト: zanglang/hummingbot
    async def cancel_all(self, timeout_seconds: float):
        """
        Cancels all in-flight orders and waits for cancellation results.
        Used by bot's top level stop and exit commands (cancelling outstanding orders on exit)
        :param timeout_seconds: The timeout at which the operation will be canceled.
        :returns List of CancellationResult which indicates whether each order is successfully cancelled.
        """
        if self._trading_pairs is None:
            raise Exception(
                "cancel_all can only be used when trading_pairs are specified."
            )
        cancellation_results = []

        for trading_pair in self._trading_pairs:
            order_ids = [
                await o.get_exchange_order_id()
                for _, o in self.in_flight_orders.items()
                if o.trading_pair == trading_pair
            ]

            api_params = {
                "symbol":
                k2_utils.convert_to_exchange_trading_pair(trading_pair),
                "orderids": ",".join(order_ids)
            }

            try:
                await self._api_request(method="POST",
                                        path_url=constants.CANCEL_ALL_ORDERS,
                                        params=api_params,
                                        is_auth_required=True)
                open_orders = await self.get_open_orders()
                for cl_order_id, tracked_order in self._in_flight_orders.items(
                ):
                    open_order = [
                        o for o in open_orders
                        if o.client_order_id == cl_order_id
                    ]
                    if not open_order:
                        cancellation_results.append(
                            CancellationResult(cl_order_id, True))
                        self.trigger_event(
                            MarketEvent.OrderCancelled,
                            OrderCancelledEvent(self.current_timestamp,
                                                cl_order_id))
                    else:
                        cancellation_results.append(
                            CancellationResult(cl_order_id, False))
            except Exception:
                self.logger().network(
                    "Failed to cancel all orders.",
                    exc_info=True,
                    app_warning_msg=
                    "Failed to cancel all orders on K2. Check API key and network connection."
                )
        return cancellation_results
コード例 #12
0
    async def cancel_all(self, timeout_seconds: float):
        """
        Cancels all in-flight orders and waits for cancellation results.
        Used by bot's top level stop and exit commands (cancelling outstanding orders on exit)
        :param timeout_seconds: The timeout at which the operation will be canceled.
        :returns List of CancellationResult which indicates whether each order is successfully cancelled.
        """
        if self._trading_pairs is None:
            raise Exception(
                "cancel_all can only be used when trading_pairs are specified."
            )
        cancellation_results = []
        try:

            # ProBit does not have cancel_all_order endpoint
            tasks = []
            for tracked_order in self.in_flight_orders.values():
                body_params = {
                    "market_id": tracked_order.trading_pair,
                    "order_id": tracked_order.exchange_order_id
                }
                tasks.append(
                    self._api_request(method="POST",
                                      path_url=CONSTANTS.CANCEL_ORDER_URL,
                                      data=body_params,
                                      is_auth_required=True))

            await safe_gather(*tasks)

            open_orders = await self.get_open_orders()
            for cl_order_id, tracked_order in self._in_flight_orders.items():
                open_order = [
                    o for o in open_orders if o.client_order_id == cl_order_id
                ]
                if not open_order:
                    cancellation_results.append(
                        CancellationResult(cl_order_id, True))
                    self.trigger_event(
                        MarketEvent.OrderCancelled,
                        OrderCancelledEvent(self.current_timestamp,
                                            cl_order_id))
                else:
                    cancellation_results.append(
                        CancellationResult(cl_order_id, False))
        except Exception:
            self.logger().network(
                "Failed to cancel all orders.",
                exc_info=True,
                app_warning_msg=
                "Failed to cancel all orders on ProBit. Check API key and network connection."
            )
        return cancellation_results
    def test_limit_buy_and_sell_and_cancel_all(self):
        trading_pair: str = self.base_token_asset + "-" + self.quote_token_asset
        current_price: Decimal = self.market.get_price(trading_pair, True)
        amount = Decimal("0.001")
        expires = int(time.time() + 60 * 3)
        quantized_amount: Decimal = self.market.quantize_order_amount(trading_pair, amount)
        buy_order_id = self.market.buy(trading_pair=trading_pair,
                                       amount=amount,
                                       order_type=OrderType.LIMIT,
                                       price=current_price - Decimal("0.2") * current_price,
                                       expiration_ts=expires)
        [buy_order_opened_event] = self.run_parallel(self.market_logger.wait_for(BuyOrderCreatedEvent))
        self.assertEqual(buy_order_id, buy_order_opened_event.order_id)
        self.assertEqual(float(quantized_amount), float(buy_order_opened_event.amount))
        self.assertEqual(self.base_token_asset + "-" + self.quote_token_asset, buy_order_opened_event.trading_pair)
        self.assertEqual(OrderType.LIMIT, buy_order_opened_event.type)

        # Reset the logs
        self.market_logger.clear()

        current_price: Decimal = self.market.get_price(trading_pair, False)
        sell_order_id = self.market.sell(trading_pair=trading_pair,
                                         amount=amount,
                                         order_type=OrderType.LIMIT,
                                         price=current_price + Decimal("0.2") * current_price,
                                         expiration_ts=expires)
        [sell_order_opened_event] = self.run_parallel(self.market_logger.wait_for(SellOrderCreatedEvent))
        self.assertEqual(sell_order_id, sell_order_opened_event.order_id)
        self.assertEqual(float(quantized_amount), float(sell_order_opened_event.amount))
        self.assertEqual(self.base_token_asset + "-" + self.quote_token_asset, sell_order_opened_event.trading_pair)
        self.assertEqual(OrderType.LIMIT, sell_order_opened_event.type)

        [cancellation_results, order_cancelled_event] = self.run_parallel(self.market.cancel_all(60 * 3),
                                                                          self.market_logger.wait_for(OrderCancelledEvent))
        is_buy_cancelled = False
        is_sell_cancelled = False
        for cancellation_result in cancellation_results:
            if cancellation_result == CancellationResult(buy_order_id, True):
                is_buy_cancelled = True
            if cancellation_result == CancellationResult(sell_order_id, True):
                is_sell_cancelled = True
        self.assertEqual(is_buy_cancelled, True)
        self.assertEqual(is_sell_cancelled, True)

        # Wait for the order book source to also register the cancellation
        self.assertTrue((buy_order_opened_event.order_id == order_cancelled_event.order_id or
                         sell_order_opened_event.order_id == order_cancelled_event.order_id))
        # Reset the logs
        self.market_logger.clear()
コード例 #14
0
    async def cancel_outdated_orders(
            self, cancel_age: int) -> List[CancellationResult]:
        """
        Iterate through all known orders and cancel them if their age is greater than cancel_age.
        """
        incomplete_orders: List[GatewayInFlightOrder] = []

        # Incomplete Approval Requests
        incomplete_orders.extend(
            [o for o in self.approval_orders if o.is_pending_approval])
        # Incomplete Active Orders
        incomplete_orders.extend([o for o in self.amm_orders if not o.is_done])

        if len(incomplete_orders) < 1:
            return []

        timeout_seconds: float = 30.0
        canceling_id_set: Set[str] = set(
            [o.client_order_id for o in incomplete_orders])
        sent_cancellations: List[CancellationResult] = []

        try:
            async with timeout(timeout_seconds):
                for incomplete_order in incomplete_orders:
                    try:
                        canceling_order_id: Optional[
                            str] = await self._execute_cancel(
                                incomplete_order.client_order_id, cancel_age)
                    except Exception:
                        continue
                    if canceling_order_id is not None:
                        canceling_id_set.remove(canceling_order_id)
                        sent_cancellations.append(
                            CancellationResult(canceling_order_id, True))
        except asyncio.CancelledError:
            raise
        except Exception:
            self.logger().network(
                "Unexpected error cancelling outdated orders.",
                exc_info=True,
                app_warning_msg=
                f"Failed to cancel orders on {self.chain}-{self.network}.")

        skipped_cancellations: List[CancellationResult] = [
            CancellationResult(oid, False) for oid in canceling_id_set
        ]
        return sent_cancellations + skipped_cancellations
コード例 #15
0
    def test_limit_buy_and_sell_and_cancel_all(self):
        symbol: str = "ZRX-WETH"
        current_price: float = self.market.get_price(symbol, True)
        amount: float = 10
        expires = int(time.time() + 60 * 5)
        quantized_amount: Decimal = self.market.quantize_order_amount(
            symbol, amount)
        buy_order_id = self.market.buy(symbol=symbol,
                                       amount=amount,
                                       order_type=OrderType.LIMIT,
                                       price=current_price -
                                       0.2 * current_price,
                                       expiration_ts=expires)
        [buy_order_opened_event] = self.run_parallel(
            self.market_logger.wait_for(BuyOrderCreatedEvent))
        self.assertEqual(buy_order_id, buy_order_opened_event.order_id)
        self.assertEqual(quantized_amount,
                         Decimal(buy_order_opened_event.amount))
        self.assertEqual("ZRX-WETH", buy_order_opened_event.symbol)
        self.assertEqual(OrderType.LIMIT, buy_order_opened_event.type)

        # Reset the logs
        self.market_logger.clear()

        sell_order_id = self.market.sell(symbol=symbol,
                                         amount=amount,
                                         order_type=OrderType.LIMIT,
                                         price=current_price +
                                         0.2 * current_price,
                                         expiration_ts=expires)
        [sell_order_opened_event] = self.run_parallel(
            self.market_logger.wait_for(SellOrderCreatedEvent))
        self.assertEqual(sell_order_id, sell_order_opened_event.order_id)
        self.assertEqual(quantized_amount,
                         Decimal(sell_order_opened_event.amount))
        self.assertEqual("ZRX-WETH", sell_order_opened_event.symbol)
        self.assertEqual(OrderType.LIMIT, sell_order_opened_event.type)

        [cancellation_results
         ] = self.run_parallel(self.market.cancel_all(60 * 5))
        self.assertEqual(cancellation_results[0],
                         CancellationResult(buy_order_id, True))
        self.assertEqual(cancellation_results[1],
                         CancellationResult(sell_order_id, True))
        # Reset the logs
        self.market_logger.clear()
コード例 #16
0
    async def cancel_all(self, timeout_seconds: float):
        """
        Cancels all in-flight orders and waits for cancellation results.
        Used by bot's top level stop and exit commands (cancelling outstanding orders on exit)
        :param timeout_seconds: The timeout at which the operation will be canceled.
        :returns List of CancellationResult which indicates whether each order is successfully cancelled.
        """
        if self._trading_pairs is None:
            raise Exception(
                "cancel_all can only be used when trading_pairs are specified."
            )
        cancellation_results = []
        try:
            # for trading_pair in self._trading_pairs:
            #     await self._global.rest_api.request(
            #         "post",
            #         "private/cancel-all-orders",
            #         {"instrument_name": digifinex_utils.convert_to_exchange_trading_pair(trading_pair)},
            #         True
            #     )

            open_orders = list(self._in_flight_orders.values())
            for o in open_orders:
                await self._execute_cancel(o)

            for cl_order_id, tracked_order in self._in_flight_orders.items():
                open_order = [
                    o for o in open_orders
                    if o.exchange_order_id == tracked_order.exchange_order_id
                ]
                if not open_order:
                    cancellation_results.append(
                        CancellationResult(cl_order_id, True))
                    # self.trigger_event(MarketEvent.OrderCancelled,
                    #                    OrderCancelledEvent(self.current_timestamp, cl_order_id))
                else:
                    cancellation_results.append(
                        CancellationResult(cl_order_id, False))
        except Exception:
            self.logger().network(
                "Failed to cancel all orders.",
                exc_info=True,
                app_warning_msg=
                "Failed to cancel all orders on Digifinex. Check API key and network connection."
            )
        return cancellation_results
コード例 #17
0
    async def cancel_all(self, timeout_seconds: float):
        """
        Cancels all in-flight orders and waits for cancellation results.
        Used by bot's top level stop and exit commands (cancelling outstanding orders on exit)
        :param timeout_seconds: The timeout at which the operation will be canceled.
        :returns List of CancellationResult which indicates whether each order is successfully cancelled.
        """
        order_ids_to_cancel = []
        cancel_payloads = []
        successful_cancellations = []
        failed_cancellations = []

        for order in filter(lambda active_order: not active_order.is_done,
                            self._in_flight_order_tracker.active_orders.values()):
            if order.exchange_order_id is not None:
                cancel_payloads.append({
                    "id": ascend_ex_utils.uuid32(),
                    "orderId": order.exchange_order_id,
                    "symbol": ascend_ex_utils.convert_to_exchange_trading_pair(order.trading_pair),
                    "time": int(time.time() * 1e3),
                })
                order_ids_to_cancel.append(order.client_order_id)
            else:
                failed_cancellations.append(CancellationResult(order.client_order_id, False))

        if cancel_payloads:
            try:
                api_params = {"orders": cancel_payloads}
                await self._api_request(
                    method="delete",
                    path_url=CONSTANTS.ORDER_BATCH_PATH_URL,
                    data=api_params,
                    is_auth_required=True,
                    force_auth_path_url="order/batch",
                )

                successful_cancellations = [CancellationResult(order_id, True) for order_id in order_ids_to_cancel]

            except Exception:
                self.logger().network(
                    "Failed to cancel all orders.",
                    exc_info=True,
                    app_warning_msg="Failed to cancel all orders on AscendEx. Check API key and network connection.",
                )
        return successful_cancellations + failed_cancellations
コード例 #18
0
    async def cancel_outdated_orders(
            self, cancel_age: int) -> List[CancellationResult]:
        """
        Iterate through all known orders and cancel them if their age is greater than cancel_age.
        """
        incomplete_orders: List[GatewayInFlightOrder] = [
            o for o in self._in_flight_orders.values()
            if not (o.is_done or o.is_cancelling)
        ]
        if len(incomplete_orders) < 1:
            return []

        timeout_seconds: float = 30.0
        canceling_id_set: Set[str] = set(
            [o.client_order_id for o in incomplete_orders])
        sent_cancellations: List[CancellationResult] = []

        try:
            async with timeout(timeout_seconds):
                # XXX (martin_kou): We CANNOT perform parallel transactions before the nonce architecture is fixed.
                # See: https://app.shortcut.com/coinalpha/story/24553/nonce-architecture-in-current-amm-trade-and-evm-approve-apis-is-incorrect-and-causes-trouble-with-concurrent-requests
                for incomplete_order in incomplete_orders:
                    try:
                        canceling_order_id: Optional[
                            str] = await self._execute_cancel(
                                incomplete_order.client_order_id, cancel_age)
                    except Exception:
                        continue
                    if canceling_order_id is not None:
                        canceling_id_set.remove(canceling_order_id)
                        sent_cancellations.append(
                            CancellationResult(canceling_order_id, True))
        except asyncio.CancelledError:
            raise
        except Exception:
            self.logger().network(
                "Unexpected error cancelling outdated orders.",
                exc_info=True,
                app_warning_msg=
                f"Failed to cancel orders on {self.chain}-{self.network}.")

        skipped_cancellations: List[CancellationResult] = [
            CancellationResult(oid, False) for oid in canceling_id_set
        ]
        return sent_cancellations + skipped_cancellations
コード例 #19
0
    async def cancel_all(self, timeout_seconds: float) -> List[CancellationResult]:
        orders_by_trading_pair = {}

        for order in self._in_flight_orders.values():
            orders_by_trading_pair[order.trading_pair] = orders_by_trading_pair.get(order.trading_pair, [])
            orders_by_trading_pair[order.trading_pair].append(order)

        if len(orders_by_trading_pair) == 0:
            return []

        for trading_pair in orders_by_trading_pair:
            cancel_order_ids = [o.exchange_order_id for o in orders_by_trading_pair[trading_pair]]
            is_need_loop = True
            while is_need_loop:
                if len(cancel_order_ids) > self.ORDER_LEN_LIMIT:
                    is_need_loop = True
                    this_turn_cancel_order_ids = cancel_order_ids[:self.ORDER_LEN_LIMIT]
                    cancel_order_ids = cancel_order_ids[self.ORDER_LEN_LIMIT:]
                else:
                    this_turn_cancel_order_ids = cancel_order_ids
                    is_need_loop = False
                self.logger().debug(
                    f"cancel_order_ids {this_turn_cancel_order_ids} orders_by_trading_pair[trading_pair]")
                params = {
                    'order_ids': quote(','.join([o for o in this_turn_cancel_order_ids])),
                }

                cancellation_results = []
                try:
                    cancel_all_results = await self._api_request(
                        "DELETE",
                        path_url=CONSTANTS.MEXC_ORDER_CANCEL,
                        params=params,
                        is_auth_required=True
                    )

                    for order_result_client_order_id, order_result_value in cancel_all_results['data'].items():
                        for o in orders_by_trading_pair[trading_pair]:
                            if o.client_order_id == order_result_client_order_id:
                                result_bool = True if order_result_value == "invalid order state" or order_result_value == "success" else False
                                cancellation_results.append(CancellationResult(o.client_order_id, result_bool))
                                if result_bool:
                                    self.trigger_event(self.MARKET_ORDER_CANCELLED_EVENT_TAG,
                                                       OrderCancelledEvent(self.current_timestamp,
                                                                           order_id=o.client_order_id,
                                                                           exchange_order_id=o.exchange_order_id))
                                    self.stop_tracking_order(o.client_order_id)

                except Exception as ex:

                    self.logger().network(
                        f"Failed to cancel all orders: {this_turn_cancel_order_ids}" + repr(ex),
                        exc_info=True,
                        app_warning_msg="Failed to cancel all orders on Mexc. Check API key and network connection."
                    )
        return cancellation_results
コード例 #20
0
    async def cancel_all(self, timeout_seconds: float):
        incomplete_orders = [order for order in self._in_flight_orders.values() if not order.is_done]
        tasks = [self.execute_cancel(order.trading_pair, order.client_order_id) for order in incomplete_orders]
        order_id_set = set([order.client_order_id for order in incomplete_orders])
        successful_cancellations = []

        try:
            async with timeout(timeout_seconds):
                cancellation_results = await safe_gather(*tasks, return_exceptions=True)
                for cancel_result in cancellation_results:
                    # TODO: QUESTION --- SHOULD I CHECK FOR THE BinanceAPIException CONSIDERING WE ARE MOVING AWAY FROM BINANCE-CLIENT?
                    if isinstance(cancel_result, dict) and "clientOrderId" in cancel_result:
                        client_order_id = cancel_result.get("clientOrderId")
                        order_id_set.remove(client_order_id)
                        successful_cancellations.append(CancellationResult(client_order_id, True))
        except Exception:
            self.logger().network(
                "Unexpected error cancelling orders.",
                exc_info=True,
                app_warning_msg="Failed to cancel order with Binance Perpetual. Check API key and network connection."
            )
        failed_cancellations = [CancellationResult(order_id, False) for order_id in order_id_set]
        return successful_cancellations + failed_cancellations
コード例 #21
0
    def test_cancel_all(self):
        self._simulate_trading_rules_initialized()

        self.exchange.start_tracking_order(
            order_side=TradeType.BUY,
            client_order_id="OID1",
            order_type=OrderType.LIMIT,
            created_at=1640001112.223,
            hash="hashcode",
            trading_pair=self.trading_pair,
            price=Decimal(1000),
            amount=Decimal(1),
            leverage=Decimal(1),
            position="position",
        )

        result = self.async_run_with_timeout(self.exchange.cancel_all(
            timeout_seconds=1
        ))

        self.assertEqual(result, [CancellationResult(order_id='OID1', success=True)])
コード例 #22
0
    async def cancel_all(self,
                         timeout_seconds: float) -> List[CancellationResult]:
        cancellation_queue = self._in_flight_orders.copy()
        if len(cancellation_queue) == 0:
            return []

        order_status = {
            o.client_order_id: o.is_done
            for o in cancellation_queue.values()
        }

        def set_cancellation_status(oce: OrderCancelledEvent):
            if oce.order_id in order_status:
                order_status[oce.order_id] = True
                return True
            return False

        cancel_verifier = LatchingEventResponder(set_cancellation_status,
                                                 len(cancellation_queue))
        self.add_listener(ORDER_CANCELLED_EVENT, cancel_verifier)

        for order_id, in_flight in cancellation_queue.items():
            try:
                if order_status[order_id]:
                    cancel_verifier.cancel_one()
                elif not await self.cancel_order(order_id):
                    # this order did not exist on the exchange
                    cancel_verifier.cancel_one()
                    order_status[order_id] = True
            except Exception:
                cancel_verifier.cancel_one()
                order_status[order_id] = True

        await cancel_verifier.wait_for_completion(timeout_seconds)
        self.remove_listener(ORDER_CANCELLED_EVENT, cancel_verifier)

        return [
            CancellationResult(order_id=order_id, success=success)
            for order_id, success in order_status.items()
        ]