diff --git a/docs/strategy-customization.md b/docs/strategy-customization.md index ae44d32ea..4d3d9bce5 100644 --- a/docs/strategy-customization.md +++ b/docs/strategy-customization.md @@ -131,7 +131,7 @@ In this example strategy, this should be set to 100 (`startup_candle_count = 100 By letting the bot know how much history is needed, backtest trades can start at the specified timerange during backtesting and hyperopt. -!!! Warning: +!!! Warning `startup_candle_count` should be below `ohlcv_candle_limit` (which is 500 for most exchanges) - since only this amount of candles will be available during trading operations. #### Example diff --git a/freqtrade/data/history.py b/freqtrade/data/history.py index dfd175b1f..c07b58da2 100644 --- a/freqtrade/data/history.py +++ b/freqtrade/data/history.py @@ -147,7 +147,7 @@ def load_pair_history(pair: str, """ timerange_startup = deepcopy(timerange) - if startup_candles: + if startup_candles and timerange_startup: logger.info('Using indicator startup period: %s ...', startup_candles) timerange_startup.subtract_start(timeframe_to_seconds(ticker_interval) * startup_candles) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 3fd7d615c..023e16cc5 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -447,6 +447,7 @@ class Exchange: def validate_required_startup_candles(self, startup_candles) -> None: """ Checks if required startup_candles is more than ohlcv_candle_limit. + Requires a grace-period of 5 candles - so a startup-period up to 494 is allowed by default. """ if startup_candles + 5 > self._ft_has['ohlcv_candle_limit']: raise OperationalException( diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 2264234d4..c576ea6f8 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -22,8 +22,7 @@ from pandas import DataFrame from skopt import Optimizer from skopt.space import Dimension -from freqtrade.configuration import TimeRange -from freqtrade.data.history import load_data, get_timeframe, trim_dataframe +from freqtrade.data.history import get_timeframe, trim_dataframe from freqtrade.misc import round_dict from freqtrade.optimize.backtesting import Backtesting # Import IHyperOpt and IHyperOptLoss to allow unpickling classes from these modules diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 48a70b0ce..d42f8e989 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -424,7 +424,7 @@ class IStrategy(ABC): def tickerdata_to_dataframe(self, tickerdata: Dict[str, List]) -> Dict[str, DataFrame]: """ Creates a dataframe and populates indicators for given ticker data - Used by optimize operations only, not during dry / live runs. + Used by optimize operations only, not during dry / live runs. """ return {pair: self.advise_indicators(pair_data, {'pair': pair}) for pair, pair_data in tickerdata.items()} diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index e0e0cc7b1..6805d8e73 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -535,7 +535,6 @@ def test_validate_order_types_not_in_config(default_conf, mocker): def test_validate_required_startup_candles(default_conf, mocker, caplog): api_mock = MagicMock() - default_conf['startup_candle_count'] = 2000 mocker.patch('freqtrade.exchange.Exchange.name', PropertyMock(return_value='Binance')) mocker.patch('freqtrade.exchange.Exchange._init_ccxt', api_mock) @@ -543,7 +542,12 @@ def test_validate_required_startup_candles(default_conf, mocker, caplog): mocker.patch('freqtrade.exchange.Exchange._load_async_markets', MagicMock()) mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock()) - with pytest.raises(OperationalException, match=r'This strategy requires 2000.*'): + default_conf['startup_candle_count'] = 20 + ex = Exchange(default_conf) + assert ex + default_conf['startup_candle_count'] = 600 + + with pytest.raises(OperationalException, match=r'This strategy requires 600.*'): Exchange(default_conf) diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index d1448d367..d0c37c40d 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -392,7 +392,8 @@ def test_roi_table_generation(hyperopt) -> None: def test_start_calls_optimizer(mocker, default_conf, caplog, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) - mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock()) + mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', + MagicMock(return_value=(MagicMock(), None))) mocker.patch( 'freqtrade.optimize.hyperopt.get_timeframe', MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))) @@ -607,7 +608,8 @@ def test_continue_hyperopt(mocker, default_conf, caplog): def test_print_json_spaces_all(mocker, default_conf, caplog, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) - mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock()) + mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', + MagicMock(return_value=(MagicMock(), None))) mocker.patch( 'freqtrade.optimize.hyperopt.get_timeframe', MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))) @@ -644,7 +646,8 @@ def test_print_json_spaces_all(mocker, default_conf, caplog, capsys) -> None: def test_print_json_spaces_roi_stoploss(mocker, default_conf, caplog, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) - mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock()) + mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', + MagicMock(return_value=(MagicMock(), None))) mocker.patch( 'freqtrade.optimize.hyperopt.get_timeframe', MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))) @@ -681,7 +684,8 @@ def test_print_json_spaces_roi_stoploss(mocker, default_conf, caplog, capsys) -> def test_simplified_interface_roi_stoploss(mocker, default_conf, caplog, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) - mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock()) + mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', + MagicMock(return_value=(MagicMock(), None))) mocker.patch( 'freqtrade.optimize.hyperopt.get_timeframe', MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))) @@ -727,7 +731,8 @@ def test_simplified_interface_roi_stoploss(mocker, default_conf, caplog, capsys) def test_simplified_interface_all_failed(mocker, default_conf, caplog, capsys) -> None: mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) - mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock()) + mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', + MagicMock(return_value=(MagicMock(), None))) mocker.patch( 'freqtrade.optimize.hyperopt.get_timeframe', MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))) @@ -756,7 +761,8 @@ def test_simplified_interface_all_failed(mocker, default_conf, caplog, capsys) - def test_simplified_interface_buy(mocker, default_conf, caplog, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) - mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock()) + mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', + MagicMock(return_value=(MagicMock(), None))) mocker.patch( 'freqtrade.optimize.hyperopt.get_timeframe', MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))) @@ -801,7 +807,8 @@ def test_simplified_interface_buy(mocker, default_conf, caplog, capsys) -> None: def test_simplified_interface_sell(mocker, default_conf, caplog, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) - mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock()) + mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', + MagicMock(return_value=(MagicMock(), None))) mocker.patch( 'freqtrade.optimize.hyperopt.get_timeframe', MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))) @@ -852,7 +859,8 @@ def test_simplified_interface_sell(mocker, default_conf, caplog, capsys) -> None ]) def test_simplified_interface_failed(mocker, default_conf, caplog, capsys, method, space) -> None: mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) - mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock()) + mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', + MagicMock(return_value=(MagicMock(), None))) mocker.patch( 'freqtrade.optimize.hyperopt.get_timeframe', MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))