diff --git a/freqtrade/configuration/arguments.py b/freqtrade/configuration/arguments.py index c129a7e47..926d02f8f 100644 --- a/freqtrade/configuration/arguments.py +++ b/freqtrade/configuration/arguments.py @@ -22,7 +22,7 @@ ARGS_BACKTEST = ARGS_COMMON_OPTIMIZE + ["position_stacking", "use_max_market_pos ARGS_HYPEROPT = ARGS_COMMON_OPTIMIZE + ["hyperopt", "hyperopt_path", "position_stacking", "epochs", "spaces", "use_max_market_positions", "print_all", - "print_colorized", "hyperopt_jobs", + "print_colorized", "print_json", "hyperopt_jobs", "hyperopt_random_state", "hyperopt_min_trades", "hyperopt_continue", "hyperopt_loss"] diff --git a/freqtrade/configuration/cli_options.py b/freqtrade/configuration/cli_options.py index b098fa8bc..84686d1e6 100644 --- a/freqtrade/configuration/cli_options.py +++ b/freqtrade/configuration/cli_options.py @@ -198,6 +198,12 @@ AVAILABLE_CLI_OPTIONS = { action='store_false', default=True, ), + "print_json": Arg( + '--print-json', + help='Print best result detailization in JSON format.', + action='store_true', + default=False, + ), "hyperopt_jobs": Arg( '-j', '--job-workers', help='The number of concurrently running jobs for hyperoptimization ' diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index 587c8757e..eaba0b4da 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -242,6 +242,9 @@ class Configuration(object): else: config.update({'print_colorized': True}) + self._args_to_config(config, argname='print_json', + logstring='Parameter --print-json detected ...') + self._args_to_config(config, argname='hyperopt_jobs', logstring='Parameter -j/--job-workers detected: {}') diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 772b4a10f..7664608ce 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -8,11 +8,14 @@ import logging import os import sys +from collections import OrderedDict from operator import itemgetter from pathlib import Path from pprint import pprint from typing import Any, Dict, List, Optional +import rapidjson + from colorama import init as colorama_init from colorama import Fore, Style from joblib import Parallel, delayed, dump, load, wrap_non_picklable_objects, cpu_count @@ -133,22 +136,44 @@ class Hyperopt(Backtesting): results = sorted(self.trials, key=itemgetter('loss')) best_result = results[0] params = best_result['params'] - log_str = self.format_results_logstring(best_result) print(f"\nBest result:\n\n{log_str}\n") - if self.has_space('buy'): - print('Buy hyperspace params:') - pprint({p.name: params.get(p.name) for p in self.hyperopt_space('buy')}, - indent=4) - if self.has_space('sell'): - print('Sell hyperspace params:') - pprint({p.name: params.get(p.name) for p in self.hyperopt_space('sell')}, - indent=4) - if self.has_space('roi'): - print("ROI table:") - pprint(self.custom_hyperopt.generate_roi_table(params), indent=4) - if self.has_space('stoploss'): - print(f"Stoploss: {params.get('stoploss')}") + + if self.config.get('print_json'): + result_dict = {} + if self.has_space('buy') or self.has_space('sell'): + result_dict['params'] = {} + if self.has_space('buy'): + result_dict['params'].update({p.name: params.get(p.name) + for p in self.hyperopt_space('buy')}) + if self.has_space('sell'): + result_dict['params'].update({p.name: params.get(p.name) + for p in self.hyperopt_space('sell')}) + if self.has_space('roi'): + min_roi = self.custom_hyperopt.generate_roi_table(params) + # Convert keys in min_roi dict to strings because + # rapidjson cannot dump dicts with integer keys... + # OrderedDict is used to keep the numeric order of the items + # in the dict. + min_roi = OrderedDict((str(k),v) for k,v in min_roi.items()) + result_dict['minimal_roi'] = min_roi + if self.has_space('stoploss'): + result_dict['stoploss'] = params.get('stoploss') + print(rapidjson.dumps(result_dict, default=str, number_mode=rapidjson.NM_NATIVE)) + else: + if self.has_space('buy'): + print('Buy hyperspace params:') + pprint({p.name: params.get(p.name) for p in self.hyperopt_space('buy')}, + indent=4) + if self.has_space('sell'): + print('Sell hyperspace params:') + pprint({p.name: params.get(p.name) for p in self.hyperopt_space('sell')}, + indent=4) + if self.has_space('roi'): + print("ROI table:") + pprint(self.custom_hyperopt.generate_roi_table(params), indent=4) + if self.has_space('stoploss'): + print(f"Stoploss: {params.get('stoploss')}") def log_results(self, results) -> None: """