diff --git a/.travis.yml b/.travis.yml index 7a75a76c2..a45334dd6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,7 +32,7 @@ jobs: name: backtest - script: - cp config.json.example config.json - - freqtrade hyperopt --datadir tests/testdata -e 5 --strategy DefaultStrategy --customhyperopt DefaultHyperOpts --hyperopt-loss DefaultHyperOptLoss + - freqtrade hyperopt --datadir tests/testdata -e 5 --strategy DefaultStrategy --customhyperopt DefaultHyperOpts name: hyperopt - script: flake8 name: flake8 diff --git a/docs/bot-usage.md b/docs/bot-usage.md index fcf82826a..8f7e0bbcf 100644 --- a/docs/bot-usage.md +++ b/docs/bot-usage.md @@ -322,7 +322,8 @@ optional arguments: generate completely different results, since the target for optimization is different. Built-in Hyperopt-loss-functions are: DefaultHyperOptLoss, - OnlyProfitHyperOptLoss, SharpeHyperOptLoss. + OnlyProfitHyperOptLoss, SharpeHyperOptLoss (default: + `DefaultHyperOptLoss`). Common arguments: diff --git a/freqtrade/configuration/cli_options.py b/freqtrade/configuration/cli_options.py index 6928ddfdb..ee0d94023 100644 --- a/freqtrade/configuration/cli_options.py +++ b/freqtrade/configuration/cli_options.py @@ -231,8 +231,10 @@ AVAILABLE_CLI_OPTIONS = { help='Specify the class name of the hyperopt loss function class (IHyperOptLoss). ' 'Different functions can generate completely different results, ' 'since the target for optimization is different. Built-in Hyperopt-loss-functions are: ' - 'DefaultHyperOptLoss, OnlyProfitHyperOptLoss, SharpeHyperOptLoss.', + 'DefaultHyperOptLoss, OnlyProfitHyperOptLoss, SharpeHyperOptLoss ' + '(default: `%(default)s`).', metavar='NAME', + default=constants.DEFAULT_HYPEROPT_LOSS, ), # List exchanges "print_one_column": Arg( diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 2f490c900..b053519b0 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -9,6 +9,7 @@ PROCESS_THROTTLE_SECS = 5 # sec DEFAULT_TICKER_INTERVAL = 5 # min HYPEROPT_EPOCH = 100 # epochs RETRY_TIMEOUT = 30 # sec +DEFAULT_HYPEROPT_LOSS = 'DefaultHyperOptLoss' DEFAULT_DB_PROD_URL = 'sqlite:///tradesv3.sqlite' DEFAULT_DB_DRYRUN_URL = 'sqlite://' UNLIMITED_STAKE_AMOUNT = 'unlimited' diff --git a/freqtrade/resolvers/hyperopt_resolver.py b/freqtrade/resolvers/hyperopt_resolver.py index 45fe2548e..d1bc90e13 100644 --- a/freqtrade/resolvers/hyperopt_resolver.py +++ b/freqtrade/resolvers/hyperopt_resolver.py @@ -8,6 +8,7 @@ from pathlib import Path from typing import Optional, Dict from freqtrade import OperationalException +from freqtrade.constants import DEFAULT_HYPEROPT_LOSS from freqtrade.optimize.hyperopt_interface import IHyperOpt from freqtrade.optimize.hyperopt_loss_interface import IHyperOptLoss from freqtrade.resolvers import IResolver @@ -87,12 +88,9 @@ class HyperOptLossResolver(IResolver): """ config = config or {} - if not config.get('hyperopt_loss'): - raise OperationalException("No Hyperopt Loss Function set. Please use " - "`--hyperopt-loss` to specify " - "the Hyperopt Loss Function class to use.") - - hyperoptloss_name = config['hyperopt_loss'] + # Verify the hyperopt_loss is in the configuration, otherwise fallback to the + # default hyperopt loss + hyperoptloss_name = config.get('hyperopt_loss') or DEFAULT_HYPEROPT_LOSS self.hyperoptloss = self._load_hyperoptloss( hyperoptloss_name, config, extra_dir=config.get('hyperopt_path')) diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index cf211e35b..e1ee649c8 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -28,7 +28,6 @@ def hyperopt(default_conf, mocker): default_conf.update({ 'spaces': ['all'], 'hyperopt': 'DefaultHyperOpts', - 'hyperopt_loss': 'DefaultHyperOptLoss', }) patch_exchange(mocker) return Hyperopt(default_conf) @@ -75,7 +74,6 @@ def test_setup_hyperopt_configuration_without_arguments(mocker, default_conf, ca 'hyperopt', '--config', 'config.json', '--customhyperopt', 'DefaultHyperOpts', - '--hyperopt-loss', 'DefaultHyperOptLoss', ] config = setup_configuration(get_args(args), RunMode.HYPEROPT) @@ -108,7 +106,6 @@ def test_setup_hyperopt_configuration_with_arguments(mocker, default_conf, caplo 'hyperopt', '--config', 'config.json', '--customhyperopt', 'DefaultHyperOpts', - '--hyperopt-loss', 'DefaultHyperOptLoss', '--datadir', '/foo/bar', '--ticker-interval', '1m', '--timerange', ':100', @@ -164,7 +161,6 @@ def test_hyperoptresolver(mocker, default_conf, caplog) -> None: MagicMock(return_value=hyperopts(default_conf)) ) default_conf.update({'hyperopt': 'DefaultHyperOpts'}) - default_conf.update({'hyperopt_loss': 'DefaultHyperOptLoss'}) x = HyperOptResolver(default_conf).hyperopt assert not hasattr(x, 'populate_buy_trend') assert not hasattr(x, 'populate_sell_trend') @@ -197,7 +193,6 @@ def test_hyperoptlossresolver(mocker, default_conf, caplog) -> None: 'freqtrade.resolvers.hyperopt_resolver.HyperOptLossResolver._load_hyperoptloss', MagicMock(return_value=hl) ) - default_conf.update({'hyperopt_loss': 'DefaultHyperOptLoss'}) x = HyperOptLossResolver(default_conf).hyperoptloss assert hasattr(x, "hyperopt_loss_function") @@ -209,16 +204,6 @@ def test_hyperoptlossresolver_wrongname(mocker, default_conf, caplog) -> None: HyperOptLossResolver(default_conf).hyperopt -def test_hyperoptlossresolver_noname(default_conf): - default_conf.update({'hyperopt': 'DefaultHyperOpts'}) - default_conf['hyperopt_loss'] = '' - with pytest.raises(OperationalException, - match="No Hyperopt Loss Function set. Please use " - "`--hyperopt-loss` to specify " - "the Hyperopt Loss Function class to use."): - HyperOptLossResolver(default_conf) - - def test_start_not_installed(mocker, default_conf, caplog, import_fails) -> None: start_mock = MagicMock() patched_configuration_load_config_file(mocker, default_conf) @@ -230,7 +215,6 @@ def test_start_not_installed(mocker, default_conf, caplog, import_fails) -> None 'hyperopt', '--config', 'config.json', '--customhyperopt', 'DefaultHyperOpts', - '--hyperopt-loss', 'DefaultHyperOptLoss', '--epochs', '5' ] args = get_args(args) @@ -249,7 +233,6 @@ def test_start(mocker, default_conf, caplog) -> None: 'hyperopt', '--config', 'config.json', '--customhyperopt', 'DefaultHyperOpts', - '--hyperopt-loss', 'DefaultHyperOptLoss', '--epochs', '5' ] args = get_args(args) @@ -273,7 +256,6 @@ def test_start_no_data(mocker, default_conf, caplog) -> None: 'hyperopt', '--config', 'config.json', '--customhyperopt', 'DefaultHyperOpts', - '--hyperopt-loss', 'DefaultHyperOptLoss', '--epochs', '5' ] args = get_args(args) @@ -292,7 +274,6 @@ def test_start_filelock(mocker, default_conf, caplog) -> None: 'hyperopt', '--config', 'config.json', '--customhyperopt', 'DefaultHyperOpts', - '--hyperopt-loss', 'DefaultHyperOptLoss', '--epochs', '5' ] args = get_args(args) @@ -301,7 +282,6 @@ def test_start_filelock(mocker, default_conf, caplog) -> None: def test_loss_calculation_prefer_correct_trade_count(default_conf, hyperopt_results) -> None: - default_conf.update({'hyperopt_loss': 'DefaultHyperOptLoss'}) hl = HyperOptLossResolver(default_conf).hyperoptloss correct = hl.hyperopt_loss_function(hyperopt_results, 600) over = hl.hyperopt_loss_function(hyperopt_results, 600 + 100) @@ -314,7 +294,6 @@ def test_loss_calculation_prefer_shorter_trades(default_conf, hyperopt_results) resultsb = hyperopt_results.copy() resultsb.loc[1, 'trade_duration'] = 20 - default_conf.update({'hyperopt_loss': 'DefaultHyperOptLoss'}) hl = HyperOptLossResolver(default_conf).hyperoptloss longer = hl.hyperopt_loss_function(hyperopt_results, 100) shorter = hl.hyperopt_loss_function(resultsb, 100) @@ -327,7 +306,6 @@ def test_loss_calculation_has_limited_profit(default_conf, hyperopt_results) -> results_under = hyperopt_results.copy() results_under['profit_percent'] = hyperopt_results['profit_percent'] / 2 - default_conf.update({'hyperopt_loss': 'DefaultHyperOptLoss'}) hl = HyperOptLossResolver(default_conf).hyperoptloss correct = hl.hyperopt_loss_function(hyperopt_results, 600) over = hl.hyperopt_loss_function(results_over, 600) @@ -448,7 +426,6 @@ def test_start_calls_optimizer(mocker, default_conf, caplog, capsys) -> None: default_conf.update({'config': 'config.json.example', 'hyperopt': 'DefaultHyperOpts', - 'hyperopt_loss': 'DefaultHyperOptLoss', 'epochs': 1, 'timerange': None, 'spaces': 'all', @@ -554,7 +531,6 @@ def test_buy_strategy_generator(hyperopt, testdatadir) -> None: def test_generate_optimizer(mocker, default_conf) -> None: default_conf.update({'config': 'config.json.example', 'hyperopt': 'DefaultHyperOpts', - 'hyperopt_loss': 'DefaultHyperOptLoss', 'timerange': None, 'spaces': 'all', 'hyperopt_min_trades': 1, @@ -622,7 +598,6 @@ def test_clean_hyperopt(mocker, default_conf, caplog): patch_exchange(mocker) default_conf.update({'config': 'config.json.example', 'hyperopt': 'DefaultHyperOpts', - 'hyperopt_loss': 'DefaultHyperOptLoss', 'epochs': 1, 'timerange': None, 'spaces': 'all', @@ -640,7 +615,6 @@ def test_continue_hyperopt(mocker, default_conf, caplog): patch_exchange(mocker) default_conf.update({'config': 'config.json.example', 'hyperopt': 'DefaultHyperOpts', - 'hyperopt_loss': 'DefaultHyperOptLoss', 'epochs': 1, 'timerange': None, 'spaces': 'all', @@ -671,7 +645,6 @@ def test_print_json_spaces_all(mocker, default_conf, caplog, capsys) -> None: default_conf.update({'config': 'config.json.example', 'hyperopt': 'DefaultHyperOpts', - 'hyperopt_loss': 'DefaultHyperOptLoss', 'epochs': 1, 'timerange': None, 'spaces': 'all', @@ -710,7 +683,6 @@ def test_print_json_spaces_roi_stoploss(mocker, default_conf, caplog, capsys) -> default_conf.update({'config': 'config.json.example', 'hyperopt': 'DefaultHyperOpts', - 'hyperopt_loss': 'DefaultHyperOptLoss', 'epochs': 1, 'timerange': None, 'spaces': 'roi stoploss', @@ -750,7 +722,6 @@ def test_simplified_interface_roi_stoploss(mocker, default_conf, caplog, capsys) default_conf.update({'config': 'config.json.example', 'hyperopt': 'DefaultHyperOpts', - 'hyperopt_loss': 'DefaultHyperOptLoss', 'epochs': 1, 'timerange': None, 'spaces': 'roi stoploss', @@ -793,7 +764,6 @@ def test_simplified_interface_all_failed(mocker, default_conf, caplog, capsys) - default_conf.update({'config': 'config.json.example', 'hyperopt': 'DefaultHyperOpts', - 'hyperopt_loss': 'DefaultHyperOptLoss', 'epochs': 1, 'timerange': None, 'spaces': 'all', @@ -828,7 +798,6 @@ def test_simplified_interface_buy(mocker, default_conf, caplog, capsys) -> None: default_conf.update({'config': 'config.json.example', 'hyperopt': 'DefaultHyperOpts', - 'hyperopt_loss': 'DefaultHyperOptLoss', 'epochs': 1, 'timerange': None, 'spaces': 'buy', @@ -875,7 +844,6 @@ def test_simplified_interface_sell(mocker, default_conf, caplog, capsys) -> None default_conf.update({'config': 'config.json.example', 'hyperopt': 'DefaultHyperOpts', - 'hyperopt_loss': 'DefaultHyperOptLoss', 'epochs': 1, 'timerange': None, 'spaces': 'sell', @@ -924,7 +892,6 @@ def test_simplified_interface_failed(mocker, default_conf, caplog, capsys, metho default_conf.update({'config': 'config.json.example', 'hyperopt': 'DefaultHyperOpts', - 'hyperopt_loss': 'DefaultHyperOptLoss', 'epochs': 1, 'timerange': None, 'spaces': space,