diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index 564725709..2f9f9bc56 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -3,6 +3,7 @@ import locale import logging from datetime import datetime from pathlib import Path +from copy import deepcopy from typing import Dict, List from unittest.mock import MagicMock, PropertyMock @@ -16,7 +17,6 @@ from freqtrade.commands.optimize_commands import (setup_optimize_configuration, start_hyperopt) from freqtrade.data.history import load_data from freqtrade.exceptions import DependencyException, OperationalException -from freqtrade.optimize.default_hyperopt import DefaultHyperOpt from freqtrade.optimize.default_hyperopt_loss import DefaultHyperOptLoss from freqtrade.optimize.hyperopt import Hyperopt from freqtrade.resolvers.hyperopt_resolver import (HyperOptLossResolver, @@ -26,15 +26,28 @@ from freqtrade.strategy.interface import SellType from tests.conftest import (get_args, log_has, log_has_re, patch_exchange, patched_configuration_load_config_file) +from .hyperopts.default_hyperopt import DefaultHyperOpt + @pytest.fixture(scope='function') -def hyperopt(default_conf, mocker): - default_conf.update({ - 'spaces': ['default'], - 'hyperopt': 'DefaultHyperOpt', - }) +def hyperopt_conf(default_conf): + hyperconf = deepcopy(default_conf) + hyperconf.update({ + 'hyperopt': 'DefaultHyperOpt', + 'hyperopt_path': str(Path(__file__).parent / 'hyperopts'), + 'epochs': 1, + 'timerange': None, + 'spaces': ['default'], + 'hyperopt_jobs': 1, + }) + return hyperconf + + +@pytest.fixture(scope='function') +def hyperopt(hyperopt_conf, mocker): + patch_exchange(mocker) - return Hyperopt(default_conf) + return Hyperopt(hyperopt_conf) @pytest.fixture(scope='function') @@ -160,7 +173,7 @@ def test_setup_hyperopt_configuration_with_arguments(mocker, default_conf, caplo assert log_has('Parameter --print-all detected ...', caplog) -def test_setup_hyperopt_configuration_unlimited_stake_amount(mocker, default_conf, caplog) -> None: +def test_setup_hyperopt_configuration_unlimited_stake_amount(mocker, default_conf) -> None: default_conf['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT patched_configuration_load_config_file(mocker, default_conf) @@ -201,7 +214,7 @@ def test_hyperoptresolver(mocker, default_conf, caplog) -> None: assert hasattr(x, "timeframe") -def test_hyperoptresolver_wrongname(mocker, default_conf, caplog) -> None: +def test_hyperoptresolver_wrongname(default_conf) -> None: default_conf.update({'hyperopt': "NonExistingHyperoptClass"}) with pytest.raises(OperationalException, match=r'Impossible to load Hyperopt.*'): @@ -216,7 +229,7 @@ def test_hyperoptresolver_noname(default_conf): HyperOptResolver.load_hyperopt(default_conf) -def test_hyperoptlossresolver(mocker, default_conf, caplog) -> None: +def test_hyperoptlossresolver(mocker, default_conf) -> None: hl = DefaultHyperOptLoss mocker.patch( @@ -227,14 +240,14 @@ def test_hyperoptlossresolver(mocker, default_conf, caplog) -> None: assert hasattr(x, "hyperopt_loss_function") -def test_hyperoptlossresolver_wrongname(mocker, default_conf, caplog) -> None: +def test_hyperoptlossresolver_wrongname(default_conf) -> None: default_conf.update({'hyperopt_loss': "NonExistingLossClass"}) with pytest.raises(OperationalException, match=r'Impossible to load HyperoptLoss.*'): HyperOptLossResolver.load_hyperoptloss(default_conf) -def test_start_not_installed(mocker, default_conf, caplog, import_fails) -> None: +def test_start_not_installed(mocker, default_conf) -> None: start_mock = MagicMock() patched_configuration_load_config_file(mocker, default_conf) @@ -253,9 +266,9 @@ def test_start_not_installed(mocker, default_conf, caplog, import_fails) -> None start_hyperopt(pargs) -def test_start(mocker, default_conf, caplog) -> None: +def test_start(mocker, hyperopt_conf, caplog) -> None: start_mock = MagicMock() - patched_configuration_load_config_file(mocker, default_conf) + patched_configuration_load_config_file(mocker, hyperopt_conf) mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.start', start_mock) patch_exchange(mocker) @@ -272,8 +285,8 @@ def test_start(mocker, default_conf, caplog) -> None: assert start_mock.call_count == 1 -def test_start_no_data(mocker, default_conf, caplog) -> None: - patched_configuration_load_config_file(mocker, default_conf) +def test_start_no_data(mocker, hyperopt_conf) -> None: + patched_configuration_load_config_file(mocker, hyperopt_conf) mocker.patch('freqtrade.data.history.load_pair_history', MagicMock(return_value=pd.DataFrame)) mocker.patch( 'freqtrade.optimize.hyperopt.get_timerange', @@ -293,9 +306,9 @@ def test_start_no_data(mocker, default_conf, caplog) -> None: start_hyperopt(pargs) -def test_start_filelock(mocker, default_conf, caplog) -> None: - start_mock = MagicMock(side_effect=Timeout(Hyperopt.get_lock_filename(default_conf))) - patched_configuration_load_config_file(mocker, default_conf) +def test_start_filelock(mocker, hyperopt_conf, caplog) -> None: + start_mock = MagicMock(side_effect=Timeout(Hyperopt.get_lock_filename(hyperopt_conf))) + patched_configuration_load_config_file(mocker, hyperopt_conf) mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.start', start_mock) patch_exchange(mocker) @@ -519,7 +532,7 @@ def test_roi_table_generation(hyperopt) -> None: assert hyperopt.custom_hyperopt.generate_roi_table(params) == {0: 6, 15: 3, 25: 1, 30: 0} -def test_start_calls_optimizer(mocker, default_conf, caplog, capsys) -> None: +def test_start_calls_optimizer(mocker, hyperopt_conf, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) @@ -545,15 +558,9 @@ def test_start_calls_optimizer(mocker, default_conf, caplog, capsys) -> None: ) patch_exchange(mocker) # Co-test loading timeframe from strategy - del default_conf['timeframe'] - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'default', - 'hyperopt_jobs': 1, }) + del hyperopt_conf['timeframe'] - hyperopt = Hyperopt(default_conf) + hyperopt = Hyperopt(hyperopt_conf) hyperopt.backtesting.strategy.ohlcvdata_to_dataframe = MagicMock() hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={}) @@ -569,7 +576,7 @@ def test_start_calls_optimizer(mocker, default_conf, caplog, capsys) -> None: 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 hyperopt.max_open_trades == hyperopt_conf['max_open_trades'] assert hasattr(hyperopt, "position_stacking") @@ -686,13 +693,36 @@ def test_buy_strategy_generator(hyperopt, testdatadir) -> None: assert 1 in result['buy'] -def test_generate_optimizer(mocker, default_conf) -> None: - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'timerange': None, - 'spaces': 'all', - 'hyperopt_min_trades': 1, - }) +def test_sell_strategy_generator(hyperopt, testdatadir) -> None: + data = load_data(testdatadir, '1m', ['UNITTEST/BTC'], fill_up_missing=True) + dataframes = hyperopt.backtesting.strategy.ohlcvdata_to_dataframe(data) + dataframe = hyperopt.custom_hyperopt.populate_indicators(dataframes['UNITTEST/BTC'], + {'pair': 'UNITTEST/BTC'}) + + populate_sell_trend = hyperopt.custom_hyperopt.sell_strategy_generator( + { + 'sell-adx-value': 20, + 'sell-fastd-value': 75, + 'sell-mfi-value': 80, + 'sell-rsi-value': 20, + 'sell-adx-enabled': True, + 'sell-fastd-enabled': True, + 'sell-mfi-enabled': True, + 'sell-rsi-enabled': True, + 'sell-trigger': 'sell-bb_upper' + } + ) + result = populate_sell_trend(dataframe, {'pair': 'UNITTEST/BTC'}) + # Check if some indicators are generated. We will not test all of them + print(result) + assert 'sell' in result + assert 1 in result['sell'] + + +def test_generate_optimizer(mocker, hyperopt_conf) -> None: + hyperopt_conf.update({'spaces': 'all', + 'hyperopt_min_trades': 1, + }) trades = [ ('TRX/BTC', 0.023117, 0.000233, 100) @@ -783,48 +813,35 @@ def test_generate_optimizer(mocker, default_conf) -> None: 'total_profit': 0.00023300 } - hyperopt = Hyperopt(default_conf) + hyperopt = Hyperopt(hyperopt_conf) hyperopt.dimensions = hyperopt.hyperopt_space() generate_optimizer_value = hyperopt.generate_optimizer(list(optimizer_param.values())) assert generate_optimizer_value == response_expected -def test_clean_hyperopt(mocker, default_conf, caplog): +def test_clean_hyperopt(mocker, hyperopt_conf, caplog): patch_exchange(mocker) - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'default', - 'hyperopt_jobs': 1, - }) + mocker.patch("freqtrade.optimize.hyperopt.Path.is_file", MagicMock(return_value=True)) unlinkmock = mocker.patch("freqtrade.optimize.hyperopt.Path.unlink", MagicMock()) - h = Hyperopt(default_conf) + h = Hyperopt(hyperopt_conf) assert unlinkmock.call_count == 2 assert log_has(f"Removing `{h.data_pickle_file}`.", caplog) -def test_continue_hyperopt(mocker, default_conf, caplog): +def test_continue_hyperopt(mocker, hyperopt_conf, caplog): patch_exchange(mocker) - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'default', - 'hyperopt_jobs': 1, - 'hyperopt_continue': True - }) + hyperopt_conf.update({'hyperopt_continue': True}) mocker.patch("freqtrade.optimize.hyperopt.Path.is_file", MagicMock(return_value=True)) unlinkmock = mocker.patch("freqtrade.optimize.hyperopt.Path.unlink", MagicMock()) - Hyperopt(default_conf) + Hyperopt(hyperopt_conf) assert unlinkmock.call_count == 0 assert log_has("Continuing on previous hyperopt results.", caplog) -def test_print_json_spaces_all(mocker, default_conf, caplog, capsys) -> None: +def test_print_json_spaces_all(mocker, hyperopt_conf, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) @@ -855,16 +872,12 @@ def test_print_json_spaces_all(mocker, default_conf, caplog, capsys) -> None: ) patch_exchange(mocker) - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'all', - 'hyperopt_jobs': 1, - 'print_json': True, - }) + hyperopt_conf.update({'spaces': 'all', + 'hyperopt_jobs': 1, + 'print_json': True, + }) - hyperopt = Hyperopt(default_conf) + hyperopt = Hyperopt(hyperopt_conf) hyperopt.backtesting.strategy.ohlcvdata_to_dataframe = MagicMock() hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={}) @@ -883,7 +896,7 @@ def test_print_json_spaces_all(mocker, default_conf, caplog, capsys) -> None: assert dumper.call_count == 2 -def test_print_json_spaces_default(mocker, default_conf, caplog, capsys) -> None: +def test_print_json_spaces_default(mocker, hyperopt_conf, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) @@ -913,16 +926,9 @@ def test_print_json_spaces_default(mocker, default_conf, caplog, capsys) -> None ) patch_exchange(mocker) - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'default', - 'hyperopt_jobs': 1, - 'print_json': True, - }) + hyperopt_conf.update({'print_json': True}) - hyperopt = Hyperopt(default_conf) + hyperopt = Hyperopt(hyperopt_conf) hyperopt.backtesting.strategy.ohlcvdata_to_dataframe = MagicMock() hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={}) @@ -937,7 +943,7 @@ def test_print_json_spaces_default(mocker, default_conf, caplog, capsys) -> None assert dumper.call_count == 2 -def test_print_json_spaces_roi_stoploss(mocker, default_conf, caplog, capsys) -> None: +def test_print_json_spaces_roi_stoploss(mocker, hyperopt_conf, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) @@ -963,16 +969,12 @@ def test_print_json_spaces_roi_stoploss(mocker, default_conf, caplog, capsys) -> ) patch_exchange(mocker) - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'roi stoploss', - 'hyperopt_jobs': 1, - 'print_json': True, - }) + hyperopt_conf.update({'spaces': 'roi stoploss', + 'hyperopt_jobs': 1, + 'print_json': True, + }) - hyperopt = Hyperopt(default_conf) + hyperopt = Hyperopt(hyperopt_conf) hyperopt.backtesting.strategy.ohlcvdata_to_dataframe = MagicMock() hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={}) @@ -987,7 +989,7 @@ def test_print_json_spaces_roi_stoploss(mocker, default_conf, caplog, capsys) -> assert dumper.call_count == 2 -def test_simplified_interface_roi_stoploss(mocker, default_conf, caplog, capsys) -> None: +def test_simplified_interface_roi_stoploss(mocker, hyperopt_conf, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) @@ -1012,14 +1014,9 @@ def test_simplified_interface_roi_stoploss(mocker, default_conf, caplog, capsys) ) patch_exchange(mocker) - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'roi stoploss', - 'hyperopt_jobs': 1, }) + hyperopt_conf.update({'spaces': 'roi stoploss'}) - hyperopt = Hyperopt(default_conf) + hyperopt = Hyperopt(hyperopt_conf) hyperopt.backtesting.strategy.ohlcvdata_to_dataframe = MagicMock() hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={}) @@ -1040,11 +1037,11 @@ def test_simplified_interface_roi_stoploss(mocker, default_conf, caplog, capsys) 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 hyperopt.max_open_trades == hyperopt_conf['max_open_trades'] assert hasattr(hyperopt, "position_stacking") -def test_simplified_interface_all_failed(mocker, default_conf, caplog, capsys) -> None: +def test_simplified_interface_all_failed(mocker, hyperopt_conf) -> None: mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) @@ -1055,14 +1052,9 @@ def test_simplified_interface_all_failed(mocker, default_conf, caplog, capsys) - patch_exchange(mocker) - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'all', - 'hyperopt_jobs': 1, }) + hyperopt_conf.update({'spaces': 'all', }) - hyperopt = Hyperopt(default_conf) + hyperopt = Hyperopt(hyperopt_conf) hyperopt.backtesting.strategy.ohlcvdata_to_dataframe = MagicMock() hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={}) @@ -1075,7 +1067,7 @@ def test_simplified_interface_all_failed(mocker, default_conf, caplog, capsys) - hyperopt.start() -def test_simplified_interface_buy(mocker, default_conf, caplog, capsys) -> None: +def test_simplified_interface_buy(mocker, hyperopt_conf, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) @@ -1100,14 +1092,9 @@ def test_simplified_interface_buy(mocker, default_conf, caplog, capsys) -> None: ) patch_exchange(mocker) - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'buy', - 'hyperopt_jobs': 1, }) + hyperopt_conf.update({'spaces': 'buy'}) - hyperopt = Hyperopt(default_conf) + hyperopt = Hyperopt(hyperopt_conf) hyperopt.backtesting.strategy.ohlcvdata_to_dataframe = MagicMock() hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={}) @@ -1128,11 +1115,11 @@ def test_simplified_interface_buy(mocker, default_conf, caplog, capsys) -> None: 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 hyperopt.max_open_trades == hyperopt_conf['max_open_trades'] assert hasattr(hyperopt, "position_stacking") -def test_simplified_interface_sell(mocker, default_conf, caplog, capsys) -> None: +def test_simplified_interface_sell(mocker, hyperopt_conf, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) @@ -1157,14 +1144,9 @@ def test_simplified_interface_sell(mocker, default_conf, caplog, capsys) -> None ) patch_exchange(mocker) - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'sell', - 'hyperopt_jobs': 1, }) + hyperopt_conf.update({'spaces': 'sell', }) - hyperopt = Hyperopt(default_conf) + hyperopt = Hyperopt(hyperopt_conf) hyperopt.backtesting.strategy.ohlcvdata_to_dataframe = MagicMock() hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={}) @@ -1185,7 +1167,7 @@ def test_simplified_interface_sell(mocker, default_conf, caplog, capsys) -> None 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 hyperopt.max_open_trades == hyperopt_conf['max_open_trades'] assert hasattr(hyperopt, "position_stacking") @@ -1195,7 +1177,7 @@ def test_simplified_interface_sell(mocker, default_conf, caplog, capsys) -> None ('sell_strategy_generator', 'sell'), ('sell_indicator_space', 'sell'), ]) -def test_simplified_interface_failed(mocker, default_conf, caplog, capsys, method, space) -> None: +def test_simplified_interface_failed(mocker, hyperopt_conf, method, space) -> None: mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) @@ -1206,14 +1188,9 @@ def test_simplified_interface_failed(mocker, default_conf, caplog, capsys, metho patch_exchange(mocker) - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': space, - 'hyperopt_jobs': 1, }) + hyperopt_conf.update({'spaces': space}) - hyperopt = Hyperopt(default_conf) + hyperopt = Hyperopt(hyperopt_conf) hyperopt.backtesting.strategy.ohlcvdata_to_dataframe = MagicMock() hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})