From a5e670b4023c2ae50a3441714d607f84ce8b0010 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Sun, 2 Feb 2020 18:07:21 +0300 Subject: [PATCH 1/7] Add USERPATH_NOTEBOOKS --- freqtrade/constants.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 53bc4af53..23a60ed0e 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -23,6 +23,7 @@ MATH_CLOSE_PREC = 1e-14 # Precision used for float comparisons USERPATH_HYPEROPTS = 'hyperopts' USERPATH_STRATEGY = 'strategies' +USERPATH_NOTEBOOKS = 'notebooks' # Soure files with destination directories within user-directory USER_DATA_FILES = { @@ -30,7 +31,7 @@ USER_DATA_FILES = { 'sample_hyperopt_advanced.py': USERPATH_HYPEROPTS, 'sample_hyperopt_loss.py': USERPATH_HYPEROPTS, 'sample_hyperopt.py': USERPATH_HYPEROPTS, - 'strategy_analysis_example.ipynb': 'notebooks', + 'strategy_analysis_example.ipynb': USERPATH_NOTEBOOKS, } SUPPORTED_FIAT = [ From 3fe39a3e1b3e494cd8ebaff1718e809845a324de Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Sun, 2 Feb 2020 18:12:23 +0300 Subject: [PATCH 2/7] Rename constant --- freqtrade/commands/deploy_commands.py | 4 ++-- freqtrade/commands/list_commands.py | 4 ++-- freqtrade/constants.py | 4 ++-- freqtrade/resolvers/strategy_resolver.py | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/freqtrade/commands/deploy_commands.py b/freqtrade/commands/deploy_commands.py index 99ae63244..e0935f0e5 100644 --- a/freqtrade/commands/deploy_commands.py +++ b/freqtrade/commands/deploy_commands.py @@ -6,7 +6,7 @@ from typing import Any, Dict from freqtrade.configuration import setup_utils_configuration from freqtrade.configuration.directory_operations import (copy_sample_files, create_userdata_dir) -from freqtrade.constants import USERPATH_HYPEROPTS, USERPATH_STRATEGY +from freqtrade.constants import USERPATH_HYPEROPTS, USERPATH_STRATEGIES from freqtrade.exceptions import OperationalException from freqtrade.misc import render_template from freqtrade.state import RunMode @@ -57,7 +57,7 @@ def start_new_strategy(args: Dict[str, Any]) -> None: if args["strategy"] == "DefaultStrategy": raise OperationalException("DefaultStrategy is not allowed as name.") - new_path = config['user_data_dir'] / USERPATH_STRATEGY / (args["strategy"] + ".py") + new_path = config['user_data_dir'] / USERPATH_STRATEGIES / (args["strategy"] + ".py") if new_path.exists(): raise OperationalException(f"`{new_path}` already exists. " diff --git a/freqtrade/commands/list_commands.py b/freqtrade/commands/list_commands.py index 022822782..9fe66783d 100644 --- a/freqtrade/commands/list_commands.py +++ b/freqtrade/commands/list_commands.py @@ -9,7 +9,7 @@ import rapidjson from tabulate import tabulate from freqtrade.configuration import setup_utils_configuration -from freqtrade.constants import USERPATH_STRATEGY +from freqtrade.constants import USERPATH_HYPEROPTS, USERPATH_STRATEGIES from freqtrade.exceptions import OperationalException from freqtrade.exchange import (available_exchanges, ccxt_exchanges, market_is_active, symbol_is_pair) @@ -42,7 +42,7 @@ def start_list_strategies(args: Dict[str, Any]) -> None: """ config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) - directory = Path(config.get('strategy_path', config['user_data_dir'] / USERPATH_STRATEGY)) + directory = Path(config.get('strategy_path', config['user_data_dir'] / USERPATH_STRATEGIES)) strategies = StrategyResolver.search_all_objects(directory) # Sort alphabetically strategies = sorted(strategies, key=lambda x: x['name']) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 23a60ed0e..efdd6cc0e 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -22,12 +22,12 @@ DRY_RUN_WALLET = 1000 MATH_CLOSE_PREC = 1e-14 # Precision used for float comparisons USERPATH_HYPEROPTS = 'hyperopts' -USERPATH_STRATEGY = 'strategies' +USERPATH_STRATEGIES = 'strategies' USERPATH_NOTEBOOKS = 'notebooks' # Soure files with destination directories within user-directory USER_DATA_FILES = { - 'sample_strategy.py': USERPATH_STRATEGY, + 'sample_strategy.py': USERPATH_STRATEGIES, 'sample_hyperopt_advanced.py': USERPATH_HYPEROPTS, 'sample_hyperopt_loss.py': USERPATH_HYPEROPTS, 'sample_hyperopt.py': USERPATH_HYPEROPTS, diff --git a/freqtrade/resolvers/strategy_resolver.py b/freqtrade/resolvers/strategy_resolver.py index 9e64f38df..7f28bd2e6 100644 --- a/freqtrade/resolvers/strategy_resolver.py +++ b/freqtrade/resolvers/strategy_resolver.py @@ -12,7 +12,7 @@ from pathlib import Path from typing import Dict, Optional from freqtrade.constants import (REQUIRED_ORDERTIF, REQUIRED_ORDERTYPES, - USERPATH_STRATEGY) + USERPATH_STRATEGIES) from freqtrade.exceptions import OperationalException from freqtrade.resolvers import IResolver from freqtrade.strategy.interface import IStrategy @@ -26,7 +26,7 @@ class StrategyResolver(IResolver): """ object_type = IStrategy object_type_str = "Strategy" - user_subdir = USERPATH_STRATEGY + user_subdir = USERPATH_STRATEGIES initial_search_path = Path(__file__).parent.parent.joinpath('strategy').resolve() @staticmethod @@ -140,7 +140,7 @@ class StrategyResolver(IResolver): """ abs_paths = StrategyResolver.build_search_paths(config, - user_subdir=USERPATH_STRATEGY, + user_subdir=USERPATH_STRATEGIES, extra_dir=extra_dir) if ":" in strategy_name: From 857eb5ff6994cd3a5c8765cf6d43b5b01be1dc3c Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Sun, 2 Feb 2020 18:48:29 +0300 Subject: [PATCH 3/7] Add list-hyperopts command --- freqtrade/commands/__init__.py | 1 + freqtrade/commands/arguments.py | 18 +++++++++++++++--- freqtrade/commands/list_commands.py | 22 +++++++++++++++++++++- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/freqtrade/commands/__init__.py b/freqtrade/commands/__init__.py index 990c1107a..17723715e 100644 --- a/freqtrade/commands/__init__.py +++ b/freqtrade/commands/__init__.py @@ -14,6 +14,7 @@ from freqtrade.commands.deploy_commands import (start_create_userdir, 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, start_list_timeframes) diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index 724814554..0995c89c4 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -32,6 +32,8 @@ ARGS_EDGE = ARGS_COMMON_OPTIMIZE + ["stoploss_range"] ARGS_LIST_STRATEGIES = ["strategy_path", "print_one_column"] +ARGS_LIST_HYPEROPTS = ["hyperopt_path", "print_one_column"] + ARGS_LIST_EXCHANGES = ["print_one_column", "list_exchanges_all"] ARGS_LIST_TIMEFRAMES = ["exchange", "print_one_column"] @@ -132,9 +134,10 @@ class Arguments: from freqtrade.commands import (start_create_userdir, start_download_data, start_hyperopt_list, start_hyperopt_show, - start_list_exchanges, start_list_markets, - start_list_strategies, start_new_hyperopt, - start_new_strategy, start_list_timeframes, + start_list_exchanges, start_list_hyperopts, + start_list_markets, start_list_strategies, + start_list_timeframes, + start_new_hyperopt, start_new_strategy, start_plot_dataframe, start_plot_profit, start_backtesting, start_hyperopt, start_edge, start_test_pairlist, start_trading) @@ -198,6 +201,15 @@ class Arguments: list_strategies_cmd.set_defaults(func=start_list_strategies) self._build_args(optionlist=ARGS_LIST_STRATEGIES, parser=list_strategies_cmd) + # Add list-hyperopts subcommand + list_hyperopts_cmd = subparsers.add_parser( + 'list-hyperopts', + help='Print available hyperopt classes.', + parents=[_common_parser], + ) + list_hyperopts_cmd.set_defaults(func=start_list_hyperopts) + self._build_args(optionlist=ARGS_LIST_HYPEROPTS, parser=list_hyperopts_cmd) + # Add list-exchanges subcommand list_exchanges_cmd = subparsers.add_parser( 'list-exchanges', diff --git a/freqtrade/commands/list_commands.py b/freqtrade/commands/list_commands.py index 9fe66783d..f2b6bf995 100644 --- a/freqtrade/commands/list_commands.py +++ b/freqtrade/commands/list_commands.py @@ -38,7 +38,7 @@ def start_list_exchanges(args: Dict[str, Any]) -> None: def start_list_strategies(args: Dict[str, Any]) -> None: """ - Print Strategies available in a directory + Print files with Strategy custom classes available in the directory """ config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) @@ -54,6 +54,26 @@ def start_list_strategies(args: Dict[str, Any]) -> None: print(tabulate(strats_to_print, headers='keys', tablefmt='pipe')) +def start_list_hyperopts(args: Dict[str, Any]) -> None: + """ + Print files with HyperOpt custom classes available in the directory + """ + from freqtrade.resolvers.hyperopt_resolver import HyperOptResolver + + config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) + + directory = Path(config.get('hyperopt_path', config['user_data_dir'] / USERPATH_HYPEROPTS)) + hyperopts = HyperOptResolver.search_all_objects(directory) + # Sort alphabetically + hyperopts = sorted(hyperopts, key=lambda x: x['name']) + hyperopts_to_print = [{'name': s['name'], 'location': s['location'].name} for s in hyperopts] + + if args['print_one_column']: + print('\n'.join([s['name'] for s in hyperopts])) + else: + print(tabulate(hyperopts_to_print, headers='keys', tablefmt='pipe')) + + def start_list_timeframes(args: Dict[str, Any]) -> None: """ Print ticker intervals (timeframes) available on Exchange From 505648fb661ea792d555ece1355e241079e9af82 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Sun, 2 Feb 2020 18:56:54 +0300 Subject: [PATCH 4/7] Adjust docs --- docs/utils.md | 51 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/docs/utils.md b/docs/utils.md index 18deeac54..b0559f9cc 100644 --- a/docs/utils.md +++ b/docs/utils.md @@ -108,9 +108,9 @@ With custom user directory freqtrade new-hyperopt --userdir ~/.freqtrade/ --hyperopt AwesomeHyperopt ``` -## List Strategies +## List Strategies and List Hyperopts -Use the `list-strategies` subcommand to see all strategies in one particular directory. +Use the `list-strategies` subcommand to see all strategies in one particular directory and the `list-hyperopts` subcommand to list custom Hyperopts. ``` freqtrade list-strategies --help @@ -133,22 +133,63 @@ Common arguments: --userdir PATH, --user-data-dir PATH Path to userdata directory. ``` +``` +freqtrade list-hyperopts --help +usage: freqtrade list-hyperopts [-h] [-v] [--logfile FILE] [-V] [-c PATH] + [-d PATH] [--userdir PATH] + [--hyperopt-path PATH] [-1] + +optional arguments: + -h, --help show this help message and exit + --hyperopt-path PATH Specify additional lookup path for Hyperopt and + Hyperopt Loss functions. + -1, --one-column Print output in one column. + +Common arguments: + -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). + --logfile FILE Log to the file specified. Special values are: + 'syslog', 'journald'. See the documentation for more + details. + -V, --version show program's version number and exit + -c PATH, --config PATH + Specify configuration file (default: `config.json`). + Multiple --config options may be used. Can be set to + `-` to read config from stdin. + -d PATH, --datadir PATH + Path to directory with historical backtesting data. + --userdir PATH, --user-data-dir PATH + Path to userdata directory. +``` !!! Warning - Using this command will try to load all python files from a directory. This can be a security risk if untrusted files reside in this directory, since all module-level code is executed. + Using these commands will try to load all python files from a directory. This can be a security risk if untrusted files reside in this directory, since all module-level code is executed. -Example: search default strategy directory within userdir +Example: Search default strategies and hyperopts directories (within the default userdir). + +``` bash +freqtrade list-strategies +freqtrade list-hyperopts +``` + +Example: Search strategies and hyperopts directory within the userdir. ``` bash freqtrade list-strategies --userdir ~/.freqtrade/ +freqtrade list-hyperopts --userdir ~/.freqtrade/ ``` -Example: search dedicated strategy path +Example: Search dedicated strategy path. ``` bash freqtrade list-strategies --strategy-path ~/.freqtrade/strategies/ ``` +Example: Search dedicated hyperopt path. + +``` bash +freqtrade list-hyperopt --hyperopt-path ~/.freqtrade/hyperopts/ +``` + ## List Exchanges Use the `list-exchanges` subcommand to see the exchanges available for the bot. From cd0534efcc1a0fa7d748508d22fff7972b643be2 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Sun, 2 Feb 2020 19:13:17 +0300 Subject: [PATCH 5/7] Add test --- tests/commands/test_commands.py | 36 ++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index 65d7f6eaf..c59799190 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -7,7 +7,8 @@ import pytest from freqtrade.commands import (start_create_userdir, start_download_data, start_hyperopt_list, start_hyperopt_show, start_list_exchanges, start_list_markets, - start_list_strategies, start_list_timeframes, + start_list_hyperopts, start_list_strategies, + start_list_timeframes, start_new_hyperopt, start_new_strategy, start_test_pairlist, start_trading) from freqtrade.configuration import setup_utils_configuration @@ -665,6 +666,39 @@ def test_start_list_strategies(mocker, caplog, capsys): assert "DefaultStrategy" in captured.out +def test_start_list_hyperopts(mocker, caplog, capsys): + + args = [ + "list-hyperopts", + "--hyperopt-path", + str(Path(__file__).parent.parent / "optimize"), + "-1" + ] + pargs = get_args(args) + # pargs['config'] = None + start_list_hyperopts(pargs) + captured = capsys.readouterr() + assert "TestHyperoptLegacy" not in captured.out + assert "legacy_hyperopt.py" not in captured.out + assert "DefaultHyperOpt" in captured.out + assert "test_hyperopt.py" not in captured.out + + # Test regular output + args = [ + "list-hyperopts", + "--hyperopt-path", + str(Path(__file__).parent.parent / "optimize"), + ] + pargs = get_args(args) + # pargs['config'] = None + start_list_hyperopts(pargs) + captured = capsys.readouterr() + assert "TestHyperoptLegacy" not in captured.out + assert "legacy_hyperopt.py" not in captured.out + assert "DefaultHyperOpt" in captured.out + assert "test_hyperopt.py" in captured.out + + def test_start_test_pairlist(mocker, caplog, tickers, default_conf, capsys): patch_exchange(mocker, mock_markets=True) mocker.patch.multiple('freqtrade.exchange.Exchange', From d12e03e50d30c13f57e5fa661ebf78d388051310 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Sun, 2 Feb 2020 20:01:25 +0300 Subject: [PATCH 6/7] Fix test inconsistency in test_freqtradebot.py --- tests/test_freqtradebot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 5f16894ab..f334e4eb0 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1145,11 +1145,11 @@ def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog, # Should not create new order trade.stoploss_order_id = None trade.is_open = False - stoploss_limit.reset_mock() + stoploss.reset_mock() mocker.patch('freqtrade.exchange.Exchange.get_order') - mocker.patch('freqtrade.exchange.Exchange.stoploss_limit', stoploss_limit) + mocker.patch('freqtrade.exchange.Exchange.stoploss', stoploss) assert freqtrade.handle_stoploss_on_exchange(trade) is False - assert stoploss_limit.call_count == 0 + assert stoploss.call_count == 0 def test_handle_sle_cancel_cant_recreate(mocker, default_conf, fee, caplog, From 84156879f6e96e18e6e60589bc2f45d2bb989261 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Sun, 2 Feb 2020 20:11:42 +0300 Subject: [PATCH 7/7] Fix NO_CONF_REQUIRED for list-hyperopts --- freqtrade/commands/arguments.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index 0995c89c4..1931a51be 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -66,8 +66,8 @@ ARGS_HYPEROPT_SHOW = ["hyperopt_list_best", "hyperopt_list_profitable", "hyperop "print_json", "hyperopt_show_no_header"] NO_CONF_REQURIED = ["download-data", "list-timeframes", "list-markets", "list-pairs", - "list-strategies", "hyperopt-list", "hyperopt-show", "plot-dataframe", - "plot-profit"] + "list-strategies", "list-hyperopts", "hyperopt-list", "hyperopt-show", + "plot-dataframe", "plot-profit"] NO_CONF_ALLOWED = ["create-userdir", "list-exchanges", "new-hyperopt", "new-strategy"]