diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index eefbd4e04..51122cfb2 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -445,7 +445,7 @@ class Backtesting(object): optimize.validate_backtest_data(data, min_date, max_date, timeframe_to_minutes(self.ticker_interval)) logger.info( - 'Measuring data from %s up to %s (%s days)..', + 'Backtesting with data from %s up to %s (%s days)..', min_date.isoformat(), max_date.isoformat(), (max_date - min_date).days diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 252b76252..92589aed2 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -24,7 +24,8 @@ from freqtrade import DependencyException from freqtrade.arguments import Arguments from freqtrade.configuration import Configuration from freqtrade.data.history import load_data -from freqtrade.optimize import get_timeframe +from freqtrade.exchange import timeframe_to_minutes +from freqtrade.optimize import get_timeframe, validate_backtest_data from freqtrade.optimize.backtesting import Backtesting from freqtrade.state import RunMode from freqtrade.resolvers import HyperOptResolver @@ -282,9 +283,25 @@ class Hyperopt(Backtesting): timerange=timerange ) + if not data: + logger.critical("No data found. Terminating.") + return + + min_date, max_date = get_timeframe(data) + # Validate dataframe for missing values (mainly at start and end, as fillup is called) + validate_backtest_data(data, min_date, max_date, + timeframe_to_minutes(self.ticker_interval)) + logger.info( + 'Hyperopting with data from %s up to %s (%s days)..', + min_date.isoformat(), + max_date.isoformat(), + (max_date - min_date).days + ) + if self.has_space('buy') or self.has_space('sell'): self.strategy.advise_indicators = \ self.custom_hyperopt.populate_indicators # type: ignore + dump(self.strategy.tickerdata_to_dataframe(data), TICKERDATA_PICKLE) # We don't need exchange instance anymore while running hyperopt diff --git a/freqtrade/tests/optimize/test_backtesting.py b/freqtrade/tests/optimize/test_backtesting.py index 02f8840e2..6a39deed4 100644 --- a/freqtrade/tests/optimize/test_backtesting.py +++ b/freqtrade/tests/optimize/test_backtesting.py @@ -495,7 +495,7 @@ def test_backtesting_start(default_conf, mocker, caplog) -> None: 'Using local backtesting data (using whitelist in given config) ...', 'Using stake_currency: BTC ...', 'Using stake_amount: 0.001 ...', - 'Measuring data from 2017-11-14T21:17:00+00:00 ' + 'Backtesting with data from 2017-11-14T21:17:00+00:00 ' 'up to 2017-11-14T22:59:00+00:00 (0 days)..' ] for line in exists: @@ -858,7 +858,8 @@ def test_backtest_start_live(default_conf, mocker, caplog): 'Using stake_currency: BTC ...', 'Using stake_amount: 0.001 ...', 'Downloading data for all pairs in whitelist ...', - 'Measuring data from 2017-11-14T19:31:00+00:00 up to 2017-11-14T22:58:00+00:00 (0 days)..', + 'Backtesting with data from 2017-11-14T19:31:00+00:00 ' + 'up to 2017-11-14T22:58:00+00:00 (0 days)..', 'Parameter --enable-position-stacking detected ...' ] @@ -916,7 +917,8 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog): 'Using stake_currency: BTC ...', 'Using stake_amount: 0.001 ...', 'Downloading data for all pairs in whitelist ...', - 'Measuring data from 2017-11-14T19:31:00+00:00 up to 2017-11-14T22:58:00+00:00 (0 days)..', + 'Backtesting with data from 2017-11-14T19:31:00+00:00 ' + 'up to 2017-11-14T22:58:00+00:00 (0 days)..', 'Parameter --enable-position-stacking detected ...', 'Running backtesting for Strategy DefaultStrategy', 'Running backtesting for Strategy TestStrategy', diff --git a/freqtrade/tests/optimize/test_hyperopt.py b/freqtrade/tests/optimize/test_hyperopt.py index 86c5f2a34..f50f58e5b 100644 --- a/freqtrade/tests/optimize/test_hyperopt.py +++ b/freqtrade/tests/optimize/test_hyperopt.py @@ -195,6 +195,33 @@ def test_start(mocker, default_conf, caplog) -> None: assert start_mock.call_count == 1 +def test_start_no_data(mocker, default_conf, caplog) -> None: + mocker.patch( + 'freqtrade.configuration.Configuration._load_config_file', + lambda *args, **kwargs: default_conf + ) + mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock(return_value={})) + mocker.patch( + 'freqtrade.optimize.hyperopt.get_timeframe', + MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))) + ) + + patch_exchange(mocker) + + args = [ + '--config', 'config.json', + 'hyperopt', + '--epochs', '5' + ] + args = get_args(args) + start(args) + + import pprint + pprint.pprint(caplog.record_tuples) + + assert log_has('No data found. Terminating.', caplog.record_tuples) + + def test_start_failure(mocker, default_conf, caplog) -> None: start_mock = MagicMock() mocker.patch( @@ -310,6 +337,11 @@ def test_roi_table_generation(hyperopt) -> None: def test_start_calls_optimizer(mocker, default_conf, caplog) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock()) + mocker.patch( + 'freqtrade.optimize.hyperopt.get_timeframe', + MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))) + ) + parallel = mocker.patch( 'freqtrade.optimize.hyperopt.Hyperopt.run_optimizer_parallel', MagicMock(return_value=[{'loss': 1, 'result': 'foo result', 'params': {}}])