From f5a44e4fc440ff4bedeb07617d33928d3017d858 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 23 Jan 2020 19:38:35 +0100 Subject: [PATCH 1/5] open_order_id should be None when handling stoploss orders --- tests/test_freqtradebot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index e0f2ecd3a..a80bb7452 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1165,7 +1165,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 From a83de241e41155dbef49ffd858e994033c5a1cfa Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 23 Jan 2020 19:40:31 +0100 Subject: [PATCH 2/5] Check for closed stoploss-orders first --- freqtrade/freqtradebot.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index e3856e200..5505005ff 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -679,6 +679,16 @@ 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 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): @@ -699,16 +709,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 From ea5ac1efb531058cf4ed67ba4fccd4306cad8af5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 23 Jan 2020 20:24:23 +0100 Subject: [PATCH 3/5] Don't handle stoploss if there is an open regular order --- freqtrade/freqtradebot.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 5505005ff..c150d1aa9 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -689,8 +689,13 @@ class FreqtradeBot: self._notify_sell(trade, "stoploss") return True + if trade.open_order_id: + # 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. + 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 From 70b9bd9c0e7d2b37a4386f0809af7237a9dada6a Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 23 Jan 2020 20:36:48 +0100 Subject: [PATCH 4/5] Verify if trade is closed before acting on Stoploss_on_exchange --- freqtrade/freqtradebot.py | 3 ++- tests/test_freqtradebot.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index c150d1aa9..9f06cbb67 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -689,9 +689,10 @@ class FreqtradeBot: self._notify_sell(trade, "stoploss") return True - if trade.open_order_id: + 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 diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index a80bb7452..65b5adda5 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_limit', 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 From 72c273aaedc237e70e049a67db4d469faf116c03 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 23 Jan 2020 21:07:11 +0100 Subject: [PATCH 5/5] Add test for closed trade case --- tests/test_freqtradebot.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 65b5adda5..147ad9d7c 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1141,6 +1141,16 @@ def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog, freqtrade.handle_stoploss_on_exchange(trade) assert stoploss_limit.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: