diff --git a/docs/bot-usage.md b/docs/bot-usage.md index 3a2ff60a5..0c6dcd7f4 100644 --- a/docs/bot-usage.md +++ b/docs/bot-usage.md @@ -207,7 +207,7 @@ usage: freqtrade hyperopt [-h] [-i TICKER_INTERVAL] [--timerange TIMERANGE] [--customhyperopt NAME] [--hyperopt-path PATH] [--eps] [-e INT] [-s {all,buy,sell,roi,stoploss} [{all,buy,sell,roi,stoploss} ...]] - [--dmmp] [--print-all] [-j JOBS] + [--dmmp] [--print-all] [--no-color] [-j JOBS] [--random-state INT] [--min-trades INT] [--continue] [--hyperopt-loss NAME] @@ -243,6 +243,8 @@ optional arguments: (same as setting `max_open_trades` to a very high number). --print-all Print all results, not only the best ones. + --no-color Disable colorization of hyperopt results. May be + useful if you are redirecting output to a file. -j JOBS, --job-workers JOBS The number of concurrently running jobs for hyperoptimization (hyperopt worker processes). If -1 diff --git a/docs/hyperopt.md b/docs/hyperopt.md index 918361c52..c1bf56a3d 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -352,6 +352,10 @@ def populate_buy_trend(self, dataframe: DataFrame) -> DataFrame: return dataframe ``` +By default, hyperopt prints colorized results -- epochs with positive profit are printed in the green color. This highlighting helps you find epochs that can be interesting for later analysis. Epochs with zero total profit or with negative profits (losses) are printed in the normal color. If you do not need colorization of results (for instance, when you are redirecting hyperopt output to a file) you can switch colorization off by specifying the `--no-color` option in the command line. + +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 `--print-all` is used, current best results are also colorized by default -- they are printed in bold (bright) style. This can also be switched off with the `--no-color` command line option. + ### Understand Hyperopt ROI results If you are optimizing ROI (i.e. if optimization search-space contains 'all' or 'roi'), your 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 771cdfb80..b098fa8bc 100644 --- a/freqtrade/configuration/cli_options.py +++ b/freqtrade/configuration/cli_options.py @@ -191,6 +191,13 @@ AVAILABLE_CLI_OPTIONS = { action='store_true', default=False, ), + "print_colorized": Arg( + '--no-color', + help='Disable colorization of hyperopt results. May be useful if you are ' + 'redirecting output to a file.', + action='store_false', + default=True, + ), "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 4bbf4ddd6..587c8757e 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -236,6 +236,12 @@ class Configuration(object): self._args_to_config(config, argname='print_all', logstring='Parameter --print-all detected ...') + if 'print_colorized' in self.args and not self.args.print_colorized: + logger.info('Parameter --no-color detected ...') + config.update({'print_colorized': False}) + else: + config.update({'print_colorized': True}) + 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 427b17cb8..550f13e28 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -13,6 +13,8 @@ from pathlib import Path from pprint import pprint from typing import Any, Dict, List, Optional +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 from pandas import DataFrame from skopt import Optimizer @@ -153,8 +155,17 @@ 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 = Fore.GREEN + log_str + if print_all and is_best_loss: + log_str = Style.BRIGHT + log_str if print_all: print(log_str) else: @@ -169,7 +180,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 +247,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 +258,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 +268,7 @@ class Hyperopt(Backtesting): 'loss': loss, 'params': params, 'results_explanation': results_explanation, + 'total_profit': total_profit, } def format_results(self, results: DataFrame) -> str: @@ -339,6 +352,10 @@ class Hyperopt(Backtesting): logger.info(f'Number of parallel jobs set as: {config_jobs}') opt = self.get_optimizer(config_jobs) + + if self.config.get('print_colorized', False): + colorama_init(autoreset=True) + try: with Parallel(n_jobs=config_jobs) as parallel: jobs = parallel._effective_n_jobs() diff --git a/freqtrade/tests/optimize/test_hyperopt.py b/freqtrade/tests/optimize/test_hyperopt.py index cff1315a0..0317bb37d 100644 --- a/freqtrade/tests/optimize/test_hyperopt.py +++ b/freqtrade/tests/optimize/test_hyperopt.py @@ -578,7 +578,8 @@ def test_generate_optimizer(mocker, default_conf) -> None: 'loss': 1.9840569076926293, 'results_explanation': ' 1 trades. Avg profit 2.31%. Total profit 0.00023300 BTC ' '( 2.31Σ%). Avg duration 100.0 mins.', - 'params': optimizer_param + 'params': optimizer_param, + 'total_profit': 0.00023300 } hyperopt = Hyperopt(default_conf) diff --git a/requirements-common.txt b/requirements-common.txt index 19beec64b..651be7611 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -30,3 +30,6 @@ sdnotify==0.3.2 # Api server flask==1.1.1 + +# Support for colorized terminal output +colorama==0.4.1 diff --git a/setup.py b/setup.py index 41e1b8f45..631c8b654 100644 --- a/setup.py +++ b/setup.py @@ -64,6 +64,7 @@ setup(name='freqtrade', 'py_find_1st', 'python-rapidjson', 'sdnotify', + 'colorama', # from requirements.txt 'numpy', 'pandas',