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