diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index 3b27237da..15c13cec9 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -111,7 +111,7 @@ AVAILABLE_CLI_OPTIONS = { action='store_true', ), "dry_run_wallet": Arg( - '--dry-run-wallet', + '--dry-run-wallet', '--starting-balance', help='Starting balance, used for backtesting / hyperopt and dry-runs.', type=float, ), diff --git a/freqtrade/commands/optimize_commands.py b/freqtrade/commands/optimize_commands.py index bf36972c4..130743f68 100644 --- a/freqtrade/commands/optimize_commands.py +++ b/freqtrade/commands/optimize_commands.py @@ -4,6 +4,7 @@ from typing import Any, Dict from freqtrade import constants from freqtrade.configuration import setup_utils_configuration from freqtrade.exceptions import OperationalException +from freqtrade.misc import round_coin_value from freqtrade.state import RunMode @@ -22,9 +23,13 @@ def setup_optimize_configuration(args: Dict[str, Any], method: RunMode) -> Dict[ RunMode.BACKTEST: 'backtesting', RunMode.HYPEROPT: 'hyperoptimization', } - if (method in no_unlimited_runmodes.keys() and - config['stake_amount'] != constants.UNLIMITED_STAKE_AMOUNT and - config['max_open_trades'] != float('inf')): + if method in no_unlimited_runmodes.keys(): + if (config['stake_amount'] != constants.UNLIMITED_STAKE_AMOUNT + and config['stake_amount'] > config['dry_run_wallet']): + wallet = round_coin_value(config['dry_run_wallet'], config['stake_currency']) + stake = round_coin_value(config['stake_amount'], config['stake_currency']) + raise OperationalException(f"Starting balance ({wallet}) " + f"is smaller than stake_amount {stake}.") pass # config['dry_run_wallet'] = config['stake_amount'] * \ # config['max_open_trades'] * (2 - config['tradable_balance_ratio']) diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index 88447e490..a40a4fd83 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -214,9 +214,6 @@ class Configuration: self._args_to_config( config, argname='enable_protections', logstring='Parameter --enable-protections detected, enabling Protections. ...') - # Setting max_open_trades to infinite if -1 - if config.get('max_open_trades') == -1: - config['max_open_trades'] = float('inf') if 'use_max_market_positions' in self.args and not self.args["use_max_market_positions"]: config.update({'use_max_market_positions': False}) @@ -228,6 +225,9 @@ class Configuration: 'overriding max_open_trades to: %s ...', config.get('max_open_trades')) elif config['runmode'] in NON_UTIL_MODES: logger.info('Using max_open_trades: %s ...', config.get('max_open_trades')) + # Setting max_open_trades to infinite if -1 + if config.get('max_open_trades') == -1: + config['max_open_trades'] = float('inf') if self.args.get('stake_amount', None): # Convert explicitly to float to support CLI argument for both unlimited and value diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 9a4a3787a..13ffc1d25 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -128,7 +128,7 @@ class Backtesting: PairLocks.use_db = True Trade.use_db = True - def _set_strategy(self, strategy): + def _set_strategy(self, strategy: IStrategy): """ Load strategy into backtesting """ diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index 354b3f6b0..4bbfe8a78 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -9,7 +9,6 @@ import pandas as pd import pytest from arrow import Arrow -from freqtrade import constants from freqtrade.commands.optimize_commands import setup_optimize_configuration, start_backtesting from freqtrade.configuration import TimeRange from freqtrade.data import history @@ -232,8 +231,7 @@ def test_setup_bt_configuration_with_arguments(mocker, default_conf, caplog) -> assert log_has('Parameter --fee detected, setting fee to: {} ...'.format(config['fee']), caplog) -def test_setup_optimize_configuration_unlimited_stake_amount(mocker, default_conf, caplog) -> None: - default_conf['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT +def test_setup_optimize_configuration_stake_amount(mocker, default_conf, caplog) -> None: patched_configuration_load_config_file(mocker, default_conf) @@ -241,12 +239,23 @@ def test_setup_optimize_configuration_unlimited_stake_amount(mocker, default_con 'backtesting', '--config', 'config.json', '--strategy', 'DefaultStrategy', + '--stake-amount', '1', + '--starting-balance', '2' ] - # TODO: does this test still make sense? conf = setup_optimize_configuration(get_args(args), RunMode.BACKTEST) assert isinstance(conf, dict) + args = [ + 'backtesting', + '--config', 'config.json', + '--strategy', 'DefaultStrategy', + '--stake-amount', '1', + '--starting-balance', '0.5' + ] + with pytest.raises(OperationalException, match=r"Starting balance .* smaller .*"): + setup_optimize_configuration(get_args(args), RunMode.BACKTEST) + def test_start(mocker, fee, default_conf, caplog) -> None: start_mock = MagicMock() diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index 88a4cea2d..9ebdad2b5 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -12,7 +12,6 @@ import pytest from arrow import Arrow from filelock import Timeout -from freqtrade import constants from freqtrade.commands.optimize_commands import setup_optimize_configuration, start_hyperopt from freqtrade.data.history import load_data from freqtrade.exceptions import OperationalException @@ -130,8 +129,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) -> None: - default_conf['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT +def test_setup_hyperopt_configuration_stake_amount(mocker, default_conf) -> None: patched_configuration_load_config_file(mocker, default_conf) @@ -139,11 +137,22 @@ def test_setup_hyperopt_configuration_unlimited_stake_amount(mocker, default_con 'hyperopt', '--config', 'config.json', '--hyperopt', 'DefaultHyperOpt', + '--stake-amount', '1', + '--starting-balance', '2' ] - # TODO: does this test still make sense? conf = setup_optimize_configuration(get_args(args), RunMode.HYPEROPT) assert isinstance(conf, dict) + args = [ + 'hyperopt', + '--config', 'config.json', + '--strategy', 'DefaultStrategy', + '--stake-amount', '1', + '--starting-balance', '0.5' + ] + with pytest.raises(OperationalException, match=r"Starting balance .* smaller .*"): + setup_optimize_configuration(get_args(args), RunMode.HYPEROPT) + def test_hyperoptresolver(mocker, default_conf, caplog) -> None: patched_configuration_load_config_file(mocker, default_conf)