Update advise_* methods to entry/exit

This commit is contained in:
Matthias 2021-09-22 20:42:31 +02:00
parent 4c6b1cd55b
commit 0e13d57e57
8 changed files with 53 additions and 53 deletions

View File

@ -168,8 +168,8 @@ class Edge:
pair_data = pair_data.sort_values(by=['date']) pair_data = pair_data.sort_values(by=['date'])
pair_data = pair_data.reset_index(drop=True) pair_data = pair_data.reset_index(drop=True)
df_analyzed = self.strategy.advise_sell( df_analyzed = self.strategy.advise_exit(
dataframe=self.strategy.advise_buy( dataframe=self.strategy.advise_entry(
dataframe=pair_data, dataframe=pair_data,
metadata={'pair': pair} metadata={'pair': pair}
), ),

View File

@ -274,8 +274,8 @@ class Backtesting:
pair_data.loc[:, 'long_tag'] = None pair_data.loc[:, 'long_tag'] = None
pair_data.loc[:, 'short_tag'] = None pair_data.loc[:, 'short_tag'] = None
df_analyzed = self.strategy.advise_sell( df_analyzed = self.strategy.advise_exit(
self.strategy.advise_buy(pair_data, {'pair': pair}), self.strategy.advise_entry(pair_data, {'pair': pair}),
{'pair': pair} {'pair': pair}
).copy() ).copy()
# Trim startup period from analyzed dataframe # Trim startup period from analyzed dataframe

View File

@ -489,8 +489,8 @@ class IStrategy(ABC, HyperStrategyMixin):
""" """
logger.debug("TA Analysis Launched") logger.debug("TA Analysis Launched")
dataframe = self.advise_indicators(dataframe, metadata) dataframe = self.advise_indicators(dataframe, metadata)
dataframe = self.advise_buy(dataframe, metadata) dataframe = self.advise_entry(dataframe, metadata)
dataframe = self.advise_sell(dataframe, metadata) dataframe = self.advise_exit(dataframe, metadata)
return dataframe return dataframe
def _analyze_ticker_internal(self, dataframe: DataFrame, metadata: dict) -> DataFrame: def _analyze_ticker_internal(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
@ -912,7 +912,7 @@ class IStrategy(ABC, HyperStrategyMixin):
def advise_all_indicators(self, data: Dict[str, DataFrame]) -> Dict[str, DataFrame]: def advise_all_indicators(self, data: Dict[str, DataFrame]) -> Dict[str, DataFrame]:
""" """
Populates indicators for given candle (OHLCV) data (for multiple pairs) Populates indicators for given candle (OHLCV) data (for multiple pairs)
Does not run advise_buy or advise_sell! Does not run advise_entry or advise_exit!
Used by optimize operations only, not during dry / live runs. Used by optimize operations only, not during dry / live runs.
Using .copy() to get a fresh copy of the dataframe for every strategy run. Using .copy() to get a fresh copy of the dataframe for every strategy run.
Also copy on output to avoid PerformanceWarnings pandas 1.3.0 started to show. Also copy on output to avoid PerformanceWarnings pandas 1.3.0 started to show.
@ -944,7 +944,7 @@ class IStrategy(ABC, HyperStrategyMixin):
else: else:
return self.populate_indicators(dataframe, metadata) return self.populate_indicators(dataframe, metadata)
def advise_buy(self, dataframe: DataFrame, metadata: dict) -> DataFrame: def advise_entry(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
""" """
Based on TA indicators, populates the entry order signal for the given dataframe Based on TA indicators, populates the entry order signal for the given dataframe
This method should not be overridden. This method should not be overridden.
@ -967,7 +967,7 @@ class IStrategy(ABC, HyperStrategyMixin):
return df return df
def advise_sell(self, dataframe: DataFrame, metadata: dict) -> DataFrame: def advise_exit(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
""" """
Based on TA indicators, populates the exit order signal for the given dataframe Based on TA indicators, populates the exit order signal for the given dataframe
This method should not be overridden. This method should not be overridden.

View File

@ -598,8 +598,8 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None:
backtesting = Backtesting(default_conf) backtesting = Backtesting(default_conf)
backtesting._set_strategy(backtesting.strategylist[0]) backtesting._set_strategy(backtesting.strategylist[0])
backtesting.required_startup = 0 backtesting.required_startup = 0
backtesting.strategy.advise_buy = lambda a, m: frame backtesting.strategy.advise_entry = lambda a, m: frame
backtesting.strategy.advise_sell = lambda a, m: frame backtesting.strategy.advise_exit = lambda a, m: frame
backtesting.strategy.use_custom_stoploss = data.use_custom_stoploss backtesting.strategy.use_custom_stoploss = data.use_custom_stoploss
caplog.set_level(logging.DEBUG) caplog.set_level(logging.DEBUG)

View File

@ -295,8 +295,8 @@ def test_backtesting_init(mocker, default_conf, order_types) -> None:
assert backtesting.config == default_conf assert backtesting.config == default_conf
assert backtesting.timeframe == '5m' assert backtesting.timeframe == '5m'
assert callable(backtesting.strategy.advise_all_indicators) assert callable(backtesting.strategy.advise_all_indicators)
assert callable(backtesting.strategy.advise_buy) assert callable(backtesting.strategy.advise_entry)
assert callable(backtesting.strategy.advise_sell) assert callable(backtesting.strategy.advise_exit)
assert isinstance(backtesting.strategy.dp, DataProvider) assert isinstance(backtesting.strategy.dp, DataProvider)
get_fee.assert_called() get_fee.assert_called()
assert backtesting.fee == 0.5 assert backtesting.fee == 0.5
@ -811,8 +811,8 @@ def test_backtest_clash_buy_sell(mocker, default_conf, testdatadir):
backtest_conf = _make_backtest_conf(mocker, conf=default_conf, datadir=testdatadir) backtest_conf = _make_backtest_conf(mocker, conf=default_conf, datadir=testdatadir)
backtesting = Backtesting(default_conf) backtesting = Backtesting(default_conf)
backtesting._set_strategy(backtesting.strategylist[0]) backtesting._set_strategy(backtesting.strategylist[0])
backtesting.strategy.advise_buy = fun # Override backtesting.strategy.advise_entry = fun # Override
backtesting.strategy.advise_sell = fun # Override backtesting.strategy.advise_exit = fun # Override
result = backtesting.backtest(**backtest_conf) result = backtesting.backtest(**backtest_conf)
assert result['results'].empty assert result['results'].empty
@ -827,8 +827,8 @@ def test_backtest_only_sell(mocker, default_conf, testdatadir):
backtest_conf = _make_backtest_conf(mocker, conf=default_conf, datadir=testdatadir) backtest_conf = _make_backtest_conf(mocker, conf=default_conf, datadir=testdatadir)
backtesting = Backtesting(default_conf) backtesting = Backtesting(default_conf)
backtesting._set_strategy(backtesting.strategylist[0]) backtesting._set_strategy(backtesting.strategylist[0])
backtesting.strategy.advise_buy = fun # Override backtesting.strategy.advise_entry = fun # Override
backtesting.strategy.advise_sell = fun # Override backtesting.strategy.advise_exit = fun # Override
result = backtesting.backtest(**backtest_conf) result = backtesting.backtest(**backtest_conf)
assert result['results'].empty assert result['results'].empty
@ -842,8 +842,8 @@ def test_backtest_alternate_buy_sell(default_conf, fee, mocker, testdatadir):
backtesting = Backtesting(default_conf) backtesting = Backtesting(default_conf)
backtesting.required_startup = 0 backtesting.required_startup = 0
backtesting._set_strategy(backtesting.strategylist[0]) backtesting._set_strategy(backtesting.strategylist[0])
backtesting.strategy.advise_buy = _trend_alternate # Override backtesting.strategy.advise_entry = _trend_alternate # Override
backtesting.strategy.advise_sell = _trend_alternate # Override backtesting.strategy.advise_exit = _trend_alternate # Override
result = backtesting.backtest(**backtest_conf) result = backtesting.backtest(**backtest_conf)
# 200 candles in backtest data # 200 candles in backtest data
# won't buy on first (shifted by 1) # won't buy on first (shifted by 1)
@ -896,8 +896,8 @@ def test_backtest_multi_pair(default_conf, fee, mocker, tres, pair, testdatadir)
backtesting = Backtesting(default_conf) backtesting = Backtesting(default_conf)
backtesting._set_strategy(backtesting.strategylist[0]) backtesting._set_strategy(backtesting.strategylist[0])
backtesting.strategy.advise_buy = _trend_alternate_hold # Override backtesting.strategy.advise_entry = _trend_alternate_hold # Override
backtesting.strategy.advise_sell = _trend_alternate_hold # Override backtesting.strategy.advise_exit = _trend_alternate_hold # Override
processed = backtesting.strategy.advise_all_indicators(data) processed = backtesting.strategy.advise_all_indicators(data)
min_date, max_date = get_timerange(processed) min_date, max_date = get_timerange(processed)

View File

@ -318,8 +318,8 @@ def test_start_calls_optimizer(mocker, hyperopt_conf, capsys) -> None:
# Should be called for historical candle data # Should be called for historical candle data
assert dumper.call_count == 1 assert dumper.call_count == 1
assert dumper2.call_count == 1 assert dumper2.call_count == 1
assert hasattr(hyperopt.backtesting.strategy, "advise_sell") assert hasattr(hyperopt.backtesting.strategy, "advise_exit")
assert hasattr(hyperopt.backtesting.strategy, "advise_buy") assert hasattr(hyperopt.backtesting.strategy, "advise_entry")
assert hasattr(hyperopt, "max_open_trades") assert hasattr(hyperopt, "max_open_trades")
assert hyperopt.max_open_trades == hyperopt_conf['max_open_trades'] assert hyperopt.max_open_trades == hyperopt_conf['max_open_trades']
assert hasattr(hyperopt, "position_stacking") assert hasattr(hyperopt, "position_stacking")
@ -698,8 +698,8 @@ def test_simplified_interface_roi_stoploss(mocker, hyperopt_conf, capsys) -> Non
assert dumper.call_count == 1 assert dumper.call_count == 1
assert dumper2.call_count == 1 assert dumper2.call_count == 1
assert hasattr(hyperopt.backtesting.strategy, "advise_sell") assert hasattr(hyperopt.backtesting.strategy, "advise_exit")
assert hasattr(hyperopt.backtesting.strategy, "advise_buy") assert hasattr(hyperopt.backtesting.strategy, "advise_entry")
assert hasattr(hyperopt, "max_open_trades") assert hasattr(hyperopt, "max_open_trades")
assert hyperopt.max_open_trades == hyperopt_conf['max_open_trades'] assert hyperopt.max_open_trades == hyperopt_conf['max_open_trades']
assert hasattr(hyperopt, "position_stacking") assert hasattr(hyperopt, "position_stacking")
@ -772,8 +772,8 @@ def test_simplified_interface_buy(mocker, hyperopt_conf, capsys) -> None:
assert dumper.called assert dumper.called
assert dumper.call_count == 1 assert dumper.call_count == 1
assert dumper2.call_count == 1 assert dumper2.call_count == 1
assert hasattr(hyperopt.backtesting.strategy, "advise_sell") assert hasattr(hyperopt.backtesting.strategy, "advise_exit")
assert hasattr(hyperopt.backtesting.strategy, "advise_buy") assert hasattr(hyperopt.backtesting.strategy, "advise_entry")
assert hasattr(hyperopt, "max_open_trades") assert hasattr(hyperopt, "max_open_trades")
assert hyperopt.max_open_trades == hyperopt_conf['max_open_trades'] assert hyperopt.max_open_trades == hyperopt_conf['max_open_trades']
assert hasattr(hyperopt, "position_stacking") assert hasattr(hyperopt, "position_stacking")
@ -821,8 +821,8 @@ def test_simplified_interface_sell(mocker, hyperopt_conf, capsys) -> None:
assert dumper.called assert dumper.called
assert dumper.call_count == 1 assert dumper.call_count == 1
assert dumper2.call_count == 1 assert dumper2.call_count == 1
assert hasattr(hyperopt.backtesting.strategy, "advise_sell") assert hasattr(hyperopt.backtesting.strategy, "advise_exit")
assert hasattr(hyperopt.backtesting.strategy, "advise_buy") assert hasattr(hyperopt.backtesting.strategy, "advise_entry")
assert hasattr(hyperopt, "max_open_trades") assert hasattr(hyperopt, "max_open_trades")
assert hyperopt.max_open_trades == hyperopt_conf['max_open_trades'] assert hyperopt.max_open_trades == hyperopt_conf['max_open_trades']
assert hasattr(hyperopt, "position_stacking") assert hasattr(hyperopt, "position_stacking")

View File

@ -535,20 +535,20 @@ def test_leverage_callback(default_conf, side) -> None:
def test_analyze_ticker_default(ohlcv_history, mocker, caplog) -> None: def test_analyze_ticker_default(ohlcv_history, mocker, caplog) -> None:
caplog.set_level(logging.DEBUG) caplog.set_level(logging.DEBUG)
ind_mock = MagicMock(side_effect=lambda x, meta: x) ind_mock = MagicMock(side_effect=lambda x, meta: x)
buy_mock = MagicMock(side_effect=lambda x, meta: x) entry_mock = MagicMock(side_effect=lambda x, meta: x)
sell_mock = MagicMock(side_effect=lambda x, meta: x) exit_mock = MagicMock(side_effect=lambda x, meta: x)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.strategy.interface.IStrategy', 'freqtrade.strategy.interface.IStrategy',
advise_indicators=ind_mock, advise_indicators=ind_mock,
advise_buy=buy_mock, advise_entry=entry_mock,
advise_sell=sell_mock, advise_exit=exit_mock,
) )
strategy = StrategyTestV3({}) strategy = StrategyTestV3({})
strategy.analyze_ticker(ohlcv_history, {'pair': 'ETH/BTC'}) strategy.analyze_ticker(ohlcv_history, {'pair': 'ETH/BTC'})
assert ind_mock.call_count == 1 assert ind_mock.call_count == 1
assert buy_mock.call_count == 1 assert entry_mock.call_count == 1
assert buy_mock.call_count == 1 assert entry_mock.call_count == 1
assert log_has('TA Analysis Launched', caplog) assert log_has('TA Analysis Launched', caplog)
assert not log_has('Skipping TA Analysis for already analyzed candle', caplog) assert not log_has('Skipping TA Analysis for already analyzed candle', caplog)
@ -557,8 +557,8 @@ def test_analyze_ticker_default(ohlcv_history, mocker, caplog) -> None:
strategy.analyze_ticker(ohlcv_history, {'pair': 'ETH/BTC'}) strategy.analyze_ticker(ohlcv_history, {'pair': 'ETH/BTC'})
# No analysis happens as process_only_new_candles is true # No analysis happens as process_only_new_candles is true
assert ind_mock.call_count == 2 assert ind_mock.call_count == 2
assert buy_mock.call_count == 2 assert entry_mock.call_count == 2
assert buy_mock.call_count == 2 assert entry_mock.call_count == 2
assert log_has('TA Analysis Launched', caplog) assert log_has('TA Analysis Launched', caplog)
assert not log_has('Skipping TA Analysis for already analyzed candle', caplog) assert not log_has('Skipping TA Analysis for already analyzed candle', caplog)
@ -566,13 +566,13 @@ def test_analyze_ticker_default(ohlcv_history, mocker, caplog) -> None:
def test__analyze_ticker_internal_skip_analyze(ohlcv_history, mocker, caplog) -> None: def test__analyze_ticker_internal_skip_analyze(ohlcv_history, mocker, caplog) -> None:
caplog.set_level(logging.DEBUG) caplog.set_level(logging.DEBUG)
ind_mock = MagicMock(side_effect=lambda x, meta: x) ind_mock = MagicMock(side_effect=lambda x, meta: x)
buy_mock = MagicMock(side_effect=lambda x, meta: x) entry_mock = MagicMock(side_effect=lambda x, meta: x)
sell_mock = MagicMock(side_effect=lambda x, meta: x) exit_mock = MagicMock(side_effect=lambda x, meta: x)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.strategy.interface.IStrategy', 'freqtrade.strategy.interface.IStrategy',
advise_indicators=ind_mock, advise_indicators=ind_mock,
advise_buy=buy_mock, advise_entry=entry_mock,
advise_sell=sell_mock, advise_exit=exit_mock,
) )
strategy = StrategyTestV3({}) strategy = StrategyTestV3({})
@ -585,8 +585,8 @@ def test__analyze_ticker_internal_skip_analyze(ohlcv_history, mocker, caplog) ->
assert 'close' in ret.columns assert 'close' in ret.columns
assert isinstance(ret, DataFrame) assert isinstance(ret, DataFrame)
assert ind_mock.call_count == 1 assert ind_mock.call_count == 1
assert buy_mock.call_count == 1 assert entry_mock.call_count == 1
assert buy_mock.call_count == 1 assert entry_mock.call_count == 1
assert log_has('TA Analysis Launched', caplog) assert log_has('TA Analysis Launched', caplog)
assert not log_has('Skipping TA Analysis for already analyzed candle', caplog) assert not log_has('Skipping TA Analysis for already analyzed candle', caplog)
caplog.clear() caplog.clear()
@ -594,8 +594,8 @@ def test__analyze_ticker_internal_skip_analyze(ohlcv_history, mocker, caplog) ->
ret = strategy._analyze_ticker_internal(ohlcv_history, {'pair': 'ETH/BTC'}) ret = strategy._analyze_ticker_internal(ohlcv_history, {'pair': 'ETH/BTC'})
# No analysis happens as process_only_new_candles is true # No analysis happens as process_only_new_candles is true
assert ind_mock.call_count == 1 assert ind_mock.call_count == 1
assert buy_mock.call_count == 1 assert entry_mock.call_count == 1
assert buy_mock.call_count == 1 assert entry_mock.call_count == 1
# only skipped analyze adds buy and sell columns, otherwise it's all mocked # only skipped analyze adds buy and sell columns, otherwise it's all mocked
assert 'enter_long' in ret.columns assert 'enter_long' in ret.columns
assert 'exit_long' in ret.columns assert 'exit_long' in ret.columns

View File

@ -117,11 +117,11 @@ def test_strategy_v2(result, default_conf):
df_indicators = strategy.advise_indicators(result, metadata=metadata) df_indicators = strategy.advise_indicators(result, metadata=metadata)
assert 'adx' in df_indicators assert 'adx' in df_indicators
dataframe = strategy.advise_buy(df_indicators, metadata=metadata) dataframe = strategy.advise_entry(df_indicators, metadata=metadata)
assert 'buy' not in dataframe.columns assert 'buy' not in dataframe.columns
assert 'enter_long' in dataframe.columns assert 'enter_long' in dataframe.columns
dataframe = strategy.advise_sell(df_indicators, metadata=metadata) dataframe = strategy.advise_exit(df_indicators, metadata=metadata)
assert 'sell' not in dataframe.columns assert 'sell' not in dataframe.columns
assert 'exit_long' in dataframe.columns assert 'exit_long' in dataframe.columns
@ -347,7 +347,7 @@ def test_deprecate_populate_indicators(result, default_conf):
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings(record=True) as w:
# Cause all warnings to always be triggered. # Cause all warnings to always be triggered.
warnings.simplefilter("always") warnings.simplefilter("always")
strategy.advise_buy(indicators, {'pair': 'ETH/BTC'}) strategy.advise_entry(indicators, {'pair': 'ETH/BTC'})
assert len(w) == 1 assert len(w) == 1
assert issubclass(w[-1].category, DeprecationWarning) assert issubclass(w[-1].category, DeprecationWarning)
assert "deprecated - check out the Sample strategy to see the current function headers!" \ assert "deprecated - check out the Sample strategy to see the current function headers!" \
@ -356,7 +356,7 @@ def test_deprecate_populate_indicators(result, default_conf):
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings(record=True) as w:
# Cause all warnings to always be triggered. # Cause all warnings to always be triggered.
warnings.simplefilter("always") warnings.simplefilter("always")
strategy.advise_sell(indicators, {'pair': 'ETH_BTC'}) strategy.advise_exit(indicators, {'pair': 'ETH_BTC'})
assert len(w) == 1 assert len(w) == 1
assert issubclass(w[-1].category, DeprecationWarning) assert issubclass(w[-1].category, DeprecationWarning)
assert "deprecated - check out the Sample strategy to see the current function headers!" \ assert "deprecated - check out the Sample strategy to see the current function headers!" \
@ -384,11 +384,11 @@ def test_call_deprecated_function(result, monkeypatch, default_conf, caplog):
assert isinstance(indicator_df, DataFrame) assert isinstance(indicator_df, DataFrame)
assert 'adx' in indicator_df.columns assert 'adx' in indicator_df.columns
enterdf = strategy.advise_buy(result, metadata=metadata) enterdf = strategy.advise_entry(result, metadata=metadata)
assert isinstance(enterdf, DataFrame) assert isinstance(enterdf, DataFrame)
assert 'buy' in enterdf.columns assert 'buy' in enterdf.columns
exitdf = strategy.advise_sell(result, metadata=metadata) exitdf = strategy.advise_exit(result, metadata=metadata)
assert isinstance(exitdf, DataFrame) assert isinstance(exitdf, DataFrame)
assert 'sell' in exitdf assert 'sell' in exitdf
@ -411,13 +411,13 @@ def test_strategy_interface_versioning(result, default_conf):
assert isinstance(indicator_df, DataFrame) assert isinstance(indicator_df, DataFrame)
assert 'adx' in indicator_df.columns assert 'adx' in indicator_df.columns
enterdf = strategy.advise_buy(result, metadata=metadata) enterdf = strategy.advise_entry(result, metadata=metadata)
assert isinstance(enterdf, DataFrame) assert isinstance(enterdf, DataFrame)
assert 'buy' not in enterdf.columns assert 'buy' not in enterdf.columns
assert 'enter_long' in enterdf.columns assert 'enter_long' in enterdf.columns
exitdf = strategy.advise_sell(result, metadata=metadata) exitdf = strategy.advise_exit(result, metadata=metadata)
assert isinstance(exitdf, DataFrame) assert isinstance(exitdf, DataFrame)
assert 'sell' not in exitdf assert 'sell' not in exitdf
assert 'exit_long' in exitdf assert 'exit_long' in exitdf