From 69f29e89070c0164bd43f5af8206cc178a5d77ab Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Wed, 18 Sep 2019 22:57:17 +0300 Subject: [PATCH 1/2] minor: Cleanup for backtesting --- freqtrade/configuration/configuration.py | 6 +++--- freqtrade/optimize/backtesting.py | 6 ++---- freqtrade/optimize/hyperopt.py | 18 ++++++++++++------ freqtrade/resolvers/hyperopt_resolver.py | 8 ++++---- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index dba94abc8..1aed32e50 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -217,7 +217,7 @@ class Configuration: deprecated_msg='-r/--refresh-pairs-cached will be removed soon.') self._args_to_config(config, argname='strategy_list', - logstring='Using strategy list of {} Strategies', logfun=len) + logstring='Using strategy list of {} strategies', logfun=len) self._args_to_config(config, argname='ticker_interval', logstring='Overriding ticker interval with Command line argument') @@ -238,7 +238,7 @@ class Configuration: # Hyperopt section self._args_to_config(config, argname='hyperopt', - logstring='Using Hyperopt file {}') + logstring='Using Hyperopt class name: {}') self._args_to_config(config, argname='hyperopt_path', logstring='Using additional Hyperopt lookup path: {}') @@ -276,7 +276,7 @@ class Configuration: logstring='Hyperopt continue: {}') self._args_to_config(config, argname='hyperopt_loss', - logstring='Using loss function: {}') + logstring='Using Hyperopt loss class name: {}') def _process_plot_options(self, config: Dict[str, Any]) -> None: diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 300cef82f..4956907fb 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -95,8 +95,6 @@ class Backtesting: Load strategy into backtesting """ self.strategy = strategy - self.advise_buy = strategy.advise_buy - self.advise_sell = strategy.advise_sell # Set stoploss_on_exchange to false for backtesting, # since a "perfect" stoploss-sell is assumed anyway # And the regular "stoploss" function would not apply to that case @@ -219,8 +217,8 @@ class Backtesting: for pair, pair_data in processed.items(): pair_data['buy'], pair_data['sell'] = 0, 0 # cleanup from previous run - ticker_data = self.advise_sell( - self.advise_buy(pair_data, {'pair': pair}), {'pair': pair})[headers].copy() + ticker_data = self.strategy.advise_sell( + self.strategy.advise_buy(pair_data, {'pair': pair}), {'pair': pair})[headers].copy() # to avoid using data from future, we buy/sell with signal from previous candle ticker_data.loc[:, 'buy'] = ticker_data['buy'].shift(1) diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 6dbcf8765..c511aa5ac 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -49,10 +49,11 @@ class Hyperopt: """ def __init__(self, config: Dict[str, Any]) -> None: self.config = config - self.backtesting = Backtesting(self.config) self.custom_hyperopt = HyperOptResolver(self.config).hyperopt + self.backtesting = Backtesting(self.config) + self.custom_hyperoptloss = HyperOptLossResolver(self.config).hyperoptloss self.calculate_loss = self.custom_hyperoptloss.hyperopt_loss_function @@ -77,9 +78,11 @@ class Hyperopt: self.backtesting.strategy.advise_indicators = \ self.custom_hyperopt.populate_indicators # type: ignore if hasattr(self.custom_hyperopt, 'populate_buy_trend'): - self.backtesting.advise_buy = self.custom_hyperopt.populate_buy_trend # type: ignore + self.backtesting.strategy.advise_buy = \ + self.custom_hyperopt.populate_buy_trend # type: ignore if hasattr(self.custom_hyperopt, 'populate_sell_trend'): - self.backtesting.advise_sell = self.custom_hyperopt.populate_sell_trend # type: ignore + self.backtesting.strategy.advise_sell = \ + self.custom_hyperopt.populate_sell_trend # type: ignore # Use max_open_trades for hyperopt as well, except --disable-max-market-positions is set if self.config.get('use_max_market_positions', True): @@ -259,13 +262,16 @@ class Hyperopt: """ params = self.get_args(_params) if self.has_space('roi'): - self.backtesting.strategy.minimal_roi = self.custom_hyperopt.generate_roi_table(params) + self.backtesting.strategy.minimal_roi = \ + self.custom_hyperopt.generate_roi_table(params) if self.has_space('buy'): - self.backtesting.advise_buy = self.custom_hyperopt.buy_strategy_generator(params) + self.backtesting.strategy.advise_buy = \ + self.custom_hyperopt.buy_strategy_generator(params) if self.has_space('sell'): - self.backtesting.advise_sell = self.custom_hyperopt.sell_strategy_generator(params) + self.backtesting.strategy.advise_sell = \ + self.custom_hyperopt.sell_strategy_generator(params) if self.has_space('stoploss'): self.backtesting.strategy.stoploss = params['stoploss'] diff --git a/freqtrade/resolvers/hyperopt_resolver.py b/freqtrade/resolvers/hyperopt_resolver.py index f808ca0d9..3ffdc5e1f 100644 --- a/freqtrade/resolvers/hyperopt_resolver.py +++ b/freqtrade/resolvers/hyperopt_resolver.py @@ -38,11 +38,11 @@ class HyperOptResolver(IResolver): IHyperOpt.ticker_interval = str(config['ticker_interval']) if not hasattr(self.hyperopt, 'populate_buy_trend'): - logger.warning("Custom Hyperopt does not provide populate_buy_trend. " - "Using populate_buy_trend from DefaultStrategy.") + logger.warning("Hyperopt class does not provide populate_buy_trend() method. " + "Using populate_buy_trend from the strategy.") if not hasattr(self.hyperopt, 'populate_sell_trend'): - logger.warning("Custom Hyperopt does not provide populate_sell_trend. " - "Using populate_sell_trend from DefaultStrategy.") + logger.warning("Hyperopt class does not provide populate_sell_trend() method. " + "Using populate_sell_trend from the strategy.") def _load_hyperopt( self, hyperopt_name: str, config: Dict, extra_dir: Optional[str] = None) -> IHyperOpt: From 50b45639124ae418a4383164ce6d08b16cb506f6 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Wed, 18 Sep 2019 22:57:37 +0300 Subject: [PATCH 2/2] Tests adjusted --- tests/optimize/test_backtest_detail.py | 4 ++-- tests/optimize/test_backtesting.py | 20 ++++++++++---------- tests/optimize/test_hyperopt.py | 24 ++++++++++++------------ tests/test_configuration.py | 2 +- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/tests/optimize/test_backtest_detail.py b/tests/optimize/test_backtest_detail.py index 1bcd9b08e..d8a4190e2 100644 --- a/tests/optimize/test_backtest_detail.py +++ b/tests/optimize/test_backtest_detail.py @@ -291,8 +291,8 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None: patch_exchange(mocker) frame = _build_backtest_dataframe(data.data) backtesting = Backtesting(default_conf) - backtesting.advise_buy = lambda a, m: frame - backtesting.advise_sell = lambda a, m: frame + backtesting.strategy.advise_buy = lambda a, m: frame + backtesting.strategy.advise_sell = lambda a, m: frame caplog.set_level(logging.DEBUG) pair = "UNITTEST/BTC" diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index 99fb30cbd..7b50f2b18 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -313,8 +313,8 @@ def test_backtesting_init(mocker, default_conf, order_types) -> None: assert backtesting.config == default_conf assert backtesting.ticker_interval == '5m' assert callable(backtesting.strategy.tickerdata_to_dataframe) - assert callable(backtesting.advise_buy) - assert callable(backtesting.advise_sell) + assert callable(backtesting.strategy.advise_buy) + assert callable(backtesting.strategy.advise_sell) assert isinstance(backtesting.strategy.dp, DataProvider) get_fee.assert_called() assert backtesting.fee == 0.5 @@ -627,8 +627,8 @@ def test_backtest_clash_buy_sell(mocker, default_conf, testdatadir): backtest_conf = _make_backtest_conf(mocker, conf=default_conf, datadir=testdatadir) backtesting = Backtesting(default_conf) - backtesting.advise_buy = fun # Override - backtesting.advise_sell = fun # Override + backtesting.strategy.advise_buy = fun # Override + backtesting.strategy.advise_sell = fun # Override results = backtesting.backtest(backtest_conf) assert results.empty @@ -642,8 +642,8 @@ def test_backtest_only_sell(mocker, default_conf, testdatadir): backtest_conf = _make_backtest_conf(mocker, conf=default_conf, datadir=testdatadir) backtesting = Backtesting(default_conf) - backtesting.advise_buy = fun # Override - backtesting.advise_sell = fun # Override + backtesting.strategy.advise_buy = fun # Override + backtesting.strategy.advise_sell = fun # Override results = backtesting.backtest(backtest_conf) assert results.empty @@ -657,8 +657,8 @@ def test_backtest_alternate_buy_sell(default_conf, fee, mocker, testdatadir): default_conf['experimental'] = {"use_sell_signal": True} default_conf['ticker_interval'] = '1m' backtesting = Backtesting(default_conf) - backtesting.advise_buy = _trend_alternate # Override - backtesting.advise_sell = _trend_alternate # Override + backtesting.strategy.advise_buy = _trend_alternate # Override + backtesting.strategy.advise_sell = _trend_alternate # Override results = backtesting.backtest(backtest_conf) backtesting._store_backtest_result("test_.json", results) # 200 candles in backtest data @@ -700,8 +700,8 @@ def test_backtest_multi_pair(default_conf, fee, mocker, tres, pair, testdatadir) default_conf['ticker_interval'] = '5m' backtesting = Backtesting(default_conf) - backtesting.advise_buy = _trend_alternate_hold # Override - backtesting.advise_sell = _trend_alternate_hold # Override + backtesting.strategy.advise_buy = _trend_alternate_hold # Override + backtesting.strategy.advise_sell = _trend_alternate_hold # Override data_processed = backtesting.strategy.tickerdata_to_dataframe(data) min_date, max_date = get_timeframe(data_processed) diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index 15ecb92d8..2e383c839 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -166,10 +166,10 @@ def test_hyperoptresolver(mocker, default_conf, caplog) -> None: x = HyperOptResolver(default_conf, ).hyperopt assert not hasattr(x, 'populate_buy_trend') assert not hasattr(x, 'populate_sell_trend') - assert log_has("Custom Hyperopt does not provide populate_sell_trend. " - "Using populate_sell_trend from DefaultStrategy.", caplog) - assert log_has("Custom Hyperopt does not provide populate_buy_trend. " - "Using populate_buy_trend from DefaultStrategy.", caplog) + assert log_has("Hyperopt class does not provide populate_sell_trend() method. " + "Using populate_sell_trend from the strategy.", caplog) + assert log_has("Hyperopt class does not provide populate_buy_trend() method. " + "Using populate_buy_trend from the strategy.", caplog) assert hasattr(x, "ticker_interval") @@ -415,8 +415,8 @@ def test_start_calls_optimizer(mocker, default_conf, caplog, capsys) -> None: assert dumper.called # Should be called twice, once for tickerdata, once to save evaluations assert dumper.call_count == 2 - assert hasattr(hyperopt.backtesting, "advise_sell") - assert hasattr(hyperopt.backtesting, "advise_buy") + assert hasattr(hyperopt.backtesting.strategy, "advise_sell") + assert hasattr(hyperopt.backtesting.strategy, "advise_buy") assert hasattr(hyperopt, "max_open_trades") assert hyperopt.max_open_trades == default_conf['max_open_trades'] assert hasattr(hyperopt, "position_stacking") @@ -709,8 +709,8 @@ def test_simplified_interface_roi_stoploss(mocker, default_conf, caplog, capsys) assert dumper.called # Should be called twice, once for tickerdata, once to save evaluations assert dumper.call_count == 2 - assert hasattr(hyperopt.backtesting, "advise_sell") - assert hasattr(hyperopt.backtesting, "advise_buy") + assert hasattr(hyperopt.backtesting.strategy, "advise_sell") + assert hasattr(hyperopt.backtesting.strategy, "advise_buy") assert hasattr(hyperopt, "max_open_trades") assert hyperopt.max_open_trades == default_conf['max_open_trades'] assert hasattr(hyperopt, "position_stacking") @@ -783,8 +783,8 @@ def test_simplified_interface_buy(mocker, default_conf, caplog, capsys) -> None: assert dumper.called # Should be called twice, once for tickerdata, once to save evaluations assert dumper.call_count == 2 - assert hasattr(hyperopt.backtesting, "advise_sell") - assert hasattr(hyperopt.backtesting, "advise_buy") + assert hasattr(hyperopt.backtesting.strategy, "advise_sell") + assert hasattr(hyperopt.backtesting.strategy, "advise_buy") assert hasattr(hyperopt, "max_open_trades") assert hyperopt.max_open_trades == default_conf['max_open_trades'] assert hasattr(hyperopt, "position_stacking") @@ -828,8 +828,8 @@ def test_simplified_interface_sell(mocker, default_conf, caplog, capsys) -> None assert dumper.called # Should be called twice, once for tickerdata, once to save evaluations assert dumper.call_count == 2 - assert hasattr(hyperopt.backtesting, "advise_sell") - assert hasattr(hyperopt.backtesting, "advise_buy") + assert hasattr(hyperopt.backtesting.strategy, "advise_sell") + assert hasattr(hyperopt.backtesting.strategy, "advise_buy") assert hasattr(hyperopt, "max_open_trades") assert hyperopt.max_open_trades == default_conf['max_open_trades'] assert hasattr(hyperopt, "position_stacking") diff --git a/tests/test_configuration.py b/tests/test_configuration.py index 67bde50fa..53f46fe2e 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -440,7 +440,7 @@ def test_setup_configuration_with_stratlist(mocker, default_conf, caplog) -> Non caplog) assert 'strategy_list' in config - assert log_has('Using strategy list of 2 Strategies', caplog) + assert log_has('Using strategy list of 2 strategies', caplog) assert 'position_stacking' not in config