diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index fd5af363b..79a4a8ef0 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -693,8 +693,24 @@ class FreqtradeBot: except InvalidOrderException as exception: logger.warning('Unable to fetch stoploss order: %s', exception) + # We check if stoploss order is fulfilled + if stoploss_order and stoploss_order['status'] == 'closed': + trade.sell_reason = SellType.STOPLOSS_ON_EXCHANGE.value + trade.update(stoploss_order) + # Lock pair for one candle to prevent immediate rebuys + self.strategy.lock_pair(trade.pair, + timeframe_to_next_date(self.config['ticker_interval'])) + self._notify_sell(trade, "stoploss") + return True + + if trade.open_order_id or not trade.is_open: + # Trade has an open Buy or Sell order, Stoploss-handling can't happen in this case + # as the Amount on the exchange is tied up in another trade. + # The trade can be closed already (sell-order fill confirmation came in this iteration) + return False + # If buy order is fulfilled but there is no stoploss, we add a stoploss on exchange - if (not trade.open_order_id and not stoploss_order): + if (not stoploss_order): stoploss = self.edge.stoploss(pair=trade.pair) if self.edge else self.strategy.stoploss @@ -713,16 +729,6 @@ class FreqtradeBot: trade.stoploss_order_id = None logger.warning('Stoploss order was cancelled, but unable to recreate one.') - # We check if stoploss order is fulfilled - if stoploss_order and stoploss_order['status'] == 'closed': - trade.sell_reason = SellType.STOPLOSS_ON_EXCHANGE.value - trade.update(stoploss_order) - # Lock pair for one candle to prevent immediate rebuys - self.strategy.lock_pair(trade.pair, - timeframe_to_next_date(self.config['ticker_interval'])) - self._notify_sell(trade, "stoploss") - return True - # Finally we check if stoploss on exchange should be moved up because of trailing. if stoploss_order and self.config.get('trailing_stop', False): # if trailing stoploss is enabled we check if stoploss value has changed diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index a15533afa..5f16894ab 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1127,6 +1127,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog, 'freqtrade.exchange.Exchange.stoploss', side_effect=DependencyException() ) + trade.is_open = True freqtrade.handle_stoploss_on_exchange(trade) assert log_has('Unable to place a stoploss order on exchange.', caplog) assert trade.stoploss_order_id is None @@ -1140,6 +1141,16 @@ def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog, freqtrade.handle_stoploss_on_exchange(trade) assert stoploss.call_count == 1 + # Sixth case: Closed Trade + # Should not create new order + trade.stoploss_order_id = None + trade.is_open = False + stoploss_limit.reset_mock() + mocker.patch('freqtrade.exchange.Exchange.get_order') + mocker.patch('freqtrade.exchange.Exchange.stoploss_limit', stoploss_limit) + assert freqtrade.handle_stoploss_on_exchange(trade) is False + assert stoploss_limit.call_count == 0 + def test_handle_sle_cancel_cant_recreate(mocker, default_conf, fee, caplog, limit_buy_order, limit_sell_order) -> None: @@ -1165,7 +1176,7 @@ def test_handle_sle_cancel_cant_recreate(mocker, default_conf, fee, caplog, freqtrade.enter_positions() trade = Trade.query.first() trade.is_open = True - trade.open_order_id = '12345' + trade.open_order_id = None trade.stoploss_order_id = 100 assert trade