Cleanup some code and add option

This commit is contained in:
Matthias 2019-12-24 15:28:35 +01:00
parent 5a11ca86bb
commit 2ab989e274
3 changed files with 42 additions and 9 deletions

View File

@ -30,7 +30,7 @@ ARGS_HYPEROPT = ARGS_COMMON_OPTIMIZE + ["hyperopt", "hyperopt_path",
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"]

View File

@ -7,7 +7,7 @@ import importlib.util
import inspect
import logging
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
@ -41,7 +41,7 @@ class IResolver:
@classmethod
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.
:param module_path: absolute path to the module
@ -51,7 +51,7 @@ class IResolver:
# Generate spec based on absolute path
# 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)
try:
spec.loader.exec_module(module) # type: ignore # importlib does not use typehints
@ -61,7 +61,7 @@ class IResolver:
valid_objects_gen = (
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
@ -74,8 +74,7 @@ class IResolver:
:param object_name: ClassName of the object to load
:return: object class
"""
logger.debug("Searching for %s %s in '%s'",
cls.object_type.__name__, object_name, directory)
logger.debug(f"Searching for {cls.object_type.__name__} {object_name} in '{directory}'")
for entry in directory.iterdir():
# Only consider python files
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 "
"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

View File

@ -23,7 +23,7 @@ from freqtrade.data.history import (convert_trades_to_ohlcv,
from freqtrade.exchange import (available_exchanges, ccxt_exchanges,
market_is_active, symbol_is_pair)
from freqtrade.misc import plural, render_template
from freqtrade.resolvers import ExchangeResolver
from freqtrade.resolvers import ExchangeResolver, StrategyResolver
from freqtrade.state import RunMode
logger = logging.getLogger(__name__)
@ -229,7 +229,17 @@ def start_list_strategies(args: Dict[str, Any]) -> None:
Print Strategies available in a folder
"""
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: