From d6c66a54fd8f5b9712e3472ccd827c37043a8359 Mon Sep 17 00:00:00 2001 From: orehunt Date: Tue, 3 Mar 2020 07:57:13 +0100 Subject: [PATCH] deformat --- freqtrade/commands/arguments.py | 116 ++-- freqtrade/commands/cli_options.py | 291 +++------ freqtrade/configuration/configuration.py | 164 ++--- freqtrade/constants.py | 403 +++--------- freqtrade/optimize/hyperopt.py | 103 ++- setup.cfg | 4 - tests/optimize/test_hyperopt.py | 784 ++++++++++------------- 7 files changed, 726 insertions(+), 1139 deletions(-) diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index da5015f73..323a556f8 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -15,7 +15,8 @@ ARGS_STRATEGY = ["strategy", "strategy_path"] ARGS_TRADE = ["db_url", "sd_notify", "dry_run"] -ARGS_COMMON_OPTIMIZE = ["ticker_interval", "timerange", "max_open_trades", "stake_amount", "fee"] +ARGS_COMMON_OPTIMIZE = ["ticker_interval", "timerange", + "max_open_trades", "stake_amount", "fee"] ARGS_BACKTEST = ARGS_COMMON_OPTIMIZE + [ "position_stacking", "use_max_market_positions", "strategy_list", "export", "exportfilename" @@ -38,10 +39,8 @@ ARGS_LIST_EXCHANGES = ["print_one_column", "list_exchanges_all"] ARGS_LIST_TIMEFRAMES = ["exchange", "print_one_column"] -ARGS_LIST_PAIRS = [ - "exchange", "print_list", "list_pairs_print_json", "print_one_column", "print_csv", - "base_currencies", "quote_currencies", "list_pairs_all" -] +ARGS_LIST_PAIRS = ["exchange", "print_list", "list_pairs_print_json", "print_one_column", + "print_csv", "base_currencies", "quote_currencies", "list_pairs_all"] ARGS_TEST_PAIRLIST = ["config", "quote_currencies", "print_one_column", "list_pairs_print_json"] @@ -56,38 +55,30 @@ ARGS_BUILD_HYPEROPT = ["user_data_dir", "hyperopt", "template"] ARGS_CONVERT_DATA = ["pairs", "format_from", "format_to", "erase"] ARGS_CONVERT_DATA_OHLCV = ARGS_CONVERT_DATA + ["timeframes"] -ARGS_DOWNLOAD_DATA = [ - "pairs", "pairs_file", "days", "download_trades", "exchange", "timeframes", "erase", - "dataformat_ohlcv", "dataformat_trades" -] +ARGS_DOWNLOAD_DATA = ["pairs", "pairs_file", "days", "download_trades", "exchange", + "timeframes", "erase", "dataformat_ohlcv", "dataformat_trades"] -ARGS_PLOT_DATAFRAME = [ - "pairs", "indicators1", "indicators2", "plot_limit", "db_url", "trade_source", "export", - "exportfilename", "timerange", "ticker_interval" -] +ARGS_PLOT_DATAFRAME = ["pairs", "indicators1", "indicators2", "plot_limit", + "db_url", "trade_source", "export", "exportfilename", + "timerange", "ticker_interval"] -ARGS_PLOT_PROFIT = [ - "pairs", "timerange", "export", "exportfilename", "db_url", "trade_source", "ticker_interval" -] +ARGS_PLOT_PROFIT = ["pairs", "timerange", "export", "exportfilename", "db_url", + "trade_source", "ticker_interval"] -ARGS_HYPEROPT_LIST = [ - "hyperopt_list_best", "hyperopt_list_profitable", "hyperopt_list_min_trades", - "hyperopt_list_max_trades", "hyperopt_list_min_avg_time", "hyperopt_list_max_avg_time", - "hyperopt_list_min_avg_profit", "hyperopt_list_max_avg_profit", - "hyperopt_list_min_total_profit", "hyperopt_list_max_total_profit", "print_colorized", - "print_json", "hyperopt_list_no_details" -] +ARGS_HYPEROPT_LIST = ["hyperopt_list_best", "hyperopt_list_profitable", + "hyperopt_list_min_trades", "hyperopt_list_max_trades", + "hyperopt_list_min_avg_time", "hyperopt_list_max_avg_time", + "hyperopt_list_min_avg_profit", "hyperopt_list_max_avg_profit", + "hyperopt_list_min_total_profit", "hyperopt_list_max_total_profit", + "print_colorized", "print_json", "hyperopt_list_no_details"] -ARGS_HYPEROPT_SHOW = [ - "hyperopt_list_best", "hyperopt_list_profitable", "hyperopt_show_index", "print_json", - "hyperopt_show_no_header" -] +ARGS_HYPEROPT_SHOW = ["hyperopt_list_best", "hyperopt_list_profitable", "hyperopt_show_index", + "print_json", "hyperopt_show_no_header"] -NO_CONF_REQURIED = [ - "convert-data", "convert-trade-data", "download-data", "list-timeframes", "list-markets", - "list-pairs", "list-strategies", "list-hyperopts", "hyperopt-list", "hyperopt-show", - "plot-dataframe", "plot-profit" -] +NO_CONF_REQURIED = ["convert-data", "convert-trade-data", "download-data", "list-timeframes", + "list-markets", "list-pairs", "list-strategies", + "list-hyperopts", "hyperopt-list", "hyperopt-show", + "plot-dataframe", "plot-profit"] NO_CONF_ALLOWED = ["create-userdir", "list-exchanges", "new-hyperopt", "new-strategy"] @@ -96,6 +87,7 @@ class Arguments: """ Arguments Class. Manage the arguments received by the cli """ + def __init__(self, args: Optional[List[str]]) -> None: self.args = args self._parsed_arg: Optional[argparse.Namespace] = None @@ -164,70 +156,70 @@ class Arguments: self.parser = argparse.ArgumentParser(description='Free, open source crypto trading bot') self._build_args(optionlist=['version'], parser=self.parser) - from freqtrade.commands import ( - start_create_userdir, start_convert_data, start_download_data, start_hyperopt_list, - start_hyperopt_show, start_list_exchanges, start_list_hyperopts, start_list_markets, - start_list_strategies, start_list_timeframes, start_new_config, start_new_hyperopt, - start_new_strategy, start_plot_dataframe, start_plot_profit, start_backtesting, - start_hyperopt, start_edge, start_test_pairlist, start_trading) + from freqtrade.commands import (start_create_userdir, start_convert_data, + start_download_data, + start_hyperopt_list, start_hyperopt_show, + start_list_exchanges, start_list_hyperopts, + start_list_markets, start_list_strategies, + start_list_timeframes, start_new_config, + start_new_hyperopt, start_new_strategy, + start_plot_dataframe, start_plot_profit, + start_backtesting, start_hyperopt, start_edge, + start_test_pairlist, start_trading) - subparsers = self.parser.add_subparsers( - dest='command', - # Use custom message when no subhandler is added - # shown from `main.py` - # required=True - ) + subparsers = self.parser.add_subparsers(dest='command', + # Use custom message when no subhandler is added + # shown from `main.py` + # required=True + ) # Add trade subcommand - trade_cmd = subparsers.add_parser('trade', - help='Trade module.', + trade_cmd = subparsers.add_parser('trade', help='Trade module.', parents=[_common_parser, _strategy_parser]) trade_cmd.set_defaults(func=start_trading) self._build_args(optionlist=ARGS_TRADE, parser=trade_cmd) # Add backtesting subcommand - backtesting_cmd = subparsers.add_parser('backtesting', - help='Backtesting module.', + backtesting_cmd = subparsers.add_parser('backtesting', help='Backtesting module.', parents=[_common_parser, _strategy_parser]) backtesting_cmd.set_defaults(func=start_backtesting) self._build_args(optionlist=ARGS_BACKTEST, parser=backtesting_cmd) # Add edge subcommand - edge_cmd = subparsers.add_parser('edge', - help='Edge module.', + edge_cmd = subparsers.add_parser('edge', help='Edge module.', parents=[_common_parser, _strategy_parser]) edge_cmd.set_defaults(func=start_edge) self._build_args(optionlist=ARGS_EDGE, parser=edge_cmd) # Add hyperopt subcommand - hyperopt_cmd = subparsers.add_parser( - 'hyperopt', - help='Hyperopt module.', - parents=[_common_parser, _strategy_parser], - ) + hyperopt_cmd = subparsers.add_parser('hyperopt', help='Hyperopt module.', + parents=[_common_parser, _strategy_parser], + ) hyperopt_cmd.set_defaults(func=start_hyperopt) self._build_args(optionlist=ARGS_HYPEROPT, parser=hyperopt_cmd) # add create-userdir subcommand - create_userdir_cmd = subparsers.add_parser( - 'create-userdir', - help="Create user-data directory.", - ) + create_userdir_cmd = subparsers.add_parser('create-userdir', + help="Create user-data directory.", + ) create_userdir_cmd.set_defaults(func=start_create_userdir) self._build_args(optionlist=ARGS_CREATE_USERDIR, parser=create_userdir_cmd) # add new-config subcommand - build_config_cmd = subparsers.add_parser('new-config', help="Create new config") + build_config_cmd = subparsers.add_parser('new-config', + help="Create new config") build_config_cmd.set_defaults(func=start_new_config) self._build_args(optionlist=ARGS_BUILD_CONFIG, parser=build_config_cmd) # add new-strategy subcommand - build_strategy_cmd = subparsers.add_parser('new-strategy', help="Create new strategy") + build_strategy_cmd = subparsers.add_parser('new-strategy', + help="Create new strategy") build_strategy_cmd.set_defaults(func=start_new_strategy) self._build_args(optionlist=ARGS_BUILD_STRATEGY, parser=build_strategy_cmd) # add new-hyperopt subcommand - build_hyperopt_cmd = subparsers.add_parser('new-hyperopt', help="Create new hyperopt") + build_hyperopt_cmd = subparsers.add_parser('new-hyperopt', + help="Create new hyperopt") build_hyperopt_cmd.set_defaults(func=start_new_hyperopt) self._build_args(optionlist=ARGS_BUILD_HYPEROPT, parser=build_hyperopt_cmd) diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index acb629cf9..0aac462dd 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -13,7 +13,8 @@ def check_int_positive(value: str) -> int: raise ValueError except ValueError: raise ArgumentTypeError( - f"{value} is invalid for this parameter, should be a positive integer value") + f"{value} is invalid for this parameter, should be a positive integer value" + ) return uint @@ -24,7 +25,8 @@ def check_int_nonzero(value: str) -> int: raise ValueError except ValueError: raise ArgumentTypeError( - f"{value} is invalid for this parameter, should be a non-zero integer value") + f"{value} is invalid for this parameter, should be a non-zero integer value" + ) return uint @@ -38,32 +40,25 @@ class Arg: # List of available command line options AVAILABLE_CLI_OPTIONS = { # Common options - "verbosity": - Arg( - '-v', - '--verbose', + "verbosity": Arg( + '-v', '--verbose', help='Verbose mode (-vv for more, -vvv to get all messages).', action='count', default=0, ), - "logfile": - Arg( + "logfile": Arg( '--logfile', help="Log to the file specified. Special values are: 'syslog', 'journald'. " - "See the documentation for more details.", + "See the documentation for more details.", metavar='FILE', ), - "version": - Arg( - '-V', - '--version', + "version": Arg( + '-V', '--version', action='version', version=f'%(prog)s {__version__}', ), - "config": - Arg( - '-c', - '--config', + "config": Arg( + '-c', '--config', help=f'Specify configuration file (default: `userdir/{constants.DEFAULT_CONFIG}` ' f'or `config.json` whichever exists). ' f'Multiple --config options may be used. ' @@ -71,105 +66,84 @@ AVAILABLE_CLI_OPTIONS = { action='append', metavar='PATH', ), - "datadir": - Arg( - '-d', - '--datadir', + "datadir": Arg( + '-d', '--datadir', help='Path to directory with historical backtesting data.', metavar='PATH', ), - "user_data_dir": - Arg( - '--userdir', - '--user-data-dir', + "user_data_dir": Arg( + '--userdir', '--user-data-dir', help='Path to userdata directory.', metavar='PATH', ), - "reset": - Arg( + "reset": Arg( '--reset', help='Reset sample files to their original state.', action='store_true', ), # Main options - "strategy": - Arg( - '-s', - '--strategy', + "strategy": Arg( + '-s', '--strategy', help='Specify strategy class name which will be used by the bot.', metavar='NAME', ), - "strategy_path": - Arg( + "strategy_path": Arg( '--strategy-path', help='Specify additional strategy lookup path.', metavar='PATH', ), - "db_url": - Arg( + "db_url": Arg( '--db-url', help=f'Override trades database URL, this is useful in custom deployments ' f'(default: `{constants.DEFAULT_DB_PROD_URL}` for Live Run mode, ' f'`{constants.DEFAULT_DB_DRYRUN_URL}` for Dry Run).', metavar='PATH', ), - "sd_notify": - Arg( + "sd_notify": Arg( '--sd-notify', help='Notify systemd service manager.', action='store_true', ), - "dry_run": - Arg( + "dry_run": Arg( '--dry-run', help='Enforce dry-run for trading (removes Exchange secrets and simulates trades).', action='store_true', ), # Optimize common - "ticker_interval": - Arg( - '-i', - '--ticker-interval', + "ticker_interval": Arg( + '-i', '--ticker-interval', help='Specify ticker interval (`1m`, `5m`, `30m`, `1h`, `1d`).', ), - "timerange": - Arg( + "timerange": Arg( '--timerange', help='Specify what timerange of data to use.', ), - "max_open_trades": - Arg( + "max_open_trades": Arg( '--max-open-trades', help='Override the value of the `max_open_trades` configuration setting.', type=int, metavar='INT', ), - "stake_amount": - Arg( + "stake_amount": Arg( '--stake-amount', help='Override the value of the `stake_amount` configuration setting.', type=float, ), # Backtesting - "position_stacking": - Arg( - '--eps', - '--enable-position-stacking', + "position_stacking": Arg( + '--eps', '--enable-position-stacking', help='Allow buying the same pair multiple times (position stacking).', action='store_true', default=False, ), - "use_max_market_positions": - Arg( - '--dmmp', - '--disable-max-market-positions', + "use_max_market_positions": Arg( + '--dmmp', '--disable-max-market-positions', help='Disable applying `max_open_trades` during backtest ' '(same as setting `max_open_trades` to a very high number).', action='store_false', default=True, ), - "strategy_list": - Arg( + "strategy_list": Arg( '--strategy-list', help='Provide a space-separated list of strategies to backtest. ' 'Please note that ticker-interval needs to be set either in config ' @@ -178,52 +152,44 @@ AVAILABLE_CLI_OPTIONS = { '(so `backtest-data.json` becomes `backtest-data-DefaultStrategy.json`', nargs='+', ), - "export": - Arg( + "export": Arg( '--export', help='Export backtest results, argument are: trades. ' 'Example: `--export=trades`', ), - "exportfilename": - Arg( + "exportfilename": Arg( '--export-filename', help='Save backtest results to the file with this filename. ' 'Requires `--export` to be set as well. ' 'Example: `--export-filename=user_data/backtest_results/backtest_today.json`', metavar='PATH', ), - "fee": - Arg( + "fee": Arg( '--fee', help='Specify fee ratio. Will be applied twice (on trade entry and exit).', type=float, metavar='FLOAT', ), # Edge - "stoploss_range": - Arg( + "stoploss_range": Arg( '--stoplosses', help='Defines a range of stoploss values against which edge will assess the strategy. ' 'The format is "min,max,step" (without any space). ' 'Example: `--stoplosses=-0.01,-0.1,-0.001`', ), # Hyperopt - "hyperopt": - Arg( + "hyperopt": Arg( '--hyperopt', help='Specify hyperopt class name which will be used by the bot.', metavar='NAME', ), - "hyperopt_path": - Arg( + "hyperopt_path": Arg( '--hyperopt-path', help='Specify additional lookup path for Hyperopt and Hyperopt Loss functions.', metavar='PATH', ), - "epochs": - Arg( - '-e', - '--epochs', + "epochs": Arg( + '-e', '--epochs', help='Specify number of epochs (default: %(default)d).', type=check_int_positive, metavar='INT', @@ -260,32 +226,27 @@ AVAILABLE_CLI_OPTIONS = { nargs='+', default='default', ), - "print_all": - Arg( + "print_all": Arg( '--print-all', help='Print all results, not only the best ones.', action='store_true', default=False, ), - "print_colorized": - Arg( + "print_colorized": Arg( '--no-color', help='Disable colorization of hyperopt results. May be useful if you are ' 'redirecting output to a file.', action='store_false', default=True, ), - "print_json": - Arg( + "print_json": Arg( '--print-json', help='Print best result detailization in JSON format.', action='store_true', default=False, ), - "hyperopt_jobs": - Arg( - '-j', - '--job-workers', + "hyperopt_jobs": Arg( + '-j', '--job-workers', help='The number of concurrently running jobs for hyperoptimization ' '(hyperopt worker processes). ' 'If -1 (default), all CPUs are used, for -2, all CPUs but one are used, etc. ' @@ -294,15 +255,13 @@ AVAILABLE_CLI_OPTIONS = { metavar='JOBS', default=-1, ), - "hyperopt_random_state": - Arg( + "hyperopt_random_state": Arg( '--random-state', help='Set random state to some positive integer for reproducible hyperopt results.', type=check_int_positive, metavar='INT', ), - "hyperopt_min_trades": - Arg( + "hyperopt_min_trades": Arg( '--min-trades', help="Set minimal desired number of trades for evaluations in the hyperopt " "optimization path (default: 1).", @@ -310,16 +269,14 @@ AVAILABLE_CLI_OPTIONS = { metavar='INT', default=1, ), - "hyperopt_continue": - Arg( + "hyperopt_continue": Arg( "--continue", help="Continue hyperopt from previous runs. " "By default, temporary files will be removed and hyperopt will start from scratch.", default=False, action='store_true', ), - "hyperopt_loss": - Arg( + "hyperopt_loss": Arg( '--hyperopt-loss', help='Specify the class name of the hyperopt loss function class (IHyperOptLoss). ' 'Different functions can generate completely different results, ' @@ -331,143 +288,121 @@ AVAILABLE_CLI_OPTIONS = { default=constants.DEFAULT_HYPEROPT_LOSS, ), # List exchanges - "print_one_column": - Arg( - '-1', - '--one-column', + "print_one_column": Arg( + '-1', '--one-column', help='Print output in one column.', action='store_true', ), - "list_exchanges_all": - Arg( - '-a', - '--all', + "list_exchanges_all": Arg( + '-a', '--all', help='Print all exchanges known to the ccxt library.', action='store_true', ), # List pairs / markets - "list_pairs_all": - Arg( - '-a', - '--all', + "list_pairs_all": Arg( + '-a', '--all', help='Print all pairs or market symbols. By default only active ' - 'ones are shown.', + 'ones are shown.', action='store_true', ), - "print_list": - Arg( + "print_list": Arg( '--print-list', help='Print list of pairs or market symbols. By default data is ' - 'printed in the tabular format.', + 'printed in the tabular format.', action='store_true', ), - "list_pairs_print_json": - Arg( + "list_pairs_print_json": Arg( '--print-json', help='Print list of pairs or market symbols in JSON format.', action='store_true', default=False, ), - "print_csv": - Arg( + "print_csv": Arg( '--print-csv', help='Print exchange pair or market data in the csv format.', action='store_true', ), - "quote_currencies": - Arg( + "quote_currencies": Arg( '--quote', help='Specify quote currency(-ies). Space-separated list.', nargs='+', metavar='QUOTE_CURRENCY', ), - "base_currencies": - Arg( + "base_currencies": Arg( '--base', help='Specify base currency(-ies). Space-separated list.', nargs='+', metavar='BASE_CURRENCY', ), # Script options - "pairs": - Arg( - '-p', - '--pairs', + "pairs": Arg( + '-p', '--pairs', help='Show profits for only these pairs. Pairs are space-separated.', nargs='+', ), # Download data - "pairs_file": - Arg( + "pairs_file": Arg( '--pairs-file', help='File containing a list of pairs to download.', metavar='FILE', ), - "days": - Arg( + "days": Arg( '--days', help='Download data for given number of days.', type=check_int_positive, metavar='INT', ), - "download_trades": - Arg( + "download_trades": Arg( '--dl-trades', help='Download trades instead of OHLCV data. The bot will resample trades to the ' - 'desired timeframe as specified as --timeframes/-t.', + 'desired timeframe as specified as --timeframes/-t.', action='store_true', ), - "format_from": - Arg( + "format_from": Arg( '--format-from', help='Source format for data conversion.', choices=constants.AVAILABLE_DATAHANDLERS, required=True, ), - "format_to": - Arg( + "format_to": Arg( '--format-to', help='Destination format for data conversion.', choices=constants.AVAILABLE_DATAHANDLERS, required=True, ), - "dataformat_ohlcv": - Arg('--data-format-ohlcv', + "dataformat_ohlcv": Arg( + '--data-format-ohlcv', help='Storage format for downloaded ohlcv data. (default: `%(default)s`).', choices=constants.AVAILABLE_DATAHANDLERS, - default='json'), - "dataformat_trades": - Arg('--data-format-trades', + default='json' + ), + "dataformat_trades": Arg( + '--data-format-trades', help='Storage format for downloaded trades data. (default: `%(default)s`).', choices=constants.AVAILABLE_DATAHANDLERS, - default='jsongz'), - "exchange": - Arg( + default='jsongz' + ), + "exchange": Arg( '--exchange', help=f'Exchange name (default: `{constants.DEFAULT_EXCHANGE}`). ' f'Only valid if no config is provided.', ), - "timeframes": - Arg( - '-t', - '--timeframes', + "timeframes": Arg( + '-t', '--timeframes', help=f'Specify which tickers to download. Space-separated list. ' f'Default: `1m 5m`.', - choices=[ - '1m', '3m', '5m', '15m', '30m', '1h', '2h', '4h', '6h', '8h', '12h', '1d', '3d', '1w' - ], + choices=['1m', '3m', '5m', '15m', '30m', '1h', '2h', '4h', + '6h', '8h', '12h', '1d', '3d', '1w'], default=['1m', '5m'], nargs='+', ), - "erase": - Arg( + "erase": Arg( '--erase', help='Clean all existing data for the selected exchange/pairs/timeframes.', action='store_true', ), # Templating options - "template": - Arg( + "template": Arg( '--template', help='Use a template which is either `minimal` or ' '`full` (containing multiple sample indicators). Default: `%(default)s`.', @@ -475,22 +410,19 @@ AVAILABLE_CLI_OPTIONS = { default='full', ), # Plot dataframe - "indicators1": - Arg( + "indicators1": Arg( '--indicators1', help='Set indicators from your strategy you want in the first row of the graph. ' "Space-separated list. Example: `ema3 ema5`. Default: `['sma', 'ema3', 'ema5']`.", nargs='+', ), - "indicators2": - Arg( + "indicators2": Arg( '--indicators2', help='Set indicators from your strategy you want in the third row of the graph. ' "Space-separated list. Example: `fastd fastk`. Default: `['macd', 'macdsignal']`.", nargs='+', ), - "plot_limit": - Arg( + "plot_limit": Arg( '--plot-limit', help='Specify tick limit for plotting. Notice: too high values cause huge files. ' 'Default: %(default)s.', @@ -498,8 +430,7 @@ AVAILABLE_CLI_OPTIONS = { metavar='INT', default=750, ), - "trade_source": - Arg( + "trade_source": Arg( '--trade-source', help='Specify the source for trades (Can be DB or file (backtest file)) ' 'Default: %(default)s', @@ -507,90 +438,76 @@ AVAILABLE_CLI_OPTIONS = { default="file", ), # hyperopt-list, hyperopt-show - "hyperopt_list_profitable": - Arg( + "hyperopt_list_profitable": Arg( '--profitable', help='Select only profitable epochs.', action='store_true', ), - "hyperopt_list_best": - Arg( + "hyperopt_list_best": Arg( '--best', help='Select only best epochs.', action='store_true', ), - "hyperopt_list_min_trades": - Arg( + "hyperopt_list_min_trades": Arg( '--min-trades', help='Select epochs with more than INT trades.', type=check_int_positive, metavar='INT', ), - "hyperopt_list_max_trades": - Arg( + "hyperopt_list_max_trades": Arg( '--max-trades', help='Select epochs with less than INT trades.', type=check_int_positive, metavar='INT', ), - "hyperopt_list_min_avg_time": - Arg( + "hyperopt_list_min_avg_time": Arg( '--min-avg-time', help='Select epochs on above average time.', type=float, metavar='FLOAT', ), - "hyperopt_list_max_avg_time": - Arg( + "hyperopt_list_max_avg_time": Arg( '--max-avg-time', help='Select epochs on under average time.', type=float, metavar='FLOAT', ), - "hyperopt_list_min_avg_profit": - Arg( + "hyperopt_list_min_avg_profit": Arg( '--min-avg-profit', help='Select epochs on above average profit.', type=float, metavar='FLOAT', ), - "hyperopt_list_max_avg_profit": - Arg( + "hyperopt_list_max_avg_profit": Arg( '--max-avg-profit', help='Select epochs on below average profit.', type=float, metavar='FLOAT', ), - "hyperopt_list_min_total_profit": - Arg( + "hyperopt_list_min_total_profit": Arg( '--min-total-profit', help='Select epochs on above total profit.', type=float, metavar='FLOAT', ), - "hyperopt_list_max_total_profit": - Arg( + "hyperopt_list_max_total_profit": Arg( '--max-total-profit', help='Select epochs on below total profit.', type=float, metavar='FLOAT', ), - "hyperopt_list_no_details": - Arg( + "hyperopt_list_no_details": Arg( '--no-details', help='Do not print best epoch details.', action='store_true', ), - "hyperopt_show_index": - Arg( - '-n', - '--index', + "hyperopt_show_index": Arg( + '-n', '--index', help='Specify the index of the epoch to print details for.', type=check_int_nonzero, metavar='INT', ), - "hyperopt_show_no_header": - Arg( + "hyperopt_show_no_header": Arg( '--no-header', help='Do not print epoch details header.', action='store_true', diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index 4f2db4065..7c9c01237 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -10,7 +10,8 @@ from typing import Any, Callable, Dict, List, Optional from freqtrade import constants from freqtrade.configuration.check_exchange import check_exchange from freqtrade.configuration.deprecated_settings import process_temporary_deprecated_settings -from freqtrade.configuration.directory_operations import (create_datadir, create_userdata_dir) +from freqtrade.configuration.directory_operations import (create_datadir, + create_userdata_dir) from freqtrade.configuration.load_config import load_config_file from freqtrade.exceptions import OperationalException from freqtrade.loggers import setup_logging @@ -25,6 +26,7 @@ class Configuration: Class to read and init the bot configuration Reuse this class for the bot, backtesting, hyperopt and every script that required configuration """ + def __init__(self, args: Dict[str, Any], runmode: RunMode = None) -> None: self.args = args self.config: Optional[Dict[str, Any]] = None @@ -150,12 +152,11 @@ class Configuration: if self.args.get("strategy") or not config.get('strategy'): config.update({'strategy': self.args.get("strategy")}) - self._args_to_config(config, - argname='strategy_path', + self._args_to_config(config, argname='strategy_path', logstring='Using additional Strategy lookup path: {}') - if ('db_url' in self.args and self.args["db_url"] - and self.args["db_url"] != constants.DEFAULT_DB_PROD_URL): + if ('db_url' in self.args and self.args["db_url"] and + self.args["db_url"] != constants.DEFAULT_DB_PROD_URL): config.update({'db_url': self.args["db_url"]}) logger.info('Parameter --db-url detected ...') @@ -193,23 +194,20 @@ class Configuration: logger.info('Using data directory: %s ...', config.get('datadir')) if self.args.get('exportfilename'): - self._args_to_config(config, - argname='exportfilename', + self._args_to_config(config, argname='exportfilename', logstring='Storing backtest results to {} ...') else: - config['exportfilename'] = (config['user_data_dir'] / - 'backtest_results/backtest-result.json') + config['exportfilename'] = (config['user_data_dir'] + / 'backtest_results/backtest-result.json') def _process_optimize_options(self, config: Dict[str, Any]) -> None: # This will override the strategy configuration - self._args_to_config(config, - argname='ticker_interval', + self._args_to_config(config, argname='ticker_interval', logstring='Parameter -i/--ticker-interval detected ... ' 'Using ticker_interval: {} ...') - self._args_to_config(config, - argname='position_stacking', + self._args_to_config(config, argname='position_stacking', logstring='Parameter --enable-position-stacking detected ...') # Setting max_open_trades to infinite if -1 @@ -222,39 +220,31 @@ class Configuration: logger.info('max_open_trades set to unlimited ...') elif 'max_open_trades' in self.args and self.args["max_open_trades"]: config.update({'max_open_trades': self.args["max_open_trades"]}) - logger.info( - 'Parameter --max-open-trades detected, ' - 'overriding max_open_trades to: %s ...', config.get('max_open_trades')) + logger.info('Parameter --max-open-trades detected, ' + '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')) - self._args_to_config(config, - argname='stake_amount', + self._args_to_config(config, argname='stake_amount', logstring='Parameter --stake-amount detected, ' 'overriding stake_amount to: {} ...') - self._args_to_config(config, - argname='fee', + self._args_to_config(config, argname='fee', logstring='Parameter --fee detected, ' 'setting fee to: {} ...') - self._args_to_config(config, - argname='timerange', + self._args_to_config(config, argname='timerange', logstring='Parameter --timerange detected: {} ...') self._process_datadir_options(config) - self._args_to_config(config, - argname='strategy_list', - logstring='Using strategy list of {} strategies', - logfun=len) + self._args_to_config(config, argname='strategy_list', + logstring='Using strategy list of {} strategies', logfun=len) - self._args_to_config(config, - argname='ticker_interval', + self._args_to_config(config, argname='ticker_interval', logstring='Overriding ticker interval with Command line argument') - self._args_to_config(config, - argname='export', + self._args_to_config(config, argname='export', logstring='Parameter --export detected: {} ...') # Edge section: @@ -266,14 +256,13 @@ class Configuration: logger.info('Parameter --stoplosses detected: %s ...', self.args["stoploss_range"]) # Hyperopt section - self._args_to_config(config, argname='hyperopt', logstring='Using Hyperopt class name: {}') + self._args_to_config(config, argname='hyperopt', + logstring='Using Hyperopt class name: {}') - self._args_to_config(config, - argname='hyperopt_path', + self._args_to_config(config, argname='hyperopt_path', logstring='Using additional Hyperopt lookup path: {}') - self._args_to_config(config, - argname='epochs', + self._args_to_config(config, argname='epochs', logstring='Parameter --epochs detected ... ' 'Will run Hyperopt with for {} epochs ...') self._args_to_config(config, @@ -290,8 +279,7 @@ class Configuration: argname='spaces', logstring='Parameter -s/--spaces detected: {}') - self._args_to_config(config, - argname='print_all', + self._args_to_config(config, argname='print_all', logstring='Parameter --print-all detected ...') if 'print_colorized' in self.args and not self.args["print_colorized"]: @@ -300,115 +288,100 @@ class Configuration: else: config.update({'print_colorized': True}) - self._args_to_config(config, - argname='print_json', + self._args_to_config(config, argname='print_json', logstring='Parameter --print-json detected ...') - self._args_to_config(config, - argname='hyperopt_jobs', + self._args_to_config(config, argname='hyperopt_jobs', logstring='Parameter -j/--job-workers detected: {}') - self._args_to_config(config, - argname='hyperopt_random_state', + self._args_to_config(config, argname='hyperopt_random_state', logstring='Parameter --random-state detected: {}') - self._args_to_config(config, - argname='hyperopt_min_trades', + self._args_to_config(config, argname='hyperopt_min_trades', logstring='Parameter --min-trades detected: {}') - self._args_to_config(config, argname='hyperopt_continue', logstring='Hyperopt continue: {}') + self._args_to_config(config, argname='hyperopt_continue', + logstring='Hyperopt continue: {}') - self._args_to_config(config, - argname='hyperopt_loss', + self._args_to_config(config, argname='hyperopt_loss', logstring='Using Hyperopt loss class name: {}') - self._args_to_config(config, - argname='hyperopt_show_index', + self._args_to_config(config, argname='hyperopt_show_index', logstring='Parameter -n/--index detected: {}') - self._args_to_config(config, - argname='hyperopt_list_best', + self._args_to_config(config, argname='hyperopt_list_best', logstring='Parameter --best detected: {}') - self._args_to_config(config, - argname='hyperopt_list_profitable', + self._args_to_config(config, argname='hyperopt_list_profitable', logstring='Parameter --profitable detected: {}') - self._args_to_config(config, - argname='hyperopt_list_min_trades', + self._args_to_config(config, argname='hyperopt_list_min_trades', logstring='Parameter --min-trades detected: {}') - self._args_to_config(config, - argname='hyperopt_list_max_trades', + self._args_to_config(config, argname='hyperopt_list_max_trades', logstring='Parameter --max-trades detected: {}') - self._args_to_config(config, - argname='hyperopt_list_min_avg_time', + self._args_to_config(config, argname='hyperopt_list_min_avg_time', logstring='Parameter --min-avg-time detected: {}') - self._args_to_config(config, - argname='hyperopt_list_max_avg_time', + self._args_to_config(config, argname='hyperopt_list_max_avg_time', logstring='Parameter --max-avg-time detected: {}') - self._args_to_config(config, - argname='hyperopt_list_min_avg_profit', + self._args_to_config(config, argname='hyperopt_list_min_avg_profit', logstring='Parameter --min-avg-profit detected: {}') - self._args_to_config(config, - argname='hyperopt_list_max_avg_profit', + self._args_to_config(config, argname='hyperopt_list_max_avg_profit', logstring='Parameter --max-avg-profit detected: {}') - self._args_to_config(config, - argname='hyperopt_list_min_total_profit', + self._args_to_config(config, argname='hyperopt_list_min_total_profit', logstring='Parameter --min-total-profit detected: {}') - self._args_to_config(config, - argname='hyperopt_list_max_total_profit', + self._args_to_config(config, argname='hyperopt_list_max_total_profit', logstring='Parameter --max-total-profit detected: {}') - self._args_to_config(config, - argname='hyperopt_list_no_details', + self._args_to_config(config, argname='hyperopt_list_no_details', logstring='Parameter --no-details detected: {}') - self._args_to_config(config, - argname='hyperopt_show_no_header', + self._args_to_config(config, argname='hyperopt_show_no_header', logstring='Parameter --no-header detected: {}') def _process_plot_options(self, config: Dict[str, Any]) -> None: - self._args_to_config(config, argname='pairs', logstring='Using pairs {}') + self._args_to_config(config, argname='pairs', + logstring='Using pairs {}') - self._args_to_config(config, argname='indicators1', logstring='Using indicators1: {}') + self._args_to_config(config, argname='indicators1', + logstring='Using indicators1: {}') - self._args_to_config(config, argname='indicators2', logstring='Using indicators2: {}') + self._args_to_config(config, argname='indicators2', + logstring='Using indicators2: {}') - self._args_to_config(config, argname='plot_limit', logstring='Limiting plot to: {}') - self._args_to_config(config, argname='trade_source', logstring='Using trades from: {}') + self._args_to_config(config, argname='plot_limit', + logstring='Limiting plot to: {}') + self._args_to_config(config, argname='trade_source', + logstring='Using trades from: {}') - self._args_to_config(config, - argname='erase', + self._args_to_config(config, argname='erase', logstring='Erase detected. Deleting existing data.') - self._args_to_config(config, argname='timeframes', logstring='timeframes --timeframes: {}') + self._args_to_config(config, argname='timeframes', + logstring='timeframes --timeframes: {}') - self._args_to_config(config, argname='days', logstring='Detected --days: {}') + self._args_to_config(config, argname='days', + logstring='Detected --days: {}') - self._args_to_config(config, - argname='download_trades', + self._args_to_config(config, argname='download_trades', logstring='Detected --dl-trades: {}') - self._args_to_config(config, - argname='dataformat_ohlcv', + self._args_to_config(config, argname='dataformat_ohlcv', logstring='Using "{}" to store OHLCV data.') - self._args_to_config(config, - argname='dataformat_trades', + self._args_to_config(config, argname='dataformat_trades', logstring='Using "{}" to store trades data.') def _process_runmode(self, config: Dict[str, Any]) -> None: - self._args_to_config(config, - argname='dry_run', + self._args_to_config(config, argname='dry_run', logstring='Parameter --dry-run detected, ' 'overriding dry_run to: {} ...') @@ -419,11 +392,8 @@ class Configuration: config.update({'runmode': self.runmode}) - def _args_to_config(self, - config: Dict[str, Any], - argname: str, - logstring: str, - logfun: Optional[Callable] = None, + def _args_to_config(self, config: Dict[str, Any], argname: str, + logstring: str, logfun: Optional[Callable] = None, deprecated_msg: Optional[str] = None) -> None: """ :param config: Configuration dictionary @@ -435,7 +405,7 @@ class Configuration: configuration instead of the content) """ if (argname in self.args and self.args[argname] is not None - and self.args[argname] is not False): + and self.args[argname] is not False): config.update({argname: self.args[argname]}) if logfun: diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 7def3a054..2c24fd01e 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -1,4 +1,5 @@ # pragma pylint: disable=too-few-public-methods + """ bot constants """ @@ -18,12 +19,11 @@ REQUIRED_ORDERTIF = ['buy', 'sell'] REQUIRED_ORDERTYPES = ['buy', 'sell', 'stoploss', 'stoploss_on_exchange'] ORDERTYPE_POSSIBILITIES = ['limit', 'market'] ORDERTIF_POSSIBILITIES = ['gtc', 'fok', 'ioc'] -AVAILABLE_PAIRLISTS = [ - 'StaticPairList', 'VolumePairList', 'PrecisionFilter', 'PriceFilter', 'SpreadFilter' -] +AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList', + 'PrecisionFilter', 'PriceFilter', 'SpreadFilter'] AVAILABLE_DATAHANDLERS = ['json', 'jsongz'] DRY_RUN_WALLET = 1000 -MATH_CLOSE_PREC = 1e-14 # Precision used for float comparisons +MATH_CLOSE_PREC = 1e-14 # Precision used for float comparisons DEFAULT_DATAFRAME_COLUMNS = ['date', 'open', 'high', 'low', 'close', 'volume'] USERPATH_HYPEROPTS = 'hyperopts' @@ -40,9 +40,11 @@ USER_DATA_FILES = { } SUPPORTED_FIAT = [ - "AUD", "BRL", "CAD", "CHF", "CLP", "CNY", "CZK", "DKK", "EUR", "GBP", "HKD", "HUF", "IDR", - "ILS", "INR", "JPY", "KRW", "MXN", "MYR", "NOK", "NZD", "PHP", "PKR", "PLN", "RUB", "SEK", - "SGD", "THB", "TRY", "TWD", "ZAR", "USD", "BTC", "XBT", "ETH", "XRP", "LTC", "BCH", "USDT" + "AUD", "BRL", "CAD", "CHF", "CLP", "CNY", "CZK", "DKK", + "EUR", "GBP", "HKD", "HUF", "IDR", "ILS", "INR", "JPY", + "KRW", "MXN", "MYR", "NOK", "NZD", "PHP", "PKR", "PLN", + "RUB", "SEK", "SGD", "THB", "TRY", "TWD", "ZAR", "USD", + "BTC", "XBT", "ETH", "XRP", "LTC", "BCH", "USDT" ] MINIMAL_CONFIG = { @@ -63,16 +65,9 @@ MINIMAL_CONFIG = { CONF_SCHEMA = { 'type': 'object', 'properties': { - 'max_open_trades': { - 'type': ['integer', 'number'], - 'minimum': -1 - }, - 'ticker_interval': { - 'type': 'string' - }, - 'stake_currency': { - 'type': 'string' - }, + 'max_open_trades': {'type': ['integer', 'number'], 'minimum': -1}, + 'ticker_interval': {'type': 'string'}, + 'stake_currency': {'type': 'string'}, 'stake_amount': { 'type': ['number', 'string'], 'minimum': 0.0001, @@ -84,76 +79,32 @@ CONF_SCHEMA = { 'maximum': 1, 'default': 0.99 }, - 'amend_last_stake_amount': { - 'type': 'boolean', - 'default': False - }, + 'amend_last_stake_amount': {'type': 'boolean', 'default': False}, 'last_stake_amount_min_ratio': { - 'type': 'number', - 'minimum': 0.0, - 'maximum': 1.0, - 'default': 0.5 - }, - 'fiat_display_currency': { - 'type': 'string', - 'enum': SUPPORTED_FIAT - }, - 'dry_run': { - 'type': 'boolean' - }, - 'dry_run_wallet': { - 'type': 'number', - 'default': DRY_RUN_WALLET - }, - 'process_only_new_candles': { - 'type': 'boolean' + 'type': 'number', 'minimum': 0.0, 'maximum': 1.0, 'default': 0.5 }, + 'fiat_display_currency': {'type': 'string', 'enum': SUPPORTED_FIAT}, + 'dry_run': {'type': 'boolean'}, + 'dry_run_wallet': {'type': 'number', 'default': DRY_RUN_WALLET}, + 'process_only_new_candles': {'type': 'boolean'}, 'minimal_roi': { 'type': 'object', 'patternProperties': { - '^[0-9.]+$': { - 'type': 'number' - } + '^[0-9.]+$': {'type': 'number'} }, 'minProperties': 1 }, - 'amount_reserve_percent': { - 'type': 'number', - 'minimum': 0.0, - 'maximum': 0.5 - }, - 'stoploss': { - 'type': 'number', - 'maximum': 0, - 'exclusiveMaximum': True - }, - 'trailing_stop': { - 'type': 'boolean' - }, - 'trailing_stop_positive': { - 'type': 'number', - 'minimum': 0, - 'maximum': 1 - }, - 'trailing_stop_positive_offset': { - 'type': 'number', - 'minimum': 0, - 'maximum': 1 - }, - 'trailing_only_offset_is_reached': { - 'type': 'boolean' - }, + 'amount_reserve_percent': {'type': 'number', 'minimum': 0.0, 'maximum': 0.5}, + 'stoploss': {'type': 'number', 'maximum': 0, 'exclusiveMaximum': True}, + 'trailing_stop': {'type': 'boolean'}, + 'trailing_stop_positive': {'type': 'number', 'minimum': 0, 'maximum': 1}, + 'trailing_stop_positive_offset': {'type': 'number', 'minimum': 0, 'maximum': 1}, + 'trailing_only_offset_is_reached': {'type': 'boolean'}, 'unfilledtimeout': { 'type': 'object', 'properties': { - 'buy': { - 'type': 'number', - 'minimum': 1 - }, - 'sell': { - 'type': 'number', - 'minimum': 1 - } + 'buy': {'type': 'number', 'minimum': 1}, + 'sell': {'type': 'number', 'minimum': 1} } }, 'bid_strategy': { @@ -164,24 +115,13 @@ CONF_SCHEMA = { 'minimum': 0, 'maximum': 1, 'exclusiveMaximum': False, - 'use_order_book': { - 'type': 'boolean' - }, - 'order_book_top': { - 'type': 'integer', - 'maximum': 20, - 'minimum': 1 - }, + 'use_order_book': {'type': 'boolean'}, + 'order_book_top': {'type': 'integer', 'maximum': 20, 'minimum': 1}, 'check_depth_of_market': { 'type': 'object', 'properties': { - 'enabled': { - 'type': 'boolean' - }, - 'bids_to_ask_delta': { - 'type': 'number', - 'minimum': 0 - }, + 'enabled': {'type': 'boolean'}, + 'bids_to_ask_delta': {'type': 'number', 'minimum': 0}, } }, }, @@ -191,92 +131,43 @@ CONF_SCHEMA = { 'ask_strategy': { 'type': 'object', 'properties': { - 'use_order_book': { - 'type': 'boolean' - }, - 'order_book_min': { - 'type': 'integer', - 'minimum': 1 - }, - 'order_book_max': { - 'type': 'integer', - 'minimum': 1, - 'maximum': 50 - }, - 'use_sell_signal': { - 'type': 'boolean' - }, - 'sell_profit_only': { - 'type': 'boolean' - }, - 'ignore_roi_if_buy_signal': { - 'type': 'boolean' - } + 'use_order_book': {'type': 'boolean'}, + 'order_book_min': {'type': 'integer', 'minimum': 1}, + 'order_book_max': {'type': 'integer', 'minimum': 1, 'maximum': 50}, + 'use_sell_signal': {'type': 'boolean'}, + 'sell_profit_only': {'type': 'boolean'}, + 'ignore_roi_if_buy_signal': {'type': 'boolean'} } }, 'order_types': { 'type': 'object', 'properties': { - 'buy': { - 'type': 'string', - 'enum': ORDERTYPE_POSSIBILITIES - }, - 'sell': { - 'type': 'string', - 'enum': ORDERTYPE_POSSIBILITIES - }, - 'emergencysell': { - 'type': 'string', - 'enum': ORDERTYPE_POSSIBILITIES - }, - 'stoploss': { - 'type': 'string', - 'enum': ORDERTYPE_POSSIBILITIES - }, - 'stoploss_on_exchange': { - 'type': 'boolean' - }, - 'stoploss_on_exchange_interval': { - 'type': 'number' - } + 'buy': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES}, + 'sell': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES}, + 'emergencysell': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES}, + 'stoploss': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES}, + 'stoploss_on_exchange': {'type': 'boolean'}, + 'stoploss_on_exchange_interval': {'type': 'number'} }, 'required': ['buy', 'sell', 'stoploss', 'stoploss_on_exchange'] }, 'order_time_in_force': { 'type': 'object', 'properties': { - 'buy': { - 'type': 'string', - 'enum': ORDERTIF_POSSIBILITIES - }, - 'sell': { - 'type': 'string', - 'enum': ORDERTIF_POSSIBILITIES - } + 'buy': {'type': 'string', 'enum': ORDERTIF_POSSIBILITIES}, + 'sell': {'type': 'string', 'enum': ORDERTIF_POSSIBILITIES} }, 'required': ['buy', 'sell'] }, - 'exchange': { - '$ref': '#/definitions/exchange' - }, - 'edge': { - '$ref': '#/definitions/edge' - }, + 'exchange': {'$ref': '#/definitions/exchange'}, + 'edge': {'$ref': '#/definitions/edge'}, 'experimental': { 'type': 'object', 'properties': { - 'use_sell_signal': { - 'type': 'boolean' - }, - 'sell_profit_only': { - 'type': 'boolean' - }, - 'ignore_roi_if_buy_signal': { - 'type': 'boolean' - }, - 'block_bad_exchanges': { - 'type': 'boolean' - } + 'use_sell_signal': {'type': 'boolean'}, + 'sell_profit_only': {'type': 'boolean'}, + 'ignore_roi_if_buy_signal': {'type': 'boolean'}, + 'block_bad_exchanges': {'type': 'boolean'} } }, 'pairlists': { @@ -284,13 +175,8 @@ CONF_SCHEMA = { 'items': { 'type': 'object', 'properties': { - 'method': { - 'type': 'string', - 'enum': AVAILABLE_PAIRLISTS - }, - 'config': { - 'type': 'object' - } + 'method': {'type': 'string', 'enum': AVAILABLE_PAIRLISTS}, + 'config': {'type': 'object'} }, 'required': ['method'], } @@ -298,126 +184,71 @@ CONF_SCHEMA = { 'telegram': { 'type': 'object', 'properties': { - 'enabled': { - 'type': 'boolean' - }, - 'token': { - 'type': 'string' - }, - 'chat_id': { - 'type': 'string' - }, + 'enabled': {'type': 'boolean'}, + 'token': {'type': 'string'}, + 'chat_id': {'type': 'string'}, }, 'required': ['enabled', 'token', 'chat_id'] }, 'webhook': { 'type': 'object', 'properties': { - 'enabled': { - 'type': 'boolean' - }, - 'webhookbuy': { - 'type': 'object' - }, - 'webhookbuycancel': { - 'type': 'object' - }, - 'webhooksell': { - 'type': 'object' - }, - 'webhooksellcancel': { - 'type': 'object' - }, - 'webhookstatus': { - 'type': 'object' - }, + 'enabled': {'type': 'boolean'}, + 'webhookbuy': {'type': 'object'}, + 'webhookbuycancel': {'type': 'object'}, + 'webhooksell': {'type': 'object'}, + 'webhooksellcancel': {'type': 'object'}, + 'webhookstatus': {'type': 'object'}, }, }, 'api_server': { 'type': 'object', 'properties': { - 'enabled': { - 'type': 'boolean' - }, - 'listen_ip_address': { - 'format': 'ipv4' - }, + 'enabled': {'type': 'boolean'}, + 'listen_ip_address': {'format': 'ipv4'}, 'listen_port': { 'type': 'integer', 'minimum': 1024, 'maximum': 65535 }, - 'username': { - 'type': 'string' - }, - 'password': { - 'type': 'string' - }, + 'username': {'type': 'string'}, + 'password': {'type': 'string'}, }, 'required': ['enabled', 'listen_ip_address', 'listen_port', 'username', 'password'] }, - 'db_url': { - 'type': 'string' - }, - 'initial_state': { - 'type': 'string', - 'enum': ['running', 'stopped'] - }, - 'forcebuy_enable': { - 'type': 'boolean' - }, + 'db_url': {'type': 'string'}, + 'initial_state': {'type': 'string', 'enum': ['running', 'stopped']}, + 'forcebuy_enable': {'type': 'boolean'}, 'internals': { 'type': 'object', 'default': {}, 'properties': { - 'process_throttle_secs': { - 'type': 'integer' - }, - 'interval': { - 'type': 'integer' - }, - 'sd_notify': { - 'type': 'boolean' - }, + 'process_throttle_secs': {'type': 'integer'}, + 'interval': {'type': 'integer'}, + 'sd_notify': {'type': 'boolean'}, } }, 'dataformat_ohlcv': { 'type': 'string', - 'enum': AVAILABLE_DATAHANDLERS, - 'default': 'json' + 'enum': AVAILABLE_DATAHANDLERS, + 'default': 'json' }, 'dataformat_trades': { 'type': 'string', - 'enum': AVAILABLE_DATAHANDLERS, - 'default': 'jsongz' + 'enum': AVAILABLE_DATAHANDLERS, + 'default': 'jsongz' } }, 'definitions': { 'exchange': { 'type': 'object', 'properties': { - 'name': { - 'type': 'string' - }, - 'sandbox': { - 'type': 'boolean', - 'default': False - }, - 'key': { - 'type': 'string', - 'default': '' - }, - 'secret': { - 'type': 'string', - 'default': '' - }, - 'password': { - 'type': 'string', - 'default': '' - }, - 'uid': { - 'type': 'string' - }, + 'name': {'type': 'string'}, + 'sandbox': {'type': 'boolean', 'default': False}, + 'key': {'type': 'string', 'default': ''}, + 'secret': {'type': 'string', 'default': ''}, + 'password': {'type': 'string', 'default': ''}, + 'uid': {'type': 'string'}, 'pair_whitelist': { 'type': 'array', 'items': { @@ -432,65 +263,29 @@ CONF_SCHEMA = { }, 'uniqueItems': True }, - 'outdated_offset': { - 'type': 'integer', - 'minimum': 1 - }, - 'markets_refresh_interval': { - 'type': 'integer' - }, - 'ccxt_config': { - 'type': 'object' - }, - 'ccxt_async_config': { - 'type': 'object' - } + 'outdated_offset': {'type': 'integer', 'minimum': 1}, + 'markets_refresh_interval': {'type': 'integer'}, + 'ccxt_config': {'type': 'object'}, + 'ccxt_async_config': {'type': 'object'} }, 'required': ['name'] }, 'edge': { 'type': 'object', 'properties': { - 'enabled': { - 'type': 'boolean' - }, - 'process_throttle_secs': { - 'type': 'integer', - 'minimum': 600 - }, - 'calculate_since_number_of_days': { - 'type': 'integer' - }, - 'allowed_risk': { - 'type': 'number' - }, - 'capital_available_percentage': { - 'type': 'number' - }, - 'stoploss_range_min': { - 'type': 'number' - }, - 'stoploss_range_max': { - 'type': 'number' - }, - 'stoploss_range_step': { - 'type': 'number' - }, - 'minimum_winrate': { - 'type': 'number' - }, - 'minimum_expectancy': { - 'type': 'number' - }, - 'min_trade_number': { - 'type': 'number' - }, - 'max_trade_duration_minute': { - 'type': 'integer' - }, - 'remove_pumps': { - 'type': 'boolean' - } + 'enabled': {'type': 'boolean'}, + 'process_throttle_secs': {'type': 'integer', 'minimum': 600}, + 'calculate_since_number_of_days': {'type': 'integer'}, + 'allowed_risk': {'type': 'number'}, + 'capital_available_percentage': {'type': 'number'}, + 'stoploss_range_min': {'type': 'number'}, + 'stoploss_range_max': {'type': 'number'}, + 'stoploss_range_step': {'type': 'number'}, + 'minimum_winrate': {'type': 'number'}, + 'minimum_expectancy': {'type': 'number'}, + 'min_trade_number': {'type': 'number'}, + 'max_trade_duration_minute': {'type': 'integer'}, + 'remove_pumps': {'type': 'boolean'} }, 'required': ['process_throttle_secs', 'allowed_risk'] } diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 5919a37e0..8c3ea50ce 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -248,27 +248,24 @@ class Hyperopt: result: Dict = {} if self.has_space('buy'): - result['buy'] = {p.name: params.get(p.name) for p in self.hyperopt_space('buy')} + result['buy'] = {p.name: params.get(p.name) + for p in self.hyperopt_space('buy')} if self.has_space('sell'): - result['sell'] = {p.name: params.get(p.name) for p in self.hyperopt_space('sell')} + result['sell'] = {p.name: params.get(p.name) + for p in self.hyperopt_space('sell')} if self.has_space('roi'): result['roi'] = self.custom_hyperopt.generate_roi_table(params) if self.has_space('stoploss'): - result['stoploss'] = { - p.name: params.get(p.name) - for p in self.hyperopt_space('stoploss') - } + result['stoploss'] = {p.name: params.get(p.name) + for p in self.hyperopt_space('stoploss')} if self.has_space('trailing'): result['trailing'] = self.custom_hyperopt.generate_trailing_params(params) return result @staticmethod - def print_epoch_details(results, - total_epochs: int, - print_json: bool, - no_header: bool = False, - header_str: str = None) -> None: + def print_epoch_details(results, total_epochs: int, print_json: bool, + no_header: bool = False, header_str: str = None) -> None: """ Display details of the hyperopt result """ @@ -307,7 +304,8 @@ class Hyperopt: # OrderedDict is used to keep the numeric order of the items # in the dict. result_dict['minimal_roi'] = OrderedDict( - (str(k), v) for k, v in space_params.items()) + (str(k), v) for k, v in space_params.items() + ) else: # 'stoploss', 'trailing' result_dict.update(space_params) @@ -359,7 +357,8 @@ class Hyperopt: def _format_explanation_string(results, total_epochs) -> str: return (("*" if 'is_initial_point' in results and results['is_initial_point'] else " ") + f"{results['current_epoch']:5d}/{total_epochs}: " + - f"{results['results_explanation']} " + f"Objective: {results['loss']:.5f}") + f"{results['results_explanation']} " + + f"Objective: {results['loss']:.5f}") @staticmethod def print_result_table(config: dict, results: list, total_epochs: int, highlight_best: bool, @@ -372,15 +371,12 @@ class Hyperopt: trials = json_normalize(results, max_level=1) trials['Best'] = '' - trials = trials[[ - 'Best', 'current_epoch', 'results_metrics.trade_count', 'results_metrics.avg_profit', - 'results_metrics.total_profit', 'results_metrics.profit', 'results_metrics.duration', - 'loss', 'is_initial_point', 'is_best' - ]] - trials.columns = [ - 'Best', 'Epoch', 'Trades', 'Avg profit', 'Total profit', 'Profit', 'Avg duration', - 'Objective', 'is_initial_point', 'is_best' - ] + trials = trials[['Best', 'current_epoch', 'results_metrics.trade_count', + 'results_metrics.avg_profit', 'results_metrics.total_profit', + 'results_metrics.profit', 'results_metrics.duration', + 'loss', 'is_initial_point', 'is_best']] + trials.columns = ['Best', 'Epoch', 'Trades', 'Avg profit', 'Total profit', + 'Profit', 'Avg duration', 'Objective', 'is_initial_point', 'is_best'] trials['is_profit'] = False trials.loc[trials['is_initial_point'], 'Best'] = '*' trials.loc[trials['is_best'], 'Best'] = 'Best' @@ -388,33 +384,31 @@ class Hyperopt: trials.loc[trials['Total profit'] > 0, 'is_profit'] = True trials['Trades'] = trials['Trades'].astype(str) - trials['Epoch'] = trials['Epoch'].apply(lambda x: "{}/{}".format(x, total_epochs)) - trials['Avg profit'] = trials['Avg profit'].apply(lambda x: '{:,.2f}%'.format(x) - if not isna(x) else x) - trials['Profit'] = trials['Profit'].apply(lambda x: '{:,.2f}%'.format(x) - if not isna(x) else x) + trials['Epoch'] = trials['Epoch'].apply( + lambda x: "{}/{}".format(x, total_epochs)) + trials['Avg profit'] = trials['Avg profit'].apply( + lambda x: '{:,.2f}%'.format(x) if not isna(x) else x) + trials['Profit'] = trials['Profit'].apply( + lambda x: '{:,.2f}%'.format(x) if not isna(x) else x) trials['Total profit'] = trials['Total profit'].apply( lambda x: '{: 11.8f} '.format(x) + config['stake_currency'] if not isna(x) else x) - trials['Avg duration'] = trials['Avg duration'].apply(lambda x: '{:,.1f}m'.format(x) - if not isna(x) else x) + trials['Avg duration'] = trials['Avg duration'].apply( + lambda x: '{:,.1f}m'.format(x) if not isna(x) else x) if print_colorized: for i in range(len(trials)): if trials.loc[i]['is_profit']: - for z in range(len(trials.loc[i]) - 3): - trials.iat[i, z] = "{}{}{}".format(Fore.GREEN, str(trials.loc[i][z]), - Fore.RESET) + for z in range(len(trials.loc[i])-3): + trials.iat[i, z] = "{}{}{}".format(Fore.GREEN, + str(trials.loc[i][z]), Fore.RESET) if trials.loc[i]['is_best'] and highlight_best: - for z in range(len(trials.loc[i]) - 3): - trials.iat[i, z] = "{}{}{}".format(Style.BRIGHT, str(trials.loc[i][z]), - Style.RESET_ALL) + for z in range(len(trials.loc[i])-3): + trials.iat[i, z] = "{}{}{}".format(Style.BRIGHT, + str(trials.loc[i][z]), Style.RESET_ALL) trials = trials.drop(columns=['is_initial_point', 'is_best', 'is_profit']) - print( - tabulate(trials.to_dict(orient='list'), - headers='keys', - tablefmt='psql', - stralign="right")) + print(tabulate(trials.to_dict(orient='list'), headers='keys', tablefmt='psql', + stralign="right")) def has_space(self, space: str) -> bool: """ @@ -518,10 +512,8 @@ class Hyperopt: # path. We do not want to optimize 'hodl' strategies. loss: float = MAX_LOSS if trade_count >= self.config['hyperopt_min_trades']: - loss = self.calculate_loss(results=backtesting_results, - trade_count=trade_count, - min_date=min_date.datetime, - max_date=max_date.datetime) + loss = self.calculate_loss(results=backtesting_results, trade_count=trade_count, + min_date=min_date.datetime, max_date=max_date.datetime) return { 'loss': loss, 'params_dict': params_dict, @@ -549,8 +541,8 @@ class Hyperopt: f"Avg profit {results_metrics['avg_profit']: 6.2f}%. " f"Total profit {results_metrics['total_profit']: 11.8f} {stake_cur} " f"({results_metrics['profit']: 7.2f}\N{GREEK CAPITAL LETTER SIGMA}%). " - f"Avg duration {results_metrics['duration']:5.1f} min.").encode( - locale.getpreferredencoding(), 'replace').decode('utf-8') + f"Avg duration {results_metrics['duration']:5.1f} min." + ).encode(locale.getpreferredencoding(), 'replace').decode('utf-8') def get_next_point_strategy(self): """ Choose a strategy randomly among the supported ones, used in multi opt mode @@ -571,10 +563,6 @@ class Hyperopt: acq_optimizer=self.opt_acq_optimizer, n_initial_points=n_initial_points, acq_optimizer_kwargs={'n_jobs': n_jobs}, - acq_func_kwargs={ - 'xi': 0.00001, - 'kappa': 0.00001 - }, model_queue_size=self.n_models, random_state=self.random_state, ) @@ -755,8 +743,9 @@ class Hyperopt: n_parameters += len(d.bounds) # guess the size of the search space as the count of the # unordered combination of the dimensions entries - search_space_size = (factorial(n_parameters) / - (factorial(n_parameters - n_dimensions) * factorial(n_dimensions))) + search_space_size = int( + (factorial(n_parameters) / + (factorial(n_parameters - n_dimensions) * factorial(n_dimensions)))) # logger.info(f'Search space size: {search_space_size}') if search_space_size < n_jobs: # don't waste if the space is small @@ -789,7 +778,7 @@ class Hyperopt: if self.max_epoch > self.search_space_size: self.max_epoch = self.search_space_size print() - logger.info(f'Max epochs set to: {self.epochs_limit()}') + logger.info(f'Max epoch set to: {self.epochs_limit()}') def setup_optimizers(self): """ Setup the optimizers objects, try to load from disk, or create new ones """ @@ -834,8 +823,10 @@ class Hyperopt: self.n_samples += len(preprocessed[pair]) min_date, max_date = get_timerange(data) - logger.info('Hyperopting with data from %s up to %s (%s days)..', min_date.isoformat(), - max_date.isoformat(), (max_date - min_date).days) + logger.info( + 'Hyperopting with data from %s up to %s (%s days)..', + min_date.isoformat(), max_date.isoformat(), (max_date - min_date).days + ) dump(preprocessed, self.tickerdata_pickle) # We don't need exchange instance anymore while running hyperopt @@ -898,7 +889,7 @@ class Hyperopt: break except KeyboardInterrupt: - print("User interrupted..") + print('User interrupted..') self.save_trials(final=True) diff --git a/setup.cfg b/setup.cfg index 9853c99d9..34f25482b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -13,7 +13,3 @@ ignore_missing_imports = True [mypy-tests.*] ignore_errors = True - -[yapf] -based_on_style = pep8 -column_limit = 100 \ No newline at end of file diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index 1d43878a6..2fe86dc5a 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -10,13 +10,15 @@ import pytest from arrow import Arrow from filelock import Timeout -from freqtrade.commands.optimize_commands import (setup_optimize_configuration, start_hyperopt) +from freqtrade.commands.optimize_commands import (setup_optimize_configuration, + start_hyperopt) from freqtrade.data.history import load_data from freqtrade.exceptions import 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, HyperOptResolver) +from freqtrade.resolvers.hyperopt_resolver import (HyperOptLossResolver, + HyperOptResolver) from freqtrade.state import RunMode from freqtrade.strategy.interface import SellType from tests.conftest import (get_args, log_has, log_has_re, patch_exchange, @@ -35,18 +37,21 @@ def hyperopt(default_conf, mocker): @pytest.fixture(scope='function') def hyperopt_results(): - return pd.DataFrame({ - 'pair': ['ETH/BTC', 'ETH/BTC', 'ETH/BTC'], - 'profit_percent': [-0.1, 0.2, 0.3], - 'profit_abs': [-0.2, 0.4, 0.6], - 'trade_duration': [10, 30, 10], - 'sell_reason': [SellType.STOP_LOSS, SellType.ROI, SellType.ROI], - 'close_time': [ - datetime(2019, 1, 1, 9, 26, 3, 478039), - datetime(2019, 2, 1, 9, 26, 3, 478039), - datetime(2019, 3, 1, 9, 26, 3, 478039) - ] - }) + return pd.DataFrame( + { + 'pair': ['ETH/BTC', 'ETH/BTC', 'ETH/BTC'], + 'profit_percent': [-0.1, 0.2, 0.3], + 'profit_abs': [-0.2, 0.4, 0.6], + 'trade_duration': [10, 30, 10], + 'sell_reason': [SellType.STOP_LOSS, SellType.ROI, SellType.ROI], + 'close_time': + [ + datetime(2019, 1, 1, 9, 26, 3, 478039), + datetime(2019, 2, 1, 9, 26, 3, 478039), + datetime(2019, 3, 1, 9, 26, 3, 478039) + ] + } + ) # Functions for recurrent object patching @@ -75,10 +80,8 @@ def test_setup_hyperopt_configuration_without_arguments(mocker, default_conf, ca args = [ 'hyperopt', - '--config', - 'config.json', - '--hyperopt', - 'DefaultHyperOpt', + '--config', 'config.json', + '--hyperopt', 'DefaultHyperOpt', ] config = setup_optimize_configuration(get_args(args), RunMode.HYPEROPT) @@ -102,12 +105,23 @@ def test_setup_hyperopt_configuration_without_arguments(mocker, default_conf, ca def test_setup_hyperopt_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_datadir', + lambda c, x: x + ) args = [ - 'hyperopt', '--config', 'config.json', '--hyperopt', 'DefaultHyperOpt', '--datadir', - '/foo/bar', '--ticker-interval', '1m', '--timerange', ':100', '--enable-position-stacking', - '--disable-max-market-positions', '--epochs', '1000', '--spaces', 'default', '--print-all' + 'hyperopt', + '--config', 'config.json', + '--hyperopt', 'DefaultHyperOpt', + '--datadir', '/foo/bar', + '--ticker-interval', '1m', + '--timerange', ':100', + '--enable-position-stacking', + '--disable-max-market-positions', + '--epochs', '1000', + '--spaces', 'default', + '--print-all' ] config = setup_optimize_configuration(get_args(args), RunMode.HYPEROPT) @@ -151,22 +165,21 @@ def test_hyperoptresolver(mocker, default_conf, caplog) -> None: delattr(hyperopt, 'populate_indicators') delattr(hyperopt, 'populate_buy_trend') delattr(hyperopt, 'populate_sell_trend') - mocker.patch('freqtrade.resolvers.hyperopt_resolver.HyperOptResolver.load_object', - MagicMock(return_value=hyperopt(default_conf))) + mocker.patch( + 'freqtrade.resolvers.hyperopt_resolver.HyperOptResolver.load_object', + MagicMock(return_value=hyperopt(default_conf)) + ) default_conf.update({'hyperopt': 'DefaultHyperOpt'}) x = HyperOptResolver.load_hyperopt(default_conf) assert not hasattr(x, 'populate_indicators') assert not hasattr(x, 'populate_buy_trend') assert not hasattr(x, 'populate_sell_trend') - assert log_has( - "Hyperopt class does not provide populate_indicators() method. " - "Using populate_indicators from the strategy.", caplog) - assert log_has( - "Hyperopt class does not provide populate_sell_trend() method. " - "Using populate_sell_trend from the strategy.", caplog) - assert log_has( - "Hyperopt class does not provide populate_buy_trend() method. " - "Using populate_buy_trend from the strategy.", caplog) + assert log_has("Hyperopt class does not provide populate_indicators() method. " + "Using populate_indicators from the strategy.", caplog) + assert log_has("Hyperopt class does not provide populate_sell_trend() method. " + "Using populate_sell_trend from the strategy.", caplog) + assert log_has("Hyperopt class does not provide populate_buy_trend() method. " + "Using populate_buy_trend from the strategy.", caplog) assert hasattr(x, "ticker_interval") @@ -181,15 +194,17 @@ def test_hyperoptresolver_noname(default_conf): default_conf['hyperopt'] = '' with pytest.raises(OperationalException, match="No Hyperopt set. Please use `--hyperopt` to specify " - "the Hyperopt class to use."): + "the Hyperopt class to use."): HyperOptResolver.load_hyperopt(default_conf) def test_hyperoptlossresolver(mocker, default_conf, caplog) -> None: hl = DefaultHyperOptLoss - mocker.patch('freqtrade.resolvers.hyperopt_resolver.HyperOptLossResolver.load_object', - MagicMock(return_value=hl)) + mocker.patch( + 'freqtrade.resolvers.hyperopt_resolver.HyperOptLossResolver.load_object', + MagicMock(return_value=hl) + ) x = HyperOptLossResolver.load_hyperoptloss(default_conf) assert hasattr(x, "hyperopt_loss_function") @@ -208,7 +223,12 @@ def test_start_not_installed(mocker, default_conf, caplog, import_fails) -> None mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.start', start_mock) patch_exchange(mocker) - args = ['hyperopt', '--config', 'config.json', '--hyperopt', 'DefaultHyperOpt', '--epochs', '5'] + args = [ + 'hyperopt', + '--config', 'config.json', + '--hyperopt', 'DefaultHyperOpt', + '--epochs', '5' + ] pargs = get_args(args) with pytest.raises(OperationalException, match=r"Please ensure that the hyperopt dependencies"): @@ -221,7 +241,12 @@ def test_start(mocker, default_conf, caplog) -> None: mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.start', start_mock) patch_exchange(mocker) - args = ['hyperopt', '--config', 'config.json', '--hyperopt', 'DefaultHyperOpt', '--epochs', '5'] + args = [ + 'hyperopt', + '--config', 'config.json', + '--hyperopt', 'DefaultHyperOpt', + '--epochs', '5' + ] pargs = get_args(args) start_hyperopt(pargs) @@ -232,12 +257,19 @@ def test_start(mocker, default_conf, caplog) -> None: def test_start_no_data(mocker, default_conf, caplog) -> None: patched_configuration_load_config_file(mocker, default_conf) mocker.patch('freqtrade.data.history.load_pair_history', MagicMock(return_value=pd.DataFrame)) - mocker.patch('freqtrade.optimize.hyperopt.get_timerange', - MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))) + mocker.patch( + 'freqtrade.optimize.hyperopt.get_timerange', + MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))) + ) patch_exchange(mocker) - args = ['hyperopt', '--config', 'config.json', '--hyperopt', 'DefaultHyperOpt', '--epochs', '5'] + args = [ + 'hyperopt', + '--config', 'config.json', + '--hyperopt', 'DefaultHyperOpt', + '--epochs', '5' + ] pargs = get_args(args) with pytest.raises(OperationalException, match='No data found. Terminating.'): start_hyperopt(pargs) @@ -249,7 +281,12 @@ def test_start_filelock(mocker, default_conf, caplog) -> None: mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.start', start_mock) patch_exchange(mocker) - args = ['hyperopt', '--config', 'config.json', '--hyperopt', 'DefaultHyperOpt', '--epochs', '5'] + args = [ + 'hyperopt', + '--config', 'config.json', + '--hyperopt', 'DefaultHyperOpt', + '--epochs', '5' + ] pargs = get_args(args) start_hyperopt(pargs) assert log_has("Another running instance of freqtrade Hyperopt detected.", caplog) @@ -257,12 +294,12 @@ def test_start_filelock(mocker, default_conf, caplog) -> None: def test_loss_calculation_prefer_correct_trade_count(default_conf, hyperopt_results) -> None: hl = HyperOptLossResolver.load_hyperoptloss(default_conf) - correct = hl.hyperopt_loss_function(hyperopt_results, 600, datetime(2019, 1, 1), - datetime(2019, 5, 1)) - over = hl.hyperopt_loss_function(hyperopt_results, 600 + 100, datetime(2019, 1, 1), - datetime(2019, 5, 1)) - under = hl.hyperopt_loss_function(hyperopt_results, 600 - 100, datetime(2019, 1, 1), - datetime(2019, 5, 1)) + correct = hl.hyperopt_loss_function(hyperopt_results, 600, + datetime(2019, 1, 1), datetime(2019, 5, 1)) + over = hl.hyperopt_loss_function(hyperopt_results, 600 + 100, + datetime(2019, 1, 1), datetime(2019, 5, 1)) + under = hl.hyperopt_loss_function(hyperopt_results, 600 - 100, + datetime(2019, 1, 1), datetime(2019, 5, 1)) assert over > correct assert under > correct @@ -272,9 +309,10 @@ def test_loss_calculation_prefer_shorter_trades(default_conf, hyperopt_results) resultsb.loc[1, 'trade_duration'] = 20 hl = HyperOptLossResolver.load_hyperoptloss(default_conf) - longer = hl.hyperopt_loss_function(hyperopt_results, 100, datetime(2019, 1, 1), - datetime(2019, 5, 1)) - shorter = hl.hyperopt_loss_function(resultsb, 100, datetime(2019, 1, 1), datetime(2019, 5, 1)) + longer = hl.hyperopt_loss_function(hyperopt_results, 100, + datetime(2019, 1, 1), datetime(2019, 5, 1)) + shorter = hl.hyperopt_loss_function(resultsb, 100, + datetime(2019, 1, 1), datetime(2019, 5, 1)) assert shorter < longer @@ -285,11 +323,12 @@ def test_loss_calculation_has_limited_profit(default_conf, hyperopt_results) -> results_under['profit_percent'] = hyperopt_results['profit_percent'] / 2 hl = HyperOptLossResolver.load_hyperoptloss(default_conf) - correct = hl.hyperopt_loss_function(hyperopt_results, 600, datetime(2019, 1, 1), - datetime(2019, 5, 1)) - over = hl.hyperopt_loss_function(results_over, 600, datetime(2019, 1, 1), datetime(2019, 5, 1)) - under = hl.hyperopt_loss_function(results_under, 600, datetime(2019, 1, 1), - datetime(2019, 5, 1)) + correct = hl.hyperopt_loss_function(hyperopt_results, 600, + datetime(2019, 1, 1), datetime(2019, 5, 1)) + over = hl.hyperopt_loss_function(results_over, 600, + datetime(2019, 1, 1), datetime(2019, 5, 1)) + under = hl.hyperopt_loss_function(results_under, 600, + datetime(2019, 1, 1), datetime(2019, 5, 1)) assert over < correct assert under > correct @@ -304,10 +343,10 @@ def test_sharpe_loss_prefers_higher_profits(default_conf, hyperopt_results) -> N hl = HyperOptLossResolver.load_hyperoptloss(default_conf) correct = hl.hyperopt_loss_function(hyperopt_results, len(hyperopt_results), datetime(2019, 1, 1), datetime(2019, 5, 1)) - over = hl.hyperopt_loss_function(results_over, len(hyperopt_results), datetime(2019, 1, 1), - datetime(2019, 5, 1)) - under = hl.hyperopt_loss_function(results_under, len(hyperopt_results), datetime(2019, 1, 1), - datetime(2019, 5, 1)) + over = hl.hyperopt_loss_function(results_over, len(hyperopt_results), + datetime(2019, 1, 1), datetime(2019, 5, 1)) + under = hl.hyperopt_loss_function(results_under, len(hyperopt_results), + datetime(2019, 1, 1), datetime(2019, 5, 1)) assert over < correct assert under > correct @@ -322,10 +361,10 @@ def test_sharpe_loss_daily_prefers_higher_profits(default_conf, hyperopt_results hl = HyperOptLossResolver.load_hyperoptloss(default_conf) correct = hl.hyperopt_loss_function(hyperopt_results, len(hyperopt_results), datetime(2019, 1, 1), datetime(2019, 5, 1)) - over = hl.hyperopt_loss_function(results_over, len(hyperopt_results), datetime(2019, 1, 1), - datetime(2019, 5, 1)) - under = hl.hyperopt_loss_function(results_under, len(hyperopt_results), datetime(2019, 1, 1), - datetime(2019, 5, 1)) + over = hl.hyperopt_loss_function(results_over, len(hyperopt_results), + datetime(2019, 1, 1), datetime(2019, 5, 1)) + under = hl.hyperopt_loss_function(results_under, len(hyperopt_results), + datetime(2019, 1, 1), datetime(2019, 5, 1)) assert over < correct assert under > correct @@ -376,10 +415,10 @@ def test_onlyprofit_loss_prefers_higher_profits(default_conf, hyperopt_results) hl = HyperOptLossResolver.load_hyperoptloss(default_conf) correct = hl.hyperopt_loss_function(hyperopt_results, len(hyperopt_results), datetime(2019, 1, 1), datetime(2019, 5, 1)) - over = hl.hyperopt_loss_function(results_over, len(hyperopt_results), datetime(2019, 1, 1), - datetime(2019, 5, 1)) - under = hl.hyperopt_loss_function(results_under, len(hyperopt_results), datetime(2019, 1, 1), - datetime(2019, 5, 1)) + over = hl.hyperopt_loss_function(results_over, len(hyperopt_results), + datetime(2019, 1, 1), datetime(2019, 5, 1)) + under = hl.hyperopt_loss_function(results_under, len(hyperopt_results), + datetime(2019, 1, 1), datetime(2019, 5, 1)) assert over < correct assert under > correct @@ -387,24 +426,28 @@ def test_onlyprofit_loss_prefers_higher_profits(default_conf, hyperopt_results) def test_log_results_if_loss_improves(hyperopt, capsys) -> None: hyperopt.current_best_loss = 2 hyperopt.total_epochs = 2 - hyperopt.print_results({ - 'is_best': True, - 'loss': 1, - 'current_epoch': 2, # This starts from 1 (in a human-friendly manner) - 'results_explanation': 'foo.', - 'is_initial_point': False - }) + hyperopt.print_results( + { + 'is_best': True, + 'loss': 1, + 'current_epoch': 2, # This starts from 1 (in a human-friendly manner) + 'results_explanation': 'foo.', + 'is_initial_point': False + } + ) out, err = capsys.readouterr() assert ' 2/2: foo. Objective: 1.00000' in out def test_no_log_if_loss_does_not_improve(hyperopt, caplog) -> None: hyperopt.current_best_loss = 2 - hyperopt.print_results({ - 'is_best': False, - 'loss': 3, - 'current_epoch': 1, - }) + hyperopt.print_results( + { + 'is_best': False, + 'loss': 3, + 'current_epoch': 1, + } + ) assert caplog.record_tuples == [] @@ -452,32 +495,25 @@ def test_start_calls_optimizer(mocker, default_conf, caplog, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) - mocker.patch('freqtrade.optimize.hyperopt.get_timerange', - MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))) + mocker.patch( + 'freqtrade.optimize.hyperopt.get_timerange', + MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))) + ) parallel = mocker.patch( 'freqtrade.optimize.hyperopt.Hyperopt.run_backtest_parallel', - MagicMock(return_value=[{ - 'loss': 1, - 'results_explanation': 'foo result', - 'params': { - 'buy': {}, - 'sell': {}, - 'roi': {}, - 'stoploss': 0.0 - } - }])) + MagicMock(return_value=[{'loss': 1, 'results_explanation': 'foo result', + 'params': {'buy': {}, 'sell': {}, 'roi': {}, 'stoploss': 0.0}}]) + ) patch_exchange(mocker) # Co-test loading ticker-interval from strategy del default_conf['ticker_interval'] - default_conf.update({ - 'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'default', - 'hyperopt_jobs': 1, - }) + default_conf.update({'config': 'config.json.example', + 'hyperopt': 'DefaultHyperOpt', + 'epochs': 1, + 'timerange': None, + 'spaces': 'default', + 'hyperopt_jobs': 1, }) hyperopt = Hyperopt(default_conf) hyperopt.backtesting.strategy.tickerdata_to_dataframe = MagicMock() @@ -504,7 +540,11 @@ def test_start_calls_optimizer(mocker, default_conf, caplog, capsys) -> None: def test_format_results(hyperopt): # Test with BTC as stake_currency - trades = [('ETH/BTC', 2, 2, 123), ('LTC/BTC', 1, 1, 123), ('XPR/BTC', -1, -2, -246)] + trades = [ + ('ETH/BTC', 2, 2, 123), + ('LTC/BTC', 1, 1, 123), + ('XPR/BTC', -1, -2, -246) + ] labels = ['currency', 'profit_percent', 'profit_abs', 'trade_duration'] df = pd.DataFrame.from_records(trades, columns=labels) results_metrics = hyperopt._calculate_results_metrics(df) @@ -528,7 +568,11 @@ def test_format_results(hyperopt): assert result.find('2.0000Σ %') # Test with EUR as stake_currency - trades = [('ETH/EUR', 2, 2, 123), ('LTC/EUR', 1, 1, 123), ('XPR/EUR', -1, -2, -246)] + trades = [ + ('ETH/EUR', 2, 2, 123), + ('LTC/EUR', 1, 1, 123), + ('XPR/EUR', -1, -2, -246) + ] df = pd.DataFrame.from_records(trades, columns=labels) results_metrics = hyperopt._calculate_results_metrics(df) results['total_profit'] = results_metrics['total_profit'] @@ -537,97 +581,32 @@ def test_format_results(hyperopt): @pytest.mark.parametrize("spaces, expected_results", [ - (['buy'], { - 'buy': True, - 'sell': False, - 'roi': False, - 'stoploss': False, - 'trailing': False - }), - (['sell'], { - 'buy': False, - 'sell': True, - 'roi': False, - 'stoploss': False, - 'trailing': False - }), - (['roi'], { - 'buy': False, - 'sell': False, - 'roi': True, - 'stoploss': False, - 'trailing': False - }), - (['stoploss'], { - 'buy': False, - 'sell': False, - 'roi': False, - 'stoploss': True, - 'trailing': False - }), - (['trailing'], { - 'buy': False, - 'sell': False, - 'roi': False, - 'stoploss': False, - 'trailing': True - }), - (['buy', 'sell', 'roi', 'stoploss'], { - 'buy': True, - 'sell': True, - 'roi': True, - 'stoploss': True, - 'trailing': False - }), - (['buy', 'sell', 'roi', 'stoploss', 'trailing'], { - 'buy': True, - 'sell': True, - 'roi': True, - 'stoploss': True, - 'trailing': True - }), - (['buy', 'roi'], { - 'buy': True, - 'sell': False, - 'roi': True, - 'stoploss': False, - 'trailing': False - }), - (['all'], { - 'buy': True, - 'sell': True, - 'roi': True, - 'stoploss': True, - 'trailing': True - }), - (['default'], { - 'buy': True, - 'sell': True, - 'roi': True, - 'stoploss': True, - 'trailing': False - }), - (['default', 'trailing'], { - 'buy': True, - 'sell': True, - 'roi': True, - 'stoploss': True, - 'trailing': True - }), - (['all', 'buy'], { - 'buy': True, - 'sell': True, - 'roi': True, - 'stoploss': True, - 'trailing': True - }), - (['default', 'buy'], { - 'buy': True, - 'sell': True, - 'roi': True, - 'stoploss': True, - 'trailing': False - }), + (['buy'], + {'buy': True, 'sell': False, 'roi': False, 'stoploss': False, 'trailing': False}), + (['sell'], + {'buy': False, 'sell': True, 'roi': False, 'stoploss': False, 'trailing': False}), + (['roi'], + {'buy': False, 'sell': False, 'roi': True, 'stoploss': False, 'trailing': False}), + (['stoploss'], + {'buy': False, 'sell': False, 'roi': False, 'stoploss': True, 'trailing': False}), + (['trailing'], + {'buy': False, 'sell': False, 'roi': False, 'stoploss': False, 'trailing': True}), + (['buy', 'sell', 'roi', 'stoploss'], + {'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': False}), + (['buy', 'sell', 'roi', 'stoploss', 'trailing'], + {'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': True}), + (['buy', 'roi'], + {'buy': True, 'sell': False, 'roi': True, 'stoploss': False, 'trailing': False}), + (['all'], + {'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': True}), + (['default'], + {'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': False}), + (['default', 'trailing'], + {'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': True}), + (['all', 'buy'], + {'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': True}), + (['default', 'buy'], + {'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': False}), ]) def test_has_space(hyperopt, spaces, expected_results): for s in ['buy', 'sell', 'roi', 'stoploss', 'trailing']: @@ -653,17 +632,19 @@ def test_buy_strategy_generator(hyperopt, testdatadir) -> None: dataframe = hyperopt.custom_hyperopt.populate_indicators(dataframes['UNITTEST/BTC'], {'pair': 'UNITTEST/BTC'}) - populate_buy_trend = hyperopt.custom_hyperopt.buy_strategy_generator({ - 'adx-value': 20, - 'fastd-value': 20, - 'mfi-value': 20, - 'rsi-value': 20, - 'adx-enabled': True, - 'fastd-enabled': True, - 'mfi-enabled': True, - 'rsi-enabled': True, - 'trigger': 'bb_lower' - }) + populate_buy_trend = hyperopt.custom_hyperopt.buy_strategy_generator( + { + 'adx-value': 20, + 'fastd-value': 20, + 'mfi-value': 20, + 'rsi-value': 20, + 'adx-enabled': True, + 'fastd-enabled': True, + 'mfi-enabled': True, + 'rsi-enabled': True, + 'trigger': 'bb_lower' + } + ) result = populate_buy_trend(dataframe, {'pair': 'UNITTEST/BTC'}) # Check if some indicators are generated. We will not test all of them assert 'buy' in result @@ -679,14 +660,20 @@ def test_backtest_params(mocker, default_conf) -> None: 'hyperopt_min_trades': 1, }) - trades = [('TRX/BTC', 0.023117, 0.000233, 100)] + trades = [ + ('TRX/BTC', 0.023117, 0.000233, 100) + ] labels = ['currency', 'profit_percent', 'profit_abs', 'trade_duration'] backtest_result = pd.DataFrame.from_records(trades, columns=labels) - mocker.patch('freqtrade.optimize.hyperopt.Backtesting.backtest', - MagicMock(return_value=backtest_result)) - mocker.patch('freqtrade.optimize.hyperopt.get_timerange', - MagicMock(return_value=(Arrow(2017, 12, 10), Arrow(2017, 12, 13)))) + mocker.patch( + 'freqtrade.optimize.hyperopt.Backtesting.backtest', + MagicMock(return_value=backtest_result) + ) + mocker.patch( + 'freqtrade.optimize.hyperopt.get_timerange', + MagicMock(return_value=(Arrow(2017, 12, 10), Arrow(2017, 12, 13))) + ) patch_exchange(mocker) mocker.patch('freqtrade.optimize.hyperopt.load', MagicMock()) @@ -722,62 +709,44 @@ def test_backtest_params(mocker, default_conf) -> None: 'trailing_only_offset_is_reached': False, } response_expected = { - 'loss': - 1.9840569076926293, - 'results_explanation': - (' 1 trades. Avg profit 2.31%. Total profit 0.00023300 BTC ' - '( 2.31\N{GREEK CAPITAL LETTER SIGMA}%). Avg duration 100.0 min.').encode( - locale.getpreferredencoding(), 'replace').decode('utf-8'), - 'params_details': { - 'buy': { - 'adx-enabled': False, - 'adx-value': 0, - 'fastd-enabled': True, - 'fastd-value': 35, - 'mfi-enabled': False, - 'mfi-value': 0, - 'rsi-enabled': False, - 'rsi-value': 0, - 'trigger': 'macd_cross_signal' - }, - 'roi': { - 0: 0.12000000000000001, - 20.0: 0.02, - 50.0: 0.01, - 110.0: 0 - }, - 'sell': { - 'sell-adx-enabled': False, - 'sell-adx-value': 0, - 'sell-fastd-enabled': True, - 'sell-fastd-value': 75, - 'sell-mfi-enabled': False, - 'sell-mfi-value': 0, - 'sell-rsi-enabled': False, - 'sell-rsi-value': 0, - 'sell-trigger': 'macd_cross_signal' - }, - 'stoploss': { - 'stoploss': -0.4 - }, - 'trailing': { - 'trailing_only_offset_is_reached': False, - 'trailing_stop': True, - 'trailing_stop_positive': 0.02, - 'trailing_stop_positive_offset': 0.07 - } - }, - 'params_dict': - optimizer_param, - 'results_metrics': { - 'avg_profit': 2.3117, - 'duration': 100.0, - 'profit': 2.3117, - 'total_profit': 0.000233, - 'trade_count': 1 - }, - 'total_profit': - 0.00023300 + 'loss': 1.9840569076926293, + 'results_explanation': (' 1 trades. Avg profit 2.31%. Total profit 0.00023300 BTC ' + '( 2.31\N{GREEK CAPITAL LETTER SIGMA}%). Avg duration 100.0 min.' + ).encode(locale.getpreferredencoding(), 'replace').decode('utf-8'), + 'params_details': {'buy': {'adx-enabled': False, + 'adx-value': 0, + 'fastd-enabled': True, + 'fastd-value': 35, + 'mfi-enabled': False, + 'mfi-value': 0, + 'rsi-enabled': False, + 'rsi-value': 0, + 'trigger': 'macd_cross_signal'}, + 'roi': {0: 0.12000000000000001, + 20.0: 0.02, + 50.0: 0.01, + 110.0: 0}, + 'sell': {'sell-adx-enabled': False, + 'sell-adx-value': 0, + 'sell-fastd-enabled': True, + 'sell-fastd-value': 75, + 'sell-mfi-enabled': False, + 'sell-mfi-value': 0, + 'sell-rsi-enabled': False, + 'sell-rsi-value': 0, + 'sell-trigger': 'macd_cross_signal'}, + 'stoploss': {'stoploss': -0.4}, + 'trailing': {'trailing_only_offset_is_reached': False, + 'trailing_stop': True, + 'trailing_stop_positive': 0.02, + 'trailing_stop_positive_offset': 0.07}}, + 'params_dict': optimizer_param, + 'results_metrics': {'avg_profit': 2.3117, + 'duration': 100.0, + 'profit': 2.3117, + 'total_profit': 0.000233, + 'trade_count': 1}, + 'total_profit': 0.00023300 } hyperopt = Hyperopt(default_conf) @@ -788,14 +757,13 @@ def test_backtest_params(mocker, default_conf) -> None: def test_clean_hyperopt(mocker, default_conf, caplog): patch_exchange(mocker) - default_conf.update({ - 'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'default', - 'hyperopt_jobs': 1, - }) + 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) @@ -807,15 +775,14 @@ def test_clean_hyperopt(mocker, default_conf, caplog): def test_continue_hyperopt(mocker, default_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 - }) + default_conf.update({'config': 'config.json.example', + 'hyperopt': 'DefaultHyperOpt', + 'epochs': 1, + 'timerange': None, + 'spaces': 'default', + 'hyperopt_jobs': 1, + '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) @@ -828,42 +795,29 @@ def test_print_json_spaces_all(mocker, default_conf, caplog, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) - mocker.patch('freqtrade.optimize.hyperopt.get_timerange', - MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))) + mocker.patch( + 'freqtrade.optimize.hyperopt.get_timerange', + MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))) + ) parallel = mocker.patch( 'freqtrade.optimize.hyperopt.Hyperopt.run_backtest_parallel', - MagicMock(return_value=[{ - 'loss': 1, - 'results_explanation': 'foo result', - 'params': {}, - 'params_details': { - 'buy': { - 'mfi-value': None - }, - 'sell': { - 'sell-mfi-value': None - }, - 'roi': {}, - 'stoploss': { - 'stoploss': None - }, - 'trailing': { - 'trailing_stop': None - } - } - }])) + MagicMock(return_value=[{'loss': 1, 'results_explanation': 'foo result', 'params': {}, + 'params_details': {'buy': {'mfi-value': None}, + 'sell': {'sell-mfi-value': None}, + 'roi': {}, 'stoploss': {'stoploss': None}, + 'trailing': {'trailing_stop': 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, - }) + default_conf.update({'config': 'config.json.example', + 'hyperopt': 'DefaultHyperOpt', + 'epochs': 1, + 'timerange': None, + 'spaces': 'all', + 'hyperopt_jobs': 1, + 'print_json': True, + }) hyperopt = Hyperopt(default_conf) hyperopt.backtesting.strategy.tickerdata_to_dataframe = MagicMock() @@ -887,39 +841,28 @@ def test_print_json_spaces_default(mocker, default_conf, caplog, capsys) -> None dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) - mocker.patch('freqtrade.optimize.hyperopt.get_timerange', - MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))) + mocker.patch( + 'freqtrade.optimize.hyperopt.get_timerange', + MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))) + ) parallel = mocker.patch( 'freqtrade.optimize.hyperopt.Hyperopt.run_backtest_parallel', - MagicMock(return_value=[{ - 'loss': 1, - 'results_explanation': 'foo result', - 'params': {}, - 'params_details': { - 'buy': { - 'mfi-value': None - }, - 'sell': { - 'sell-mfi-value': None - }, - 'roi': {}, - 'stoploss': { - 'stoploss': None - } - } - }])) + MagicMock(return_value=[{'loss': 1, 'results_explanation': 'foo result', 'params': {}, + 'params_details': {'buy': {'mfi-value': None}, + 'sell': {'sell-mfi-value': None}, + 'roi': {}, 'stoploss': {'stoploss': 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, - }) + default_conf.update({'config': 'config.json.example', + 'hyperopt': 'DefaultHyperOpt', + 'epochs': 1, + 'timerange': None, + 'spaces': 'default', + 'hyperopt_jobs': 1, + 'print_json': True, + }) hyperopt = Hyperopt(default_conf) hyperopt.backtesting.strategy.tickerdata_to_dataframe = MagicMock() @@ -943,33 +886,26 @@ def test_print_json_spaces_roi_stoploss(mocker, default_conf, caplog, capsys) -> dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) - mocker.patch('freqtrade.optimize.hyperopt.get_timerange', - MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))) + mocker.patch( + 'freqtrade.optimize.hyperopt.get_timerange', + MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))) + ) parallel = mocker.patch( 'freqtrade.optimize.hyperopt.Hyperopt.run_backtest_parallel', - MagicMock(return_value=[{ - 'loss': 1, - 'results_explanation': 'foo result', - 'params': {}, - 'params_details': { - 'roi': {}, - 'stoploss': { - 'stoploss': None - } - } - }])) + MagicMock(return_value=[{'loss': 1, 'results_explanation': 'foo result', 'params': {}, + 'params_details': {'roi': {}, 'stoploss': {'stoploss': None}}}]) + ) 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, - }) + default_conf.update({'config': 'config.json.example', + 'hyperopt': 'DefaultHyperOpt', + 'epochs': 1, + 'timerange': None, + 'spaces': 'roi stoploss', + 'hyperopt_jobs': 1, + 'print_json': True, + }) hyperopt = Hyperopt(default_conf) hyperopt.backtesting.strategy.tickerdata_to_dataframe = MagicMock() @@ -993,28 +929,24 @@ def test_simplified_interface_roi_stoploss(mocker, default_conf, caplog, capsys) dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) - mocker.patch('freqtrade.optimize.hyperopt.get_timerange', - MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))) + mocker.patch( + 'freqtrade.optimize.hyperopt.get_timerange', + MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))) + ) parallel = mocker.patch( 'freqtrade.optimize.hyperopt.Hyperopt.run_backtest_parallel', MagicMock(return_value=[{ - 'loss': 1, - 'results_explanation': 'foo result', - 'params': { - 'stoploss': 0.0 - } - }])) + 'loss': 1, 'results_explanation': 'foo result', 'params': {'stoploss': 0.0}}]) + ) patch_exchange(mocker) - default_conf.update({ - 'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'roi stoploss', - 'hyperopt_jobs': 1, - }) + default_conf.update({'config': 'config.json.example', + 'hyperopt': 'DefaultHyperOpt', + 'epochs': 1, + 'timerange': None, + 'spaces': 'roi stoploss', + 'hyperopt_jobs': 1, }) hyperopt = Hyperopt(default_conf) hyperopt.backtesting.strategy.tickerdata_to_dataframe = MagicMock() @@ -1048,19 +980,19 @@ def test_simplified_interface_all_failed(mocker, default_conf, caplog, capsys) - mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) - mocker.patch('freqtrade.optimize.hyperopt.get_timerange', - MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))) + mocker.patch( + 'freqtrade.optimize.hyperopt.get_timerange', + MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))) + ) patch_exchange(mocker) - default_conf.update({ - 'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'all', - 'hyperopt_jobs': 1, - }) + default_conf.update({'config': 'config.json.example', + 'hyperopt': 'DefaultHyperOpt', + 'epochs': 1, + 'timerange': None, + 'spaces': 'all', + 'hyperopt_jobs': 1, }) hyperopt = Hyperopt(default_conf) hyperopt.backtesting.strategy.tickerdata_to_dataframe = MagicMock() @@ -1079,26 +1011,23 @@ def test_simplified_interface_buy(mocker, default_conf, caplog, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) - mocker.patch('freqtrade.optimize.hyperopt.get_timerange', - MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))) + mocker.patch( + 'freqtrade.optimize.hyperopt.get_timerange', + MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))) + ) parallel = mocker.patch( 'freqtrade.optimize.hyperopt.Hyperopt.run_backtest_parallel', - MagicMock(return_value=[{ - 'loss': 1, - 'results_explanation': 'foo result', - 'params': {} - }])) + MagicMock(return_value=[{'loss': 1, 'results_explanation': 'foo result', 'params': {}}]) + ) patch_exchange(mocker) - default_conf.update({ - 'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'buy', - 'hyperopt_jobs': 1, - }) + default_conf.update({'config': 'config.json.example', + 'hyperopt': 'DefaultHyperOpt', + 'epochs': 1, + 'timerange': None, + 'spaces': 'buy', + 'hyperopt_jobs': 1, }) hyperopt = Hyperopt(default_conf) hyperopt.backtesting.strategy.tickerdata_to_dataframe = MagicMock() @@ -1132,26 +1061,23 @@ def test_simplified_interface_sell(mocker, default_conf, caplog, capsys) -> None dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) - mocker.patch('freqtrade.optimize.hyperopt.get_timerange', - MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))) + mocker.patch( + 'freqtrade.optimize.hyperopt.get_timerange', + MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))) + ) parallel = mocker.patch( 'freqtrade.optimize.hyperopt.Hyperopt.run_backtest_parallel', - MagicMock(return_value=[{ - 'loss': 1, - 'results_explanation': 'foo result', - 'params': {} - }])) + MagicMock(return_value=[{'loss': 1, 'results_explanation': 'foo result', 'params': {}}]) + ) patch_exchange(mocker) - default_conf.update({ - 'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'sell', - 'hyperopt_jobs': 1, - }) + default_conf.update({'config': 'config.json.example', + 'hyperopt': 'DefaultHyperOpt', + 'epochs': 1, + 'timerange': None, + 'spaces': 'sell', + 'hyperopt_jobs': 1, }) hyperopt = Hyperopt(default_conf) hyperopt.backtesting.strategy.tickerdata_to_dataframe = MagicMock() @@ -1191,19 +1117,19 @@ def test_simplified_interface_failed(mocker, default_conf, caplog, capsys, metho mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) - mocker.patch('freqtrade.optimize.hyperopt.get_timerange', - MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))) + mocker.patch( + 'freqtrade.optimize.hyperopt.get_timerange', + MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))) + ) patch_exchange(mocker) - default_conf.update({ - 'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': space, - 'hyperopt_jobs': 1, - }) + default_conf.update({'config': 'config.json.example', + 'hyperopt': 'DefaultHyperOpt', + 'epochs': 1, + 'timerange': None, + 'spaces': space, + 'hyperopt_jobs': 1, }) hyperopt = Hyperopt(default_conf) hyperopt.backtesting.strategy.tickerdata_to_dataframe = MagicMock()