diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index c0d7026b2..a6d32d8fe 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -881,7 +881,7 @@ class FreqtradeBot: fully_cancelled = self.update_trade_state(trade, order) - if (order['side'] == 'buy' and ( + if (order['side'] == 'buy' and (order['status'] == 'open' or fully_cancelled) and ( fully_cancelled or self._check_timed_out('buy', order) or strategy_safe_wrapper(self.strategy.check_buy_timeout, @@ -890,7 +890,7 @@ class FreqtradeBot: order=order))): self.handle_cancel_buy(trade, order, constants.CANCEL_REASON['TIMEOUT']) - elif (order['side'] == 'sell' and ( + elif (order['side'] == 'sell' and (order['status'] == 'open' or fully_cancelled) and ( fully_cancelled or self._check_timed_out('sell', order) or strategy_safe_wrapper(self.strategy.check_sell_timeout, diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 5c5785ca3..fb4765b48 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -2407,30 +2407,47 @@ def test_handle_cancel_buy_corder_empty(mocker, default_conf, limit_buy_order, assert cancel_order_mock.call_count == 1 -def test_handle_cancel_sell_limit(mocker, default_conf) -> None: - patch_RPCManager(mocker) +def test_handle_cancel_sell_limit(mocker, default_conf, fee) -> None: + send_msg_mock = patch_RPCManager(mocker) patch_exchange(mocker) cancel_order_mock = MagicMock() mocker.patch.multiple( 'freqtrade.exchange.Exchange', - cancel_order=cancel_order_mock + cancel_order=cancel_order_mock, ) + mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_sell_rate', return_value=0.245441) freqtrade = FreqtradeBot(default_conf) - freqtrade._notify_sell_cancel = MagicMock() - trade = MagicMock() + trade = Trade( + pair='LTC/ETH', + amount=2, + exchange='binance', + open_rate=0.245441, + open_order_id="123456", + open_date=arrow.utcnow().datetime, + fee_open=fee.return_value, + fee_close=fee.return_value, + ) order = {'remaining': 1, 'amount': 1, 'status': "open"} reason = CANCEL_REASON['TIMEOUT'] assert freqtrade.handle_cancel_sell(trade, order, reason) assert cancel_order_mock.call_count == 1 + assert send_msg_mock.call_count == 1 + + send_msg_mock.reset_mock() + order['amount'] = 2 - assert (freqtrade.handle_cancel_sell(trade, order, reason) - == CANCEL_REASON['PARTIALLY_FILLED']) + assert freqtrade.handle_cancel_sell(trade, order, reason) == CANCEL_REASON['PARTIALLY_FILLED'] # Assert cancel_order was not called (callcount remains unchanged) assert cancel_order_mock.call_count == 1 + assert send_msg_mock.call_count == 1 + assert freqtrade.handle_cancel_sell(trade, order, reason) == CANCEL_REASON['PARTIALLY_FILLED'] + # Message should not be iterated again + assert trade.sell_order_status == CANCEL_REASON['PARTIALLY_FILLED'] + assert send_msg_mock.call_count == 1 def test_handle_cancel_sell_cancel_exception(mocker, default_conf) -> None: