diff --git a/docs/hyperopt.md b/docs/hyperopt.md index 0b5d1a50e..2826dfc3b 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -343,6 +343,10 @@ def populate_buy_trend(self, dataframe: DataFrame) -> DataFrame: return dataframe ``` +You can use the `--print-all` command line option if you would like to see all results in the hyperopt output, not only the best ones. + +When the `--color/--print-colorized` command line option is used, the results are colorized -- bad results (with zero trades or limited by the `--min-trades` option) are red, currest bests -- in green, results with positive total profit are printed in bold. + ### Understand Hyperopt ROI results If you are optimizing ROI, you're result will look as follows and include a ROI table. diff --git a/freqtrade/configuration/arguments.py b/freqtrade/configuration/arguments.py index 4f0c3d31b..dd5a4290e 100644 --- a/freqtrade/configuration/arguments.py +++ b/freqtrade/configuration/arguments.py @@ -23,7 +23,8 @@ 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", "hyperopt_jobs", + "use_max_market_positions", "print_all", + "print_colorized", "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 04fde2051..aab3c12b3 100644 --- a/freqtrade/configuration/cli_options.py +++ b/freqtrade/configuration/cli_options.py @@ -191,6 +191,12 @@ AVAILABLE_CLI_OPTIONS = { action='store_true', default=False, ), + "print_colorized": Arg( + '--color', '--print-colorized', + help='Print colorized hyperopt results.', + 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 17ad37d6a..01732ca9e 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -254,6 +254,9 @@ class Configuration(object): self._args_to_config(config, argname='print_all', logstring='Parameter --print-all detected ...') + self._args_to_config(config, argname='print_colorized', + logstring='Parameter --color/--print-colorized detected ...') + self._args_to_config(config, argname='hyperopt_jobs', logstring='Parameter -j/--job-workers detected: {}') diff --git a/freqtrade/misc.py b/freqtrade/misc.py index 05946e008..eadfc7490 100644 --- a/freqtrade/misc.py +++ b/freqtrade/misc.py @@ -113,3 +113,15 @@ def deep_merge_dicts(source, destination): destination[key] = value return destination + + +def green(s): + return '\033[92m' + s + '\033[0m' + + +def red(s): + return '\033[91m' + s + '\033[0m' + + +def bold(s): + return '\033[1m' + s + '\033[0m' diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 427b17cb8..e62cbe66b 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -20,6 +20,7 @@ from skopt.space import Dimension from freqtrade.configuration import Arguments from freqtrade.data.history import load_data, get_timeframe +from freqtrade.misc import green, red, bold from freqtrade.optimize.backtesting import Backtesting # Import IHyperOptLoss to allow users import from this file from freqtrade.optimize.hyperopt_loss_interface import IHyperOptLoss # noqa: F4 @@ -153,8 +154,19 @@ class Hyperopt(Backtesting): Log results if it is better than any previous evaluation """ print_all = self.config.get('print_all', False) - if print_all or results['loss'] < self.current_best_loss: + is_best_loss = results['loss'] < self.current_best_loss + if print_all or is_best_loss: + if is_best_loss: + self.current_best_loss = results['loss'] log_str = self.format_results_logstring(results) + # Colorize output + if self.config.get('print_colorized', False): + if results['total_profit'] > 0: + log_str = bold(log_str) + if results['loss'] >= MAX_LOSS: + log_str = red(log_str) + elif is_best_loss: + log_str = green(log_str) if print_all: print(log_str) else: @@ -169,7 +181,6 @@ class Hyperopt(Backtesting): total = self.total_epochs res = results['results_explanation'] loss = results['loss'] - self.current_best_loss = results['loss'] log_str = f'{current:5d}/{total}: {res} Objective: {loss:.5f}' log_str = f'*{log_str}' if results['is_initial_point'] else f' {log_str}' return log_str @@ -237,6 +248,7 @@ class Hyperopt(Backtesting): results_explanation = self.format_results(results) trade_count = len(results.index) + total_profit = results.profit_abs.sum() # If this evaluation contains too short amount of trades to be # interesting -- consider it as 'bad' (assigned max. loss value) @@ -247,6 +259,7 @@ class Hyperopt(Backtesting): 'loss': MAX_LOSS, 'params': params, 'results_explanation': results_explanation, + 'total_profit': total_profit, } loss = self.calculate_loss(results=results, trade_count=trade_count, @@ -256,6 +269,7 @@ class Hyperopt(Backtesting): 'loss': loss, 'params': params, 'results_explanation': results_explanation, + 'total_profit': total_profit, } def format_results(self, results: DataFrame) -> str: