def test_hyperopt_with_arguments(mocker, default_conf, caplog) -> None: patched_configuration_load_config_file(mocker, default_conf) arglist = [ 'hyperopt', '--epochs', '10', '--spaces', 'all', ] args = Arguments(arglist).get_parsed_arg() configuration = Configuration(args, RunMode.HYPEROPT) config = configuration.get_config() assert 'epochs' in config assert int(config['epochs']) == 10 assert log_has( 'Parameter --epochs detected ... Will run Hyperopt with for 10 epochs ...', caplog) assert 'spaces' in config assert config['spaces'] == ['all'] assert log_has("Parameter -s/--spaces detected: ['all']", caplog) assert "runmode" in config assert config['runmode'] == RunMode.HYPEROPT
def test_main_reload_conf(mocker, default_conf, caplog) -> None: patch_exchange(mocker) mocker.patch('freqtrade.freqtradebot.FreqtradeBot.cleanup', MagicMock()) # Simulate Running, reload, running workflow worker_mock = MagicMock(side_effect=[ State.RUNNING, State.RELOAD_CONF, State.RUNNING, OperationalException("Oh snap!") ]) mocker.patch('freqtrade.worker.Worker._worker', worker_mock) patched_configuration_load_config_file(mocker, default_conf) reconfigure_mock = mocker.patch('freqtrade.main.Worker._reconfigure', MagicMock()) mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock()) mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock()) args = Arguments(['-c', 'config.json.example'], '').get_parsed_arg() worker = Worker(args=args, config=default_conf) with pytest.raises(SystemExit): main(['-c', 'config.json.example']) assert log_has('Using config: config.json.example ...', caplog) assert worker_mock.call_count == 4 assert reconfigure_mock.call_count == 1 assert isinstance(worker.freqtrade, FreqtradeBot)
def test_setup_configuration_without_arguments(mocker, default_conf, caplog) -> None: patched_configuration_load_config_file(mocker, default_conf) arglist = [ 'backtesting', '--config', 'config.json', '--strategy', 'DefaultStrategy', ] args = Arguments(arglist).get_parsed_arg() configuration = Configuration(args) config = configuration.get_config() assert 'max_open_trades' in config assert 'stake_currency' in config assert 'stake_amount' in config assert 'exchange' in config assert 'pair_whitelist' in config['exchange'] assert 'datadir' in config assert 'user_data_dir' in config assert log_has('Using data directory: {} ...'.format(config['datadir']), caplog) assert 'ticker_interval' in config assert not log_has('Parameter -i/--ticker-interval detected ...', caplog) assert 'position_stacking' not in config assert not log_has('Parameter --enable-position-stacking detected ...', caplog) assert 'timerange' not in config assert 'export' not in config
def test_load_config_combine_dicts(default_conf, mocker, caplog) -> None: conf1 = deepcopy(default_conf) conf2 = deepcopy(default_conf) del conf1['exchange']['key'] del conf1['exchange']['secret'] del conf2['exchange']['name'] conf2['exchange']['pair_whitelist'] += ['NANO/BTC'] config_files = [conf1, conf2] configsmock = MagicMock(side_effect=config_files) mocker.patch('freqtrade.configuration.configuration.load_config_file', configsmock) arg_list = [ '-c', 'test_conf.json', '--config', 'test2_conf.json', ] args = Arguments(arg_list, '').get_parsed_arg() configuration = Configuration(args) validated_conf = configuration.load_config() exchange_conf = default_conf['exchange'] assert validated_conf['exchange']['name'] == exchange_conf['name'] assert validated_conf['exchange']['key'] == exchange_conf['key'] assert validated_conf['exchange']['secret'] == exchange_conf['secret'] assert validated_conf['exchange']['pair_whitelist'] != conf1['exchange'][ 'pair_whitelist'] assert validated_conf['exchange']['pair_whitelist'] == conf2['exchange'][ 'pair_whitelist'] assert 'internals' in validated_conf assert log_has('Validating configuration ...', caplog)
def test__args_to_config(caplog): arg_list = ['trade', '--strategy-path', 'TestTest'] args = Arguments(arg_list).get_parsed_arg() configuration = Configuration(args) config = {} with warnings.catch_warnings(record=True) as w: # No warnings ... configuration._args_to_config(config, argname="strategy_path", logstring="DeadBeef") assert len(w) == 0 assert log_has("DeadBeef", caplog) assert config['strategy_path'] == "TestTest" configuration = Configuration(args) config = {} with warnings.catch_warnings(record=True) as w: # Deprecation warnings! configuration._args_to_config(config, argname="strategy_path", logstring="DeadBeef", deprecated_msg="Going away soon!") assert len(w) == 1 assert issubclass(w[-1].category, DeprecationWarning) assert "DEPRECATED: Going away soon!" in str(w[-1].message) assert log_has("DeadBeef", caplog) assert config['strategy_path'] == "TestTest"
def test_reconfigure(mocker, default_conf) -> None: patch_exchange(mocker) mocker.patch('freqtrade.freqtradebot.FreqtradeBot.cleanup', MagicMock()) mocker.patch('freqtrade.worker.Worker._worker', MagicMock(side_effect=OperationalException('Oh snap!'))) patched_configuration_load_config_file(mocker, default_conf) mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock()) mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock()) args = Arguments(['-c', 'config.json.example'], '').get_parsed_arg() worker = Worker(args=args, config=default_conf) freqtrade = worker.freqtrade # Renew mock to return modified data conf = deepcopy(default_conf) conf['stake_amount'] += 1 patched_configuration_load_config_file(mocker, conf) worker._config = conf # reconfigure should return a new instance worker._reconfigure() freqtrade2 = worker.freqtrade # Verify we have a new instance with the new config assert freqtrade is not freqtrade2 assert freqtrade.config['stake_amount'] + 1 == freqtrade2.config[ 'stake_amount']
def test_config_notallowed(mocker) -> None: mocker.patch.object(Path, "is_file", MagicMock(return_value=False)) args = [ 'create-userdir', ] pargs = Arguments(args).get_parsed_arg() assert pargs["config"] is None # When file exists: mocker.patch.object(Path, "is_file", MagicMock(return_value=True)) args = [ 'create-userdir', ] pargs = Arguments(args).get_parsed_arg() # config is not added even if it exists, since create-userdir is in the notallowed list assert pargs["config"] is None
def test_config_notrequired(mocker) -> None: mocker.patch.object(Path, "is_file", MagicMock(return_value=False)) args = [ 'download-data', ] pargs = Arguments(args).get_parsed_arg() assert pargs["config"] is None # When file exists: mocker.patch.object(Path, "is_file", MagicMock(return_value=True)) args = [ 'download-data', ] pargs = Arguments(args).get_parsed_arg() # config is added if it exists assert pargs["config"] == ['config.json']
def test_load_config(default_conf, mocker) -> None: patched_configuration_load_config_file(mocker, default_conf) args = Arguments(['trade']).get_parsed_arg() configuration = Configuration(args) validated_conf = configuration.load_config() assert validated_conf.get('strategy_path') is None assert 'edge' not in validated_conf
def test_plot_dataframe_options() -> None: args = [ '--indicators1', 'sma10,sma100', '--indicators2', 'macd,fastd,fastk', '--plot-limit', '30', '-p', 'UNITTEST/BTC', ] arguments = Arguments(args, '') arguments._build_args(ARGS_PLOT_DATAFRAME) pargs = arguments._parse_args() assert pargs.indicators1 == "sma10,sma100" assert pargs.indicators2 == "macd,fastd,fastk" assert pargs.plot_limit == 30 assert pargs.pairs == "UNITTEST/BTC"
def test_load_config_warn_forcebuy(default_conf, mocker, caplog) -> None: default_conf['forcebuy_enable'] = True patched_configuration_load_config_file(mocker, default_conf) args = Arguments(['trade']).get_parsed_arg() configuration = Configuration(args) validated_conf = configuration.load_config() assert validated_conf.get('forcebuy_enable') assert log_has('`forcebuy` RPC message enabled.', caplog)
def test_load_dry_run(default_conf, mocker, config_value, expected, arglist) -> None: default_conf['dry_run'] = config_value patched_configuration_load_config_file(mocker, default_conf) configuration = Configuration(Arguments(arglist).get_parsed_arg()) validated_conf = configuration.load_config() assert validated_conf.get('dry_run') is expected
def test_load_config_max_open_trades_zero(default_conf, mocker, caplog) -> None: default_conf['max_open_trades'] = 0 patched_configuration_load_config_file(mocker, default_conf) args = Arguments([], '').get_parsed_arg() configuration = Configuration(args) validated_conf = configuration.load_config() assert validated_conf['max_open_trades'] == 0 assert 'internals' in validated_conf assert log_has('Validating configuration ...', caplog.record_tuples)
def test_download_data_options() -> None: args = [ '--datadir', 'datadir/directory', 'download-data', '--pairs-file', 'file_with_pairs', '--days', '30', '--exchange', 'binance' ] pargs = Arguments(args).get_parsed_arg() assert pargs["pairs_file"] == 'file_with_pairs' assert pargs["datadir"] == 'datadir/directory' assert pargs["days"] == 30 assert pargs["exchange"] == 'binance'
def test_parse_args_hyperopt_custom() -> None: args = [ '-c', 'test_conf.json', 'hyperopt', '--epochs', '20', '--spaces', 'buy' ] call_args = Arguments(args, '').get_parsed_arg() assert call_args.config == ['test_conf.json'] assert call_args.epochs == 20 assert call_args.verbosity == 0 assert call_args.subparser == 'hyperopt' assert call_args.spaces == ['buy'] assert call_args.func is not None
def test_load_config_max_open_trades_zero(default_conf, mocker, caplog) -> None: default_conf['max_open_trades'] = 0 patched_configuration_load_config_file(mocker, default_conf) args = Arguments(['trade']).get_parsed_arg() configuration = Configuration(args) validated_conf = configuration.load_config() assert validated_conf['max_open_trades'] == 0 assert 'internals' in validated_conf
def test_parse_args_hyperopt_custom() -> None: args = [ '-c', 'test_conf.json', 'hyperopt', '--epochs', '20', '--spaces', 'buy' ] call_args = Arguments(args).get_parsed_arg() assert call_args["config"] == ['test_conf.json'] assert call_args["epochs"] == 20 assert call_args["verbosity"] == 0 assert call_args["subparser"] == 'hyperopt' assert call_args["spaces"] == ['buy'] assert call_args["func"] is not None assert callable(call_args["func"])
def test_plot_profit_options() -> None: args = [ 'plot-profit', '-p', 'UNITTEST/BTC', '--trade-source', 'DB', "--db-url", "sqlite:///whatever.sqlite", ] pargs = Arguments(args).get_parsed_arg() assert pargs["trade_source"] == "DB" assert pargs["pairs"] == ["UNITTEST/BTC"] assert pargs["db_url"] == "sqlite:///whatever.sqlite"
def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> None: patched_configuration_load_config_file(mocker, default_conf) mocker.patch('freqtrade.configuration.configuration.create_datadir', lambda c, x: x) mocker.patch('freqtrade.configuration.configuration.create_userdata_dir', lambda x, *args, **kwargs: Path(x)) arglist = [ '--config', 'config.json', '--strategy', 'DefaultStrategy', '--datadir', '/foo/bar', '--userdir', "/tmp/freqtrade", 'backtesting', '--ticker-interval', '1m', '--enable-position-stacking', '--disable-max-market-positions', '--refresh-pairs-cached', '--timerange', ':100', '--export', '/bar/foo' ] args = Arguments(arglist, '').get_parsed_arg() configuration = Configuration(args) config = configuration.get_config() assert 'max_open_trades' in config assert 'stake_currency' in config assert 'stake_amount' in config assert 'exchange' in config assert 'pair_whitelist' in config['exchange'] assert 'datadir' in config assert log_has('Using data directory: {} ...'.format("/foo/bar"), caplog) assert log_has( 'Using user-data directory: {} ...'.format("/tmp/freqtrade"), caplog) assert 'user_data_dir' in config assert 'ticker_interval' in config assert log_has( 'Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...', caplog) assert 'position_stacking' in config assert log_has('Parameter --enable-position-stacking detected ...', caplog) assert 'use_max_market_positions' in config assert log_has('Parameter --disable-max-market-positions detected ...', caplog) assert log_has('max_open_trades set to unlimited ...', caplog) assert 'refresh_pairs' in config assert log_has('Parameter -r/--refresh-pairs-cached detected ...', caplog) assert 'timerange' in config assert log_has( 'Parameter --timerange detected: {} ...'.format(config['timerange']), caplog) assert 'export' in config assert log_has( 'Parameter --export detected: {} ...'.format(config['export']), caplog)
def test_parse_args_backtesting_custom() -> None: args = [ '-c', 'test_conf.json', 'backtesting', '--ticker-interval', '1m', '--strategy-list', 'DefaultStrategy', 'SampleStrategy' ] call_args = Arguments(args).get_parsed_arg() assert call_args["config"] == ['test_conf.json'] assert call_args["verbosity"] == 0 assert call_args["subparser"] == 'backtesting' assert call_args["func"] is not None assert call_args["ticker_interval"] == '1m' assert type(call_args["strategy_list"]) is list assert len(call_args["strategy_list"]) == 2
def test_load_config_max_open_trades_minus_one(default_conf, mocker, caplog) -> None: default_conf['max_open_trades'] = -1 patched_configuration_load_config_file(mocker, default_conf) args = Arguments(['trade']).get_parsed_arg() configuration = Configuration(args) validated_conf = configuration.load_config() assert validated_conf['max_open_trades'] > 999999999 assert validated_conf['max_open_trades'] == float('inf') assert "runmode" in validated_conf assert validated_conf['runmode'] == RunMode.DRY_RUN
def test_pairlist_resolving(): arglist = [ 'download-data', '--pairs', 'ETH/BTC', 'XRP/BTC', '--exchange', 'binance' ] args = Arguments(arglist).get_parsed_arg() configuration = Configuration(args, RunMode.OTHER) config = configuration.get_config() assert config['pairs'] == ['ETH/BTC', 'XRP/BTC'] assert config['exchange']['name'] == 'binance'
def test_cli_verbose_with_params(default_conf, mocker, caplog) -> None: patched_configuration_load_config_file(mocker, default_conf) # Prevent setting loggers mocker.patch('freqtrade.loggers._set_loggers', MagicMock) arglist = ['trade', '-vvv'] args = Arguments(arglist).get_parsed_arg() configuration = Configuration(args) validated_conf = configuration.load_config() assert validated_conf.get('verbosity') == 3 assert log_has('Verbosity set to 3', caplog)
def test_load_custom_strategy(default_conf, mocker) -> None: default_conf.update({ 'strategy': 'CustomStrategy', 'strategy_path': '/tmp/strategies', }) patched_configuration_load_config_file(mocker, default_conf) args = Arguments(['trade']).get_parsed_arg() configuration = Configuration(args) validated_conf = configuration.load_config() assert validated_conf.get('strategy') == 'CustomStrategy' assert validated_conf.get('strategy_path') == '/tmp/strategies'
def test_show_info(default_conf, mocker, caplog) -> None: patched_configuration_load_config_file(mocker, default_conf) arglist = [ '--strategy', 'TestStrategy', '--db-url', 'sqlite:///tmp/testdb', ] args = Arguments(arglist, '').get_parsed_arg() configuration = Configuration(args) configuration.get_config() assert log_has('Using DB: "sqlite:///tmp/testdb"', caplog.record_tuples) assert log_has('Dry run is enabled', caplog.record_tuples)
def test_set_logfile(default_conf, mocker): patched_configuration_load_config_file(mocker, default_conf) arglist = [ '--logfile', 'test_file.log', ] args = Arguments(arglist, '').get_parsed_arg() configuration = Configuration(args) validated_conf = configuration.load_config() assert validated_conf['logfile'] == "test_file.log" f = Path("test_file.log") assert f.is_file() f.unlink()
def test_download_data_options() -> None: args = [ '--datadir', 'datadir/directory', 'download-data', '--pairs-file', 'file_with_pairs', '--days', '30', '--exchange', 'binance' ] args = Arguments(args, '').get_parsed_arg() assert args.pairs_file == 'file_with_pairs' assert args.datadir == 'datadir/directory' assert args.days == 30 assert args.exchange == 'binance'
def test_pairlist_resolving_fallback(mocker): mocker.patch.object(Path, "exists", MagicMock(return_value=True)) mocker.patch.object(Path, "open", MagicMock(return_value=MagicMock())) mocker.patch("freqtrade.configuration.configuration.json_load", MagicMock(return_value=['XRP/BTC', 'ETH/BTC'])) arglist = ['download-data', '--exchange', 'binance'] args = Arguments(arglist, '').get_parsed_arg() configuration = Configuration(args) config = configuration.get_config() assert config['pairs'] == ['ETH/BTC', 'XRP/BTC'] assert config['exchange']['name'] == 'binance'
def main(sysargv: List[str] = None) -> None: """ This function will initiate the bot and start the trading loop. :return: None """ return_code: Any = 1 worker = None try: arguments = Arguments(sysargv, 'Free, open source crypto trading bot') args: Namespace = arguments.get_parsed_arg() # A subcommand has been issued. # Means if Backtesting or Hyperopt have been called we exit the bot if hasattr(args, 'func'): args.func(args) # TODO: fetch return_code as returned by the command function here return_code = 0 else: # Load and run worker worker = Worker(args) worker.run() except SystemExit as e: return_code = e except KeyboardInterrupt: logger.info('SIGINT received, aborting ...') return_code = 0 except OperationalException as e: logger.error(str(e)) return_code = 2 except Exception: logger.exception('Fatal exception!') finally: if worker: worker.exit() sys.exit(return_code)
def test_setup_configuration_with_stratlist(mocker, default_conf, caplog) -> None: """ Test setup_configuration() function """ patched_configuration_load_config_file(mocker, default_conf) arglist = [ '--config', 'config.json', 'backtesting', '--ticker-interval', '1m', '--export', '/bar/foo', '--strategy-list', 'DefaultStrategy', 'TestStrategy' ] args = Arguments(arglist, '').get_parsed_arg() configuration = Configuration(args, RunMode.BACKTEST) config = configuration.get_config() assert config['runmode'] == RunMode.BACKTEST assert 'max_open_trades' in config assert 'stake_currency' in config assert 'stake_amount' in config assert 'exchange' in config assert 'pair_whitelist' in config['exchange'] assert 'datadir' in config assert log_has( 'Using data directory: {} ...'.format(config['datadir']), caplog.record_tuples ) assert 'ticker_interval' in config assert log_has('Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...', caplog.record_tuples) assert 'strategy_list' in config assert log_has('Using strategy list of 2 Strategies', caplog.record_tuples) assert 'position_stacking' not in config assert 'use_max_market_positions' not in config assert 'timerange' not in config assert 'export' in config assert log_has( 'Parameter --export detected: {} ...'.format(config['export']), caplog.record_tuples )