diff --git a/freqtrade/commands/__init__.py b/freqtrade/commands/__init__.py index 784b99bed..2229ea295 100644 --- a/freqtrade/commands/__init__.py +++ b/freqtrade/commands/__init__.py @@ -12,6 +12,8 @@ from freqtrade.commands.data_commands import (start_convert_data, start_download start_list_data) from freqtrade.commands.deploy_commands import (start_create_userdir, start_install_ui, start_new_hyperopt, start_new_strategy) +from freqtrade.commands.automation_commands import start_build_hyperopt + from freqtrade.commands.hyperopt_commands import start_hyperopt_list, start_hyperopt_show from freqtrade.commands.list_commands import (start_list_exchanges, start_list_hyperopts, start_list_markets, start_list_strategies, diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index c64c11a18..feebfe279 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -55,6 +55,8 @@ ARGS_BUILD_STRATEGY = ["user_data_dir", "strategy", "template"] ARGS_BUILD_HYPEROPT = ["user_data_dir", "hyperopt", "template"] +ARGS_BUILD_CUSTOM_HYPEROPT = ["buy_indicators", "sell_indicators", "hyperopt"] + ARGS_CONVERT_DATA = ["pairs", "format_from", "format_to", "erase"] ARGS_CONVERT_DATA_OHLCV = ARGS_CONVERT_DATA + ["timeframes"] @@ -173,6 +175,7 @@ class Arguments: start_list_data, start_list_exchanges, start_list_hyperopts, start_list_markets, start_list_strategies, start_list_timeframes, start_new_config, start_new_hyperopt, + start_build_hyperopt, start_new_strategy, start_plot_dataframe, start_plot_profit, start_show_trades, start_test_pairlist, start_trading) @@ -207,6 +210,12 @@ class Arguments: build_hyperopt_cmd.set_defaults(func=start_new_hyperopt) self._build_args(optionlist=ARGS_BUILD_HYPEROPT, parser=build_hyperopt_cmd) + # add build-hyperopt subcommand + build_custom_hyperopt_cmd = subparsers.add_parser('build-hyperopt', + help="Build a custom hyperopt") + build_custom_hyperopt_cmd.set_defaults(func=start_build_hyperopt) + self._build_args(optionlist=ARGS_BUILD_CUSTOM_HYPEROPT, parser=build_custom_hyperopt_cmd) + # add new-strategy subcommand build_strategy_cmd = subparsers.add_parser('new-strategy', help="Create new strategy") diff --git a/freqtrade/commands/automation_commands.py b/freqtrade/commands/automation_commands.py new file mode 100644 index 000000000..098baad32 --- /dev/null +++ b/freqtrade/commands/automation_commands.py @@ -0,0 +1,71 @@ +import logging +from pathlib import Path +from typing import Any, Dict + +from freqtrade.constants import USERPATH_HYPEROPTS +from freqtrade.exceptions import OperationalException +from freqtrade.state import RunMode +from freqtrade.configuration import setup_utils_configuration +from freqtrade.misc import render_template, render_template_with_fallback + +logger = logging.getLogger(__name__) + + +def deploy_custom_hyperopt(hyperopt_name: str, hyperopt_path: Path, buy_indicators: str, sell_indicators: str) -> None: + """ + Deploys a custom hyperopt template to hyperopt_path + TODO make the code below more dynamic with a large list of indicators instead of a few templates + """ + fallback = 'full' + buy_guards = render_template_with_fallback( + templatefile=f"subtemplates/hyperopt_buy_guards_{subtemplate}.j2", + templatefallbackfile=f"subtemplates/hyperopt_buy_guards_{fallback}.j2", + ) + sell_guards = render_template_with_fallback( + templatefile=f"subtemplates/hyperopt_sell_guards_{subtemplate}.j2", + templatefallbackfile=f"subtemplates/hyperopt_sell_guards_{fallback}.j2", + ) + buy_space = render_template_with_fallback( + templatefile=f"subtemplates/hyperopt_buy_space_{subtemplate}.j2", + templatefallbackfile=f"subtemplates/hyperopt_buy_space_{fallback}.j2", + ) + sell_space = render_template_with_fallback( + templatefile=f"subtemplates/hyperopt_sell_space_{subtemplate}.j2", + templatefallbackfile=f"subtemplates/hyperopt_sell_space_{fallback}.j2", + ) + + strategy_text = render_template(templatefile='base_hyperopt.py.j2', + arguments={"hyperopt": hyperopt_name, + "buy_guards": buy_guards, + "sell_guards": sell_guards, + "buy_space": buy_space, + "sell_space": sell_space, + }) + + logger.info(f"Writing custom hyperopt to `{hyperopt_path}`.") + hyperopt_path.write_text(strategy_text) + + +def start_build_hyperopt(args: Dict[str, Any]) -> None: + """ + Check if the right subcommands where passed and start building the hyperopt + """ + config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) + + # check what the name of the hyperopt should + if not 'hyperopt' in args or not args['hyperopt']: + raise OperationalException("`build-hyperopt` requires --hyperopt to be set.") + elif not 'buy_indicators' in args or not args['buy_indicators']: + raise OperationalException("`build-hyperopt` requires --buy-indicators to be set.") + elif not 'sell_indicators' in args or not args['sell_indicators']: + raise OperationalException("`build-hyperopt` requires --sell-indicators to be set.") + else: + if args['hyperopt'] == 'DefaultHyperopt': + raise OperationalException("DefaultHyperopt is not allowed as name.") + + new_path = config['user_data_dir'] / USERPATH_HYPEROPTS / (args['hyperopt'] + '.py') + if new_path.exists(): + raise OperationalException(f"`{new_path}` already exists. " + "Please choose another Hyperopt Name.") + deploy_custom_hyperopt(args['hyperopt'], new_path, + args['buy_indicators'], args['sell_indicators']) diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index 7dc85377d..2aba5c606 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -439,6 +439,15 @@ AVAILABLE_CLI_OPTIONS = { help='Specify the list of trade ids.', nargs='+', ), + # automation + "buy_indicators": Arg( + '-b', '--buy-indicators', + help='Specify the buy indicators the hyperopt should build.' + ), + "sell_indicators": Arg( + '-s', '--sell-indicators', + help='Specify the buy indicators the hyperopt should build.' + ), # hyperopt-list, hyperopt-show "hyperopt_list_profitable": Arg( '--profitable',