diff --git a/freqtrade/optimize/hyperopt_tools.py b/freqtrade/optimize/hyperopt_tools.py index 65bdc4db5..393c055c4 100755 --- a/freqtrade/optimize/hyperopt_tools.py +++ b/freqtrade/optimize/hyperopt_tools.py @@ -12,7 +12,7 @@ import tabulate from colorama import Fore, Style from pandas import isna, json_normalize -from freqtrade.constants import FTHYPT_FILEVERSION, USERPATH_STRATEGIES, Config +from freqtrade.constants import FTHYPT_FILEVERSION, Config from freqtrade.enums import HyperoptState from freqtrade.exceptions import OperationalException from freqtrade.misc import deep_merge_dicts, round_coin_value, round_dict, safe_value_fallback2 @@ -50,9 +50,8 @@ class HyperoptTools(): Get Strategy-location (filename) from strategy_name """ from freqtrade.resolvers.strategy_resolver import StrategyResolver - directory = Path(config.get('strategy_path', config['user_data_dir'] / USERPATH_STRATEGIES)) strategy_objs = StrategyResolver.search_all_objects( - directory, False, config.get('recursive_strategy_search', False)) + config, False, config.get('recursive_strategy_search', False)) strategies = [s for s in strategy_objs if s['name'] == strategy_name] if strategies: strategy = strategies[0] diff --git a/freqtrade/resolvers/iresolver.py b/freqtrade/resolvers/iresolver.py index df21f5a2d..56376baa4 100644 --- a/freqtrade/resolvers/iresolver.py +++ b/freqtrade/resolvers/iresolver.py @@ -196,7 +196,6 @@ class IResolver: result = [] abs_paths = cls.build_search_paths(config, user_subdir=cls.user_subdir) - print(abs_paths) for path in abs_paths: result.extend(cls._search_all_objects(path, enum_failed, recursive)) return result @@ -209,8 +208,9 @@ class IResolver: directory) @classmethod - def _search_all_objects(cls, directory: Path, enum_failed: bool, - recursive: bool = False) -> List[Dict[str, Any]]: + def _search_all_objects( + cls, directory: Path, enum_failed: bool, recursive: bool = False, + basedir: Optional[Path] = None) -> List[Dict[str, Any]]: """ Searches a directory for valid objects :param directory: Path to search @@ -230,7 +230,8 @@ class IResolver: and not entry.name.startswith('__') and not entry.name.startswith('.') ): - objects.extend(cls._search_all_objects(entry, enum_failed, recursive=recursive)) + objects.extend(cls._search_all_objects( + entry, enum_failed, recursive, basedir or directory)) # Only consider python files if entry.suffix != '.py': logger.debug('Ignoring %s', entry) @@ -243,6 +244,6 @@ class IResolver: {'name': obj[0].__name__ if obj is not None else '', 'class': obj[0] if obj is not None else None, 'location': entry, - 'location_rel': cls._build_rel_location(directory, entry), + 'location_rel': cls._build_rel_location(basedir or directory, entry), }) return objects diff --git a/freqtrade/resolvers/strategy_resolver.py b/freqtrade/resolvers/strategy_resolver.py index c574246ac..a1eb3d190 100644 --- a/freqtrade/resolvers/strategy_resolver.py +++ b/freqtrade/resolvers/strategy_resolver.py @@ -268,6 +268,14 @@ class StrategyResolver(IResolver): "or contains Python code errors." ) + @classmethod + def build_search_paths(cls, config: Config, user_subdir: Optional[str] = None, + extra_dirs: List[str] = []) -> List[Path]: + + if 'strategy_path' in config: + extra_dirs = [config['strategy_path']] + extra_dirs + return super().build_search_paths(config, user_subdir, extra_dirs) + def warn_deprecated_setting(strategy: IStrategy, old: str, new: str, error=False): if hasattr(strategy, old): diff --git a/freqtrade/rpc/api_server/api_v1.py b/freqtrade/rpc/api_server/api_v1.py index 135892dc6..0e6f9500a 100644 --- a/freqtrade/rpc/api_server/api_v1.py +++ b/freqtrade/rpc/api_server/api_v1.py @@ -253,11 +253,9 @@ def plot_config(rpc: RPC = Depends(get_rpc)): @router.get('/strategies', response_model=StrategyListResponse, tags=['strategy']) def list_strategies(config=Depends(get_config)): - directory = Path(config.get( - 'strategy_path', config['user_data_dir'] / USERPATH_STRATEGIES)) from freqtrade.resolvers.strategy_resolver import StrategyResolver strategies = StrategyResolver.search_all_objects( - directory, False, config.get('recursive_strategy_search', False)) + config, False, config.get('recursive_strategy_search', False)) strategies = sorted(strategies, key=lambda x: x['name']) return {'strategies': [x['name'] for x in strategies]} diff --git a/tests/strategy/test_strategy_loading.py b/tests/strategy/test_strategy_loading.py index adffd0875..8b9ae658b 100644 --- a/tests/strategy/test_strategy_loading.py +++ b/tests/strategy/test_strategy_loading.py @@ -32,7 +32,7 @@ def test_search_strategy(): def test_search_all_strategies_no_failed(): directory = Path(__file__).parent / "strats" - strategies = StrategyResolver.search_all_objects(directory, enum_failed=False) + strategies = StrategyResolver._search_all_objects(directory, enum_failed=False) assert isinstance(strategies, list) assert len(strategies) == 9 assert isinstance(strategies[0], dict) @@ -40,7 +40,7 @@ def test_search_all_strategies_no_failed(): def test_search_all_strategies_with_failed(): directory = Path(__file__).parent / "strats" - strategies = StrategyResolver.search_all_objects(directory, enum_failed=True) + strategies = StrategyResolver._search_all_objects(directory, enum_failed=True) assert isinstance(strategies, list) assert len(strategies) == 10 # with enum_failed=True search_all_objects() shall find 2 good strategies @@ -49,7 +49,7 @@ def test_search_all_strategies_with_failed(): assert len([x for x in strategies if x['class'] is None]) == 1 directory = Path(__file__).parent / "strats_nonexistingdir" - strategies = StrategyResolver.search_all_objects(directory, enum_failed=True) + strategies = StrategyResolver._search_all_objects(directory, enum_failed=True) assert len(strategies) == 0