From 6f389764701c23ca00f350e3f696bf9e84212fbd Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 16 May 2021 14:15:24 +0200 Subject: [PATCH] Introduce cancel_stoploss_with_result --- freqtrade/exchange/exchange.py | 21 +++++++++++++++++++++ freqtrade/freqtradebot.py | 7 +++++-- tests/test_freqtradebot.py | 3 ++- tests/test_integration.py | 2 +- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 474eabcf3..c0674cd05 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1120,6 +1120,27 @@ class Exchange: return order + def cancel_stoploss_order_with_result(self, order_id: str, pair: str, amount: float) -> Dict: + """ + Cancel stoploss order returning a result. + Creates a fake result if cancel order returns a non-usable result + and fetch_order does not work (certain exchanges don't return cancelled orders) + :param order_id: stoploss-order-id to cancel + :param pair: Pair corresponding to order_id + :param amount: Amount to use for fake response + :return: Result from either cancel_order if usable, or fetch_order + """ + corder = self.cancel_stoploss_order(order_id, pair) + if self.is_cancel_order_result_suitable(corder): + return corder + try: + order = self.fetch_stoploss_order(order_id, pair) + except InvalidOrderException: + logger.warning(f"Could not fetch cancelled stoploss order {order_id}.") + order = {'fee': {}, 'status': 'canceled', 'amount': amount, 'info': {}} + + return order + @retrier(retries=API_FETCH_ORDER_RETRY_COUNT) def fetch_order(self, order_id: str, pair: str) -> Dict: if self._config['dry_run']: diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 4013072c9..9bfc343f6 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -939,7 +939,8 @@ class FreqtradeBot(LoggingMixin): logger.info(f"Cancelling current stoploss on exchange for pair {trade.pair} " f"(orderid:{order['id']}) in order to add another one ...") try: - co = self.exchange.cancel_stoploss_order(order['id'], trade.pair) + co = self.exchange.cancel_stoploss_order_with_result(order['id'], trade.pair, + trade.amount) trade.update_order(co) except InvalidOrderException: logger.exception(f"Could not cancel stoploss order {order['id']} " @@ -1172,7 +1173,9 @@ class FreqtradeBot(LoggingMixin): # First cancelling stoploss on exchange ... if self.strategy.order_types.get('stoploss_on_exchange') and trade.stoploss_order_id: try: - self.exchange.cancel_stoploss_order(trade.stoploss_order_id, trade.pair) + co = self.exchange.cancel_stoploss_order_with_result(trade.stoploss_order_id, + trade.pair, trade.amount) + trade.update_order(co) except InvalidOrderException: logger.exception(f"Could not cancel stoploss order {trade.stoploss_order_id}") diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 785e866ae..df0715111 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1371,7 +1371,8 @@ def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf, fee, c } mocker.patch('freqtrade.exchange.Binance.cancel_stoploss_order', side_effect=InvalidOrderException()) - mocker.patch('freqtrade.exchange.Binance.fetch_stoploss_order', stoploss_order_hanging) + mocker.patch('freqtrade.exchange.Binance.fetch_stoploss_order', + return_value=stoploss_order_hanging) freqtrade.handle_trailing_stoploss_on_exchange(trade, stoploss_order_hanging) assert log_has_re(r"Could not cancel stoploss order abcd for pair ETH/BTC.*", caplog) diff --git a/tests/test_integration.py b/tests/test_integration.py index 217910961..33b3e1140 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -63,7 +63,7 @@ def test_may_execute_sell_stoploss_on_exchange_multi(default_conf, ticker, fee, amount_to_precision=lambda s, x, y: y, price_to_precision=lambda s, x, y: y, fetch_stoploss_order=stoploss_order_mock, - cancel_stoploss_order=cancel_order_mock, + cancel_stoploss_order_with_result=cancel_order_mock, ) mocker.patch.multiple(