From 114591048c9daa227b31b7990fab6be97e0093af Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 9 Apr 2022 17:17:49 +0200 Subject: [PATCH] Always call custom_sell - also when there's a new enter signal --- docs/strategy-callbacks.md | 4 ++-- freqtrade/strategy/interface.py | 4 ++-- tests/test_freqtradebot.py | 8 +++++++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index 302ffd5fd..bd32f41c3 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -88,11 +88,11 @@ Allows to define custom exit signals, indicating that specified position should For example you could implement a 1:2 risk-reward ROI with `custom_exit()`. -Using custom_exit() signals in place of stoploss though *is not recommended*. It is a inferior method to using `custom_stoploss()` in this regard - which also allows you to keep the stoploss on exchange. +Using `custom_exit()` signals in place of stoploss though *is not recommended*. It is a inferior method to using `custom_stoploss()` in this regard - which also allows you to keep the stoploss on exchange. !!! Note Returning a (none-empty) `string` or `True` from this method is equal to setting exit signal on a candle at specified time. This method is not called when exit signal is set already, or if exit signals are disabled (`use_exit_signal=False`). `string` max length is 64 characters. Exceeding this limit will cause the message to be truncated to 64 characters. - `custom_exit()` will ignore `exit_profit_only`, and will always be called unless `use_exit_signal=False` or if there is an enter signal. + `custom_exit()` will ignore `exit_profit_only`, and will always be called unless `use_exit_signal=False`, even if there is a new enter signal. An example of how we can use different indicators depending on the current profit and also exit trades that were open longer than one day: diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 1c53b2e3e..ebaa6568f 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -881,8 +881,8 @@ class IStrategy(ABC, HyperStrategyMixin): current_rate = rate current_profit = trade.calc_profit_ratio(current_rate) - if self.use_exit_signal and not enter: - if exit_: + if self.use_exit_signal: + if exit_ and not enter: exit_signal = ExitType.EXIT_SIGNAL else: trade_type = "exit_short" if trade.is_short else "sell" diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index e4066413e..3737c7c05 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3663,6 +3663,7 @@ def test_exit_profit_only( }) freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade, enter_short=is_short, enter_long=not is_short) + freqtrade.strategy.custom_exit = MagicMock(return_value=None) if exit_type == ExitType.EXIT_SIGNAL.value: freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) else: @@ -3671,10 +3672,15 @@ def test_exit_profit_only( freqtrade.enter_positions() trade = Trade.query.first() - trade.is_short = is_short + assert trade.is_short == is_short oobj = Order.parse_from_ccxt_object(limit_order[eside], limit_order[eside]['symbol'], eside) trade.update_trade(oobj) freqtrade.wallets.update() + if profit_only: + assert freqtrade.handle_trade(trade) is False + # Custom-exit is called + freqtrade.strategy.custom_exit.call_count == 1 + patch_get_signal(freqtrade, enter_long=False, exit_short=is_short, exit_long=not is_short) assert freqtrade.handle_trade(trade) is handle_first