From c946d30596c46c823ad02a738c072594e555f24d Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 30 Sep 2022 16:17:48 +0200 Subject: [PATCH] Add partial cancel message --- freqtrade/freqtradebot.py | 23 ++++++++++++++++++----- tests/test_freqtradebot.py | 16 +++++++++++++++- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 67d734ce2..b98135fa5 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1416,11 +1416,24 @@ class FreqtradeBot(LoggingMixin): minstake = self.exchange.get_min_pair_stake_amount( trade.pair, trade.open_rate, self.strategy.stoploss) # Double-check remaining amount - if filled_val > 0 and minstake and filled_rem_stake < minstake: - logger.warning( - f"Order {trade.open_order_id} for {trade.pair} not cancelled, " - f"as the filled amount of {filled_val} would result in an unexitable trade.") - return False + if filled_val > 0: + reason = constants.CANCEL_REASON['PARTIALLY_FILLED'] + if minstake and filled_rem_stake < minstake: + logger.warning( + f"Order {trade.open_order_id} for {trade.pair} not cancelled, " + f"as the filled amount of {filled_val} would result in an unexitable trade.") + reason = constants.CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN'] + + order_obj = trade.select_order_by_order_id(order['id']) + if not order_obj: + raise DependencyException( + f"Order_obj not found for {order['id']}. This should not have happened.") + self._notify_exit_cancel( + trade, + order_type=self.strategy.order_types['exit'], + reason=reason, order=order_obj, sub_trade=trade.amount != order['amount'] + ) + return False try: co = self.exchange.cancel_order_with_result(trade.open_order_id, trade.pair, diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 0f1a05ab4..415abbc10 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3111,6 +3111,9 @@ def test_handle_cancel_exit_limit(mocker, default_conf_usdt, fee) -> None: cancel_order=cancel_order_mock, ) mocker.patch('freqtrade.exchange.Exchange.get_rate', return_value=0.245441) + mocker.patch('freqtrade.exchange.Exchange.get_min_pair_stake_amount', return_value=0.2) + + mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_order_fee') freqtrade = FreqtradeBot(default_conf_usdt) @@ -3178,7 +3181,9 @@ def test_handle_cancel_exit_limit(mocker, default_conf_usdt, fee) -> None: send_msg_mock.reset_mock() + # Partial exit - below exit threshold order['amount'] = 2 + order['filled'] = 1.9 assert not freqtrade.handle_cancel_exit(trade, order, reason) # Assert cancel_order was not called (callcount remains unchanged) assert cancel_order_mock.call_count == 1 @@ -3188,12 +3193,21 @@ def test_handle_cancel_exit_limit(mocker, default_conf_usdt, fee) -> None: assert not freqtrade.handle_cancel_exit(trade, order, reason) - send_msg_mock.call_args_list[0][0][0]['reason'] = CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN'] + assert (send_msg_mock.call_args_list[0][0][0]['reason'] + == CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN']) # Message should not be iterated again assert trade.exit_order_status == CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN'] assert send_msg_mock.call_count == 1 + send_msg_mock.reset_mock() + + order['filled'] = 1 + assert freqtrade.handle_cancel_exit(trade, order, reason) + assert send_msg_mock.call_count == 1 + assert (send_msg_mock.call_args_list[0][0][0]['reason'] + == CANCEL_REASON['PARTIALLY_FILLED']) + def test_handle_cancel_exit_cancel_exception(mocker, default_conf_usdt) -> None: patch_RPCManager(mocker)