Cleanup some code and add option
This commit is contained in:
parent
5a11ca86bb
commit
2ab989e274
@ -30,7 +30,7 @@ ARGS_HYPEROPT = ARGS_COMMON_OPTIMIZE + ["hyperopt", "hyperopt_path",
|
|||||||
|
|
||||||
ARGS_EDGE = ARGS_COMMON_OPTIMIZE + ["stoploss_range"]
|
ARGS_EDGE = ARGS_COMMON_OPTIMIZE + ["stoploss_range"]
|
||||||
|
|
||||||
ARGS_LIST_STRATEGIES = ["strategy_path"]
|
ARGS_LIST_STRATEGIES = ["strategy_path", "print_one_column"]
|
||||||
|
|
||||||
ARGS_LIST_EXCHANGES = ["print_one_column", "list_exchanges_all"]
|
ARGS_LIST_EXCHANGES = ["print_one_column", "list_exchanges_all"]
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import importlib.util
|
|||||||
import inspect
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Generator, List, Optional, Tuple, Type, Union
|
from typing import Any, Dict, Generator, List, Optional, Tuple, Type, Union
|
||||||
|
|
||||||
from freqtrade import OperationalException
|
from freqtrade import OperationalException
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ class IResolver:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _get_valid_object(cls, module_path: Path,
|
def _get_valid_object(cls, module_path: Path,
|
||||||
object_name: str) -> Generator[Any, None, None]:
|
object_name: Optional[str]) -> Generator[Any, None, None]:
|
||||||
"""
|
"""
|
||||||
Generator returning objects with matching object_type and object_name in the path given.
|
Generator returning objects with matching object_type and object_name in the path given.
|
||||||
:param module_path: absolute path to the module
|
:param module_path: absolute path to the module
|
||||||
@ -51,7 +51,7 @@ class IResolver:
|
|||||||
|
|
||||||
# Generate spec based on absolute path
|
# Generate spec based on absolute path
|
||||||
# Pass object_name as first argument to have logging print a reasonable name.
|
# Pass object_name as first argument to have logging print a reasonable name.
|
||||||
spec = importlib.util.spec_from_file_location(object_name, str(module_path))
|
spec = importlib.util.spec_from_file_location(object_name or "", str(module_path))
|
||||||
module = importlib.util.module_from_spec(spec)
|
module = importlib.util.module_from_spec(spec)
|
||||||
try:
|
try:
|
||||||
spec.loader.exec_module(module) # type: ignore # importlib does not use typehints
|
spec.loader.exec_module(module) # type: ignore # importlib does not use typehints
|
||||||
@ -61,7 +61,7 @@ class IResolver:
|
|||||||
|
|
||||||
valid_objects_gen = (
|
valid_objects_gen = (
|
||||||
obj for name, obj in inspect.getmembers(module, inspect.isclass)
|
obj for name, obj in inspect.getmembers(module, inspect.isclass)
|
||||||
if object_name == name and cls.object_type in obj.__bases__
|
if (object_name is None or object_name == name) and cls.object_type in obj.__bases__
|
||||||
)
|
)
|
||||||
return valid_objects_gen
|
return valid_objects_gen
|
||||||
|
|
||||||
@ -74,8 +74,7 @@ class IResolver:
|
|||||||
:param object_name: ClassName of the object to load
|
:param object_name: ClassName of the object to load
|
||||||
:return: object class
|
:return: object class
|
||||||
"""
|
"""
|
||||||
logger.debug("Searching for %s %s in '%s'",
|
logger.debug(f"Searching for {cls.object_type.__name__} {object_name} in '{directory}'")
|
||||||
cls.object_type.__name__, object_name, directory)
|
|
||||||
for entry in directory.iterdir():
|
for entry in directory.iterdir():
|
||||||
# Only consider python files
|
# Only consider python files
|
||||||
if not str(entry).endswith('.py'):
|
if not str(entry).endswith('.py'):
|
||||||
@ -134,3 +133,27 @@ class IResolver:
|
|||||||
f"Impossible to load {cls.object_type_str} '{object_name}'. This class does not exist "
|
f"Impossible to load {cls.object_type_str} '{object_name}'. This class does not exist "
|
||||||
"or contains Python code errors."
|
"or contains Python code errors."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def search_all_objects(cls, directory: Path) -> List[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
Searches a directory for valid objects
|
||||||
|
:param directory: Path to search
|
||||||
|
:return: List of dicts containing 'name', 'class' and 'location' entires
|
||||||
|
"""
|
||||||
|
logger.debug(f"Searching for {cls.object_type.__name__} '{directory}'")
|
||||||
|
objects = []
|
||||||
|
for entry in directory.iterdir():
|
||||||
|
# Only consider python files
|
||||||
|
if not str(entry).endswith('.py'):
|
||||||
|
logger.debug('Ignoring %s', entry)
|
||||||
|
continue
|
||||||
|
module_path = entry.resolve()
|
||||||
|
logger.info(f"Path {module_path}")
|
||||||
|
for obj in cls._get_valid_object(module_path, object_name=None):
|
||||||
|
objects.append(
|
||||||
|
{'name': obj.__name__,
|
||||||
|
'class': obj,
|
||||||
|
'location': entry,
|
||||||
|
})
|
||||||
|
return objects
|
||||||
|
@ -23,7 +23,7 @@ from freqtrade.data.history import (convert_trades_to_ohlcv,
|
|||||||
from freqtrade.exchange import (available_exchanges, ccxt_exchanges,
|
from freqtrade.exchange import (available_exchanges, ccxt_exchanges,
|
||||||
market_is_active, symbol_is_pair)
|
market_is_active, symbol_is_pair)
|
||||||
from freqtrade.misc import plural, render_template
|
from freqtrade.misc import plural, render_template
|
||||||
from freqtrade.resolvers import ExchangeResolver
|
from freqtrade.resolvers import ExchangeResolver, StrategyResolver
|
||||||
from freqtrade.state import RunMode
|
from freqtrade.state import RunMode
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -229,7 +229,17 @@ def start_list_strategies(args: Dict[str, Any]) -> None:
|
|||||||
Print Strategies available in a folder
|
Print Strategies available in a folder
|
||||||
"""
|
"""
|
||||||
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
||||||
print(config)
|
|
||||||
|
directory = Path(config.get('strategy_path', config['user_data_dir'] / USERPATH_STRATEGY))
|
||||||
|
strategies = StrategyResolver.search_all_objects(directory)
|
||||||
|
# Sort alphabetically
|
||||||
|
strategies = sorted(strategies, key=lambda x: x['name'])
|
||||||
|
strats_to_print = [{'name': s['name'], 'location': s['location']} for s in strategies]
|
||||||
|
|
||||||
|
if args['print_one_column']:
|
||||||
|
print('\n'.join([s['name'] for s in strategies]))
|
||||||
|
else:
|
||||||
|
print(tabulate(strats_to_print, headers='keys', tablefmt='pipe'))
|
||||||
|
|
||||||
|
|
||||||
def start_list_timeframes(args: Dict[str, Any]) -> None:
|
def start_list_timeframes(args: Dict[str, Any]) -> None:
|
||||||
|
Loading…
Reference in New Issue
Block a user