Merge pull request #5046 from freqtrade/list_strategy_hyperopt

allow list-strategies to show if params are hyperoptable
This commit is contained in:
Matthias 2021-05-30 16:36:31 +01:00 committed by GitHub
commit e17e35f0ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 39 additions and 9 deletions

View File

@ -54,15 +54,21 @@ def _print_objs_tabular(objs: List, print_colorized: bool) -> None:
reset = '' reset = ''
names = [s['name'] for s in objs] names = [s['name'] for s in objs]
objss_to_print = [{ objs_to_print = [{
'name': s['name'] if s['name'] else "--", 'name': s['name'] if s['name'] else "--",
'location': s['location'].name, 'location': s['location'].name,
'status': (red + "LOAD FAILED" + reset if s['class'] is None 'status': (red + "LOAD FAILED" + reset if s['class'] is None
else "OK" if names.count(s['name']) == 1 else "OK" if names.count(s['name']) == 1
else yellow + "DUPLICATE NAME" + reset) else yellow + "DUPLICATE NAME" + reset)
} for s in objs] } for s in objs]
for idx, s in enumerate(objs):
print(tabulate(objss_to_print, headers='keys', tablefmt='psql', stralign='right')) if 'hyperoptable' in s:
objs_to_print[idx].update({
'hyperoptable': "Yes" if s['hyperoptable']['count'] > 0 else "No",
'buy-Params': len(s['hyperoptable'].get('buy', [])),
'sell-Params': len(s['hyperoptable'].get('sell', [])),
})
print(tabulate(objs_to_print, headers='keys', tablefmt='psql', stralign='right'))
def start_list_strategies(args: Dict[str, Any]) -> None: def start_list_strategies(args: Dict[str, Any]) -> None:
@ -75,6 +81,11 @@ def start_list_strategies(args: Dict[str, Any]) -> None:
strategy_objs = StrategyResolver.search_all_objects(directory, not args['print_one_column']) strategy_objs = StrategyResolver.search_all_objects(directory, not args['print_one_column'])
# Sort alphabetically # Sort alphabetically
strategy_objs = sorted(strategy_objs, key=lambda x: x['name']) strategy_objs = sorted(strategy_objs, key=lambda x: x['name'])
for obj in strategy_objs:
if obj['class']:
obj['hyperoptable'] = obj['class'].detect_all_parameters()
else:
obj['hyperoptable'] = {'count': 0}
if args['print_one_column']: if args['print_one_column']:
print('\n'.join([s['name'] for s in strategy_objs])) print('\n'.join([s['name'] for s in strategy_objs]))

View File

@ -273,11 +273,12 @@ class HyperStrategyMixin(object):
for par in params: for par in params:
yield par.name, par yield par.name, par
def _detect_parameters(self, category: str) -> Iterator[Tuple[str, BaseParameter]]: @classmethod
def detect_parameters(cls, category: str) -> Iterator[Tuple[str, BaseParameter]]:
""" Detect all parameters for 'category' """ """ Detect all parameters for 'category' """
for attr_name in dir(self): for attr_name in dir(cls):
if not attr_name.startswith('__'): # Ignore internals, not strictly necessary. if not attr_name.startswith('__'): # Ignore internals, not strictly necessary.
attr = getattr(self, attr_name) attr = getattr(cls, attr_name)
if issubclass(attr.__class__, BaseParameter): if issubclass(attr.__class__, BaseParameter):
if (attr_name.startswith(category + '_') if (attr_name.startswith(category + '_')
and attr.category is not None and attr.category != category): and attr.category is not None and attr.category != category):
@ -287,6 +288,19 @@ class HyperStrategyMixin(object):
(attr_name.startswith(category + '_') and attr.category is None)): (attr_name.startswith(category + '_') and attr.category is None)):
yield attr_name, attr yield attr_name, attr
@classmethod
def detect_all_parameters(cls) -> Dict:
""" Detect all parameters and return them as a list"""
params: Dict = {
'buy': list(cls.detect_parameters('buy')),
'sell': list(cls.detect_parameters('sell')),
}
params.update({
'count': len(params['buy'] + params['sell'])
})
return params
def _load_hyper_params(self, hyperopt: bool = False) -> None: def _load_hyper_params(self, hyperopt: bool = False) -> None:
""" """
Load Hyperoptable parameters Load Hyperoptable parameters
@ -303,7 +317,7 @@ class HyperStrategyMixin(object):
logger.info(f"No params for {space} found, using default values.") logger.info(f"No params for {space} found, using default values.")
param_container: List[BaseParameter] = getattr(self, f"ft_{space}_params") param_container: List[BaseParameter] = getattr(self, f"ft_{space}_params")
for attr_name, attr in self._detect_parameters(space): for attr_name, attr in self.detect_parameters(space):
attr.name = attr_name attr.name = attr_name
attr.in_space = hyperopt and HyperoptTools.has_space(self.config, space) attr.in_space = hyperopt and HyperoptTools.has_space(self.config, space)
if not attr.category: if not attr.category:

View File

@ -667,8 +667,13 @@ def test_auto_hyperopt_interface(default_conf):
# Parameter is disabled - so value from sell_param dict will NOT be used. # Parameter is disabled - so value from sell_param dict will NOT be used.
assert strategy.sell_minusdi.value == 0.5 assert strategy.sell_minusdi.value == 0.5
all_params = strategy.detect_all_parameters()
assert isinstance(all_params, dict)
assert len(all_params['buy']) == 2
assert len(all_params['sell']) == 2
assert all_params['count'] == 4
strategy.sell_rsi = IntParameter([0, 10], default=5, space='buy') strategy.__class__.sell_rsi = IntParameter([0, 10], default=5, space='buy')
with pytest.raises(OperationalException, match=r"Inconclusive parameter.*"): with pytest.raises(OperationalException, match=r"Inconclusive parameter.*"):
[x for x in strategy._detect_parameters('sell')] [x for x in strategy.detect_parameters('sell')]