diff --git a/freqtrade/resolvers/strategy_resolver.py b/freqtrade/resolvers/strategy_resolver.py index 7dfa6b0f2..6e1e52cb7 100644 --- a/freqtrade/resolvers/strategy_resolver.py +++ b/freqtrade/resolvers/strategy_resolver.py @@ -220,15 +220,23 @@ class StrategyResolver(IResolver): ) if strategy: - strategy._populate_fun_len = len(getfullargspec(strategy.populate_indicators).args) - strategy._buy_fun_len = len(getfullargspec(strategy.populate_buy_trend).args) - strategy._sell_fun_len = len(getfullargspec(strategy.populate_sell_trend).args) - if any(x == 2 for x in [ - strategy._populate_fun_len, - strategy._buy_fun_len, - strategy._sell_fun_len - ]): - strategy.INTERFACE_VERSION = 1 + if strategy.config.get('trading_mode', TradingMode.SPOT) != TradingMode.SPOT: + # Require new method + if type(strategy).populate_entry_trend == IStrategy.populate_entry_trend: + raise OperationalException("`populate_entry_trend` must be implemented.") + if type(strategy).populate_exit_trend == IStrategy.populate_exit_trend: + raise OperationalException("`populate_exit_trend` must be implemented.") + else: + # TODO: Verify if populate_buy and populate_sell are implemented + strategy._populate_fun_len = len(getfullargspec(strategy.populate_indicators).args) + strategy._buy_fun_len = len(getfullargspec(strategy.populate_buy_trend).args) + strategy._sell_fun_len = len(getfullargspec(strategy.populate_sell_trend).args) + if any(x == 2 for x in [ + strategy._populate_fun_len, + strategy._buy_fun_len, + strategy._sell_fun_len + ]): + strategy.INTERFACE_VERSION = 1 return strategy diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 17233a027..93b017c60 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -177,19 +177,27 @@ class IStrategy(ABC, HyperStrategyMixin): """ return dataframe - @abstractmethod def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ - Based on TA indicators, populates the buy signal for the given dataframe + DEPRECATED - please migrate to populate_entry_trend :param dataframe: DataFrame :param metadata: Additional information, like the currently traded pair :return: DataFrame with buy column """ return dataframe - @abstractmethod + def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + """ + Based on TA indicators, populates the entry signal for the given dataframe + :param dataframe: DataFrame + :param metadata: Additional information, like the currently traded pair + :return: DataFrame with entry columns populated + """ + return self.populate_buy_trend(dataframe, metadata) + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ + DEPRECATED - please migrate to populate_exit_trend Based on TA indicators, populates the sell signal for the given dataframe :param dataframe: DataFrame :param metadata: Additional information, like the currently traded pair @@ -197,6 +205,15 @@ class IStrategy(ABC, HyperStrategyMixin): """ return dataframe + def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + """ + Based on TA indicators, populates the exit signal for the given dataframe + :param dataframe: DataFrame + :param metadata: Additional information, like the currently traded pair + :return: DataFrame with exit columns populated + """ + return self.populate_sell_trend(dataframe, metadata) + def bot_loop_start(self, **kwargs) -> None: """ Called at the start of the bot iteration (one loop). @@ -1072,7 +1089,7 @@ class IStrategy(ABC, HyperStrategyMixin): "the current function headers!", DeprecationWarning) df = self.populate_buy_trend(dataframe) # type: ignore else: - df = self.populate_buy_trend(dataframe, metadata) + df = self.populate_entry_trend(dataframe, metadata) if 'enter_long' not in df.columns: df = df.rename({'buy': 'enter_long', 'buy_tag': 'enter_tag'}, axis='columns') @@ -1094,7 +1111,7 @@ class IStrategy(ABC, HyperStrategyMixin): "the current function headers!", DeprecationWarning) df = self.populate_sell_trend(dataframe) # type: ignore else: - df = self.populate_sell_trend(dataframe, metadata) + df = self.populate_exit_trend(dataframe, metadata) if 'exit_long' not in df.columns: df = df.rename({'sell': 'exit_long'}, axis='columns') return df diff --git a/freqtrade/templates/base_strategy.py.j2 b/freqtrade/templates/base_strategy.py.j2 index 883444a50..ef8f46f5c 100644 --- a/freqtrade/templates/base_strategy.py.j2 +++ b/freqtrade/templates/base_strategy.py.j2 @@ -29,7 +29,7 @@ class {{ strategy }}(IStrategy): You must keep: - the lib in the section "Do not remove these libs" - - the methods: populate_indicators, populate_buy_trend, populate_sell_trend + - the methods: populate_indicators, populate_entry_trend, populate_exit_trend You should keep: - timeframe, minimal_roi, stoploss, trailing_* """ @@ -119,12 +119,12 @@ class {{ strategy }}(IStrategy): return dataframe - def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ - Based on TA indicators, populates the buy signal for the given dataframe - :param dataframe: DataFrame populated with indicators + Based on TA indicators, populates the entry signal for the given dataframe + :param dataframe: DataFrame :param metadata: Additional information, like the currently traded pair - :return: DataFrame with buy column + :return: DataFrame with entry columns populated """ dataframe.loc[ ( @@ -144,12 +144,12 @@ class {{ strategy }}(IStrategy): return dataframe - def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ - Based on TA indicators, populates the sell signal for the given dataframe - :param dataframe: DataFrame populated with indicators + Based on TA indicators, populates the exit signal for the given dataframe + :param dataframe: DataFrame :param metadata: Additional information, like the currently traded pair - :return: DataFrame with buy column + :return: DataFrame with exit columns populated """ dataframe.loc[ ( diff --git a/freqtrade/templates/sample_short_strategy.py b/freqtrade/templates/sample_short_strategy.py index 2b099ee6a..1dfd1df0d 100644 --- a/freqtrade/templates/sample_short_strategy.py +++ b/freqtrade/templates/sample_short_strategy.py @@ -30,7 +30,7 @@ class SampleShortStrategy(IStrategy): You must keep: - the lib in the section "Do not remove these libs" - - the methods: populate_indicators, populate_buy_trend, populate_sell_trend + - the methods: populate_indicators, populate_entry_trend, populate_exit_trend You should keep: - timeframe, minimal_roi, stoploss, trailing_* """ @@ -341,7 +341,7 @@ class SampleShortStrategy(IStrategy): return dataframe - def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Based on TA indicators, populates the buy signal for the given dataframe :param dataframe: DataFrame populated with indicators @@ -361,7 +361,7 @@ class SampleShortStrategy(IStrategy): return dataframe - def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Based on TA indicators, populates the sell signal for the given dataframe :param dataframe: DataFrame populated with indicators diff --git a/freqtrade/templates/sample_strategy.py b/freqtrade/templates/sample_strategy.py index 69da8b414..fe1bd22fb 100644 --- a/freqtrade/templates/sample_strategy.py +++ b/freqtrade/templates/sample_strategy.py @@ -29,7 +29,7 @@ class SampleStrategy(IStrategy): You must keep: - the lib in the section "Do not remove these libs" - - the methods: populate_indicators, populate_buy_trend, populate_sell_trend + - the methods: populate_indicators, populate_entry_trend, populate_exit_trend You should keep: - timeframe, minimal_roi, stoploss, trailing_* """ @@ -342,12 +342,12 @@ class SampleStrategy(IStrategy): return dataframe - def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ - Based on TA indicators, populates the buy signal for the given dataframe - :param dataframe: DataFrame populated with indicators + Based on TA indicators, populates the entry signal for the given dataframe + :param dataframe: DataFrame :param metadata: Additional information, like the currently traded pair - :return: DataFrame with buy column + :return: DataFrame with entry columns populated """ dataframe.loc[ ( @@ -371,12 +371,12 @@ class SampleStrategy(IStrategy): return dataframe - def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ - Based on TA indicators, populates the sell signal for the given dataframe - :param dataframe: DataFrame populated with indicators + Based on TA indicators, populates the exit signal for the given dataframe + :param dataframe: DataFrame :param metadata: Additional information, like the currently traded pair - :return: DataFrame with sell column + :return: DataFrame with exit columns populated """ dataframe.loc[ ( diff --git a/tests/strategy/strats/strategy_test_v3.py b/tests/strategy/strats/strategy_test_v3.py index 7b2c7a99f..168545bbb 100644 --- a/tests/strategy/strats/strategy_test_v3.py +++ b/tests/strategy/strats/strategy_test_v3.py @@ -125,7 +125,7 @@ class StrategyTestV3(IStrategy): return dataframe - def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ ( @@ -147,7 +147,7 @@ class StrategyTestV3(IStrategy): return dataframe - def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ ( ( diff --git a/tests/strategy/test_default_strategy.py b/tests/strategy/test_default_strategy.py index 7eb0faab5..a9d11e52f 100644 --- a/tests/strategy/test_default_strategy.py +++ b/tests/strategy/test_default_strategy.py @@ -13,8 +13,8 @@ def test_strategy_test_v3_structure(): assert hasattr(StrategyTestV3, 'stoploss') assert hasattr(StrategyTestV3, 'timeframe') assert hasattr(StrategyTestV3, 'populate_indicators') - assert hasattr(StrategyTestV3, 'populate_buy_trend') - assert hasattr(StrategyTestV3, 'populate_sell_trend') + assert hasattr(StrategyTestV3, 'populate_entry_trend') + assert hasattr(StrategyTestV3, 'populate_exit_trend') @pytest.mark.parametrize('is_short,side', [