From 35d6140068c2bbc3bf9ebe6e3b6bdf2bad1ddabf Mon Sep 17 00:00:00 2001 From: Bruno Gouvea Date: Mon, 7 Jun 2021 17:53:19 -0300 Subject: [PATCH 1/7] Displays the max drawdown in the hyper optimization results table. --- freqtrade/optimize/hyperopt_tools.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/freqtrade/optimize/hyperopt_tools.py b/freqtrade/optimize/hyperopt_tools.py index ebe405d07..29014277e 100644 --- a/freqtrade/optimize/hyperopt_tools.py +++ b/freqtrade/optimize/hyperopt_tools.py @@ -233,18 +233,20 @@ class HyperoptTools(): 'results_metrics.winsdrawslosses', 'results_metrics.profit_mean', 'results_metrics.profit_total_abs', 'results_metrics.profit_total', 'results_metrics.holding_avg', - 'loss', 'is_initial_point', 'is_best']] + 'loss', 'is_initial_point', 'is_best', 'results_metrics.max_drawdown', + 'results_metrics.max_drawdown_abs']] else: # Legacy mode trials = trials[['Best', 'current_epoch', 'results_metrics.trade_count', 'results_metrics.winsdrawslosses', 'results_metrics.avg_profit', 'results_metrics.total_profit', 'results_metrics.profit', 'results_metrics.duration', - 'loss', 'is_initial_point', 'is_best']] + 'loss', 'is_initial_point', 'is_best', 'results_metrics.max_drawdown', + 'results_metrics.max_drawdown_abs']] trials.columns = ['Best', 'Epoch', 'Trades', ' Win Draw Loss', 'Avg profit', - 'Total profit', 'Profit', 'Avg duration', 'Objective', - 'is_initial_point', 'is_best'] + 'Total profit', 'Profit', 'Avg duration', 'Max Drawdown', 'max_drawdown_abs', + 'Objective', 'is_initial_point', 'is_best'] trials['is_profit'] = False trials.loc[trials['is_initial_point'], 'Best'] = '* ' trials.loc[trials['is_best'], 'Best'] = 'Best' @@ -266,6 +268,16 @@ class HyperoptTools(): lambda x: f'{x:,.5f}'.rjust(8, ' ') if x != 100000 else "N/A".rjust(8, ' ') ) + trials['Max Drawdown'] = trials.apply( + lambda x: '{} {}'.format( + round_coin_value(x['max_drawdown_abs'], stake_currency), + '({:,.2f}%)'.format(x['Max Drawdown'] * perc_multi).rjust(10, ' ') + ).rjust(25 + len(stake_currency)) + if x['Max Drawdown'] != 0.0 else '--'.rjust(25 + len(stake_currency)), + axis=1 + ) + trials = trials.drop(columns=['max_drawdown_abs']) + stake_currency = config['stake_currency'] trials['Profit'] = trials.apply( lambda x: '{} {}'.format( From 5c3a418e6564d92c83cf123f150a6a87bb2cd81f Mon Sep 17 00:00:00 2001 From: Bruno Gouvea Date: Mon, 7 Jun 2021 18:15:26 -0300 Subject: [PATCH 2/7] Adjusting drawdown column position. --- freqtrade/optimize/hyperopt_tools.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/freqtrade/optimize/hyperopt_tools.py b/freqtrade/optimize/hyperopt_tools.py index 29014277e..9d6248643 100644 --- a/freqtrade/optimize/hyperopt_tools.py +++ b/freqtrade/optimize/hyperopt_tools.py @@ -233,16 +233,15 @@ class HyperoptTools(): 'results_metrics.winsdrawslosses', 'results_metrics.profit_mean', 'results_metrics.profit_total_abs', 'results_metrics.profit_total', 'results_metrics.holding_avg', - 'loss', 'is_initial_point', 'is_best', 'results_metrics.max_drawdown', - 'results_metrics.max_drawdown_abs']] + 'results_metrics.max_drawdown', 'results_metrics.max_drawdown_abs', + 'loss', 'is_initial_point', 'is_best']] else: # Legacy mode trials = trials[['Best', 'current_epoch', 'results_metrics.trade_count', 'results_metrics.winsdrawslosses', 'results_metrics.avg_profit', 'results_metrics.total_profit', - 'results_metrics.profit', 'results_metrics.duration', - 'loss', 'is_initial_point', 'is_best', 'results_metrics.max_drawdown', - 'results_metrics.max_drawdown_abs']] + 'results_metrics.profit', 'results_metrics.duration', 'results_metrics.max_drawdown', + 'results_metrics.max_drawdown_abs', 'loss', 'is_initial_point', 'is_best']] trials.columns = ['Best', 'Epoch', 'Trades', ' Win Draw Loss', 'Avg profit', 'Total profit', 'Profit', 'Avg duration', 'Max Drawdown', 'max_drawdown_abs', @@ -268,6 +267,8 @@ class HyperoptTools(): lambda x: f'{x:,.5f}'.rjust(8, ' ') if x != 100000 else "N/A".rjust(8, ' ') ) + stake_currency = config['stake_currency'] + trials['Max Drawdown'] = trials.apply( lambda x: '{} {}'.format( round_coin_value(x['max_drawdown_abs'], stake_currency), @@ -278,7 +279,7 @@ class HyperoptTools(): ) trials = trials.drop(columns=['max_drawdown_abs']) - stake_currency = config['stake_currency'] + trials['Profit'] = trials.apply( lambda x: '{} {}'.format( round_coin_value(x['Total profit'], stake_currency), From c513c9685d4ff57f3a586430355fe221dc96c7af Mon Sep 17 00:00:00 2001 From: Bruno Gouvea Date: Mon, 7 Jun 2021 18:20:04 -0300 Subject: [PATCH 3/7] Remove blank line (PEP8) --- freqtrade/optimize/hyperopt_tools.py | 1 - 1 file changed, 1 deletion(-) diff --git a/freqtrade/optimize/hyperopt_tools.py b/freqtrade/optimize/hyperopt_tools.py index 9d6248643..59332ef69 100644 --- a/freqtrade/optimize/hyperopt_tools.py +++ b/freqtrade/optimize/hyperopt_tools.py @@ -279,7 +279,6 @@ class HyperoptTools(): ) trials = trials.drop(columns=['max_drawdown_abs']) - trials['Profit'] = trials.apply( lambda x: '{} {}'.format( round_coin_value(x['Total profit'], stake_currency), From 4595db39aa95b2da1d9d3c8d297072a6dfdf2fa2 Mon Sep 17 00:00:00 2001 From: Bruno Gouvea Date: Tue, 8 Jun 2021 02:18:00 -0300 Subject: [PATCH 4/7] Displaying max. drawdown only when it is not legacy mode. --- freqtrade/optimize/hyperopt_tools.py | 39 ++++++++++++++++------------ 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/freqtrade/optimize/hyperopt_tools.py b/freqtrade/optimize/hyperopt_tools.py index 59332ef69..4243c182d 100644 --- a/freqtrade/optimize/hyperopt_tools.py +++ b/freqtrade/optimize/hyperopt_tools.py @@ -221,6 +221,7 @@ class HyperoptTools(): if 'results_metrics.winsdrawslosses' not in trials.columns: # Ensure compatibility with older versions of hyperopt results trials['results_metrics.winsdrawslosses'] = 'N/A' + legacy_mode = True if 'results_metrics.total_trades' in trials: @@ -235,17 +236,22 @@ class HyperoptTools(): 'results_metrics.profit_total', 'results_metrics.holding_avg', 'results_metrics.max_drawdown', 'results_metrics.max_drawdown_abs', 'loss', 'is_initial_point', 'is_best']] + + trials.columns = ['Best', 'Epoch', 'Trades', ' Win Draw Loss', 'Avg profit', + 'Total profit', 'Profit', 'Avg duration', 'Max Drawdown', + 'max_drawdown_abs', 'Objective', 'is_initial_point', 'is_best'] else: # Legacy mode trials = trials[['Best', 'current_epoch', 'results_metrics.trade_count', - 'results_metrics.winsdrawslosses', - 'results_metrics.avg_profit', 'results_metrics.total_profit', - 'results_metrics.profit', 'results_metrics.duration', 'results_metrics.max_drawdown', - 'results_metrics.max_drawdown_abs', 'loss', 'is_initial_point', 'is_best']] + 'results_metrics.winsdrawslosses', 'results_metrics.avg_profit', + 'results_metrics.total_profit', 'results_metrics.profit', + 'results_metrics.duration', 'loss', 'is_initial_point', + 'is_best']] + + trials.columns = ['Best', 'Epoch', 'Trades', ' Win Draw Loss', 'Avg profit', + 'Total profit', 'Profit', 'Avg duration', 'Objective', + 'is_initial_point', 'is_best'] - trials.columns = ['Best', 'Epoch', 'Trades', ' Win Draw Loss', 'Avg profit', - 'Total profit', 'Profit', 'Avg duration', 'Max Drawdown', 'max_drawdown_abs', - 'Objective', 'is_initial_point', 'is_best'] trials['is_profit'] = False trials.loc[trials['is_initial_point'], 'Best'] = '* ' trials.loc[trials['is_best'], 'Best'] = 'Best' @@ -269,15 +275,16 @@ class HyperoptTools(): stake_currency = config['stake_currency'] - trials['Max Drawdown'] = trials.apply( - lambda x: '{} {}'.format( - round_coin_value(x['max_drawdown_abs'], stake_currency), - '({:,.2f}%)'.format(x['Max Drawdown'] * perc_multi).rjust(10, ' ') - ).rjust(25 + len(stake_currency)) - if x['Max Drawdown'] != 0.0 else '--'.rjust(25 + len(stake_currency)), - axis=1 - ) - trials = trials.drop(columns=['max_drawdown_abs']) + if not legacy_mode: + trials['Max Drawdown'] = trials.apply( + lambda x: '{} {}'.format( + round_coin_value(x['max_drawdown_abs'], stake_currency), + '({:,.2f}%)'.format(x['Max Drawdown'] * perc_multi).rjust(10, ' ') + ).rjust(25 + len(stake_currency)) + if x['Max Drawdown'] != 0.0 else '--'.rjust(25 + len(stake_currency)), + axis=1 + ) + trials = trials.drop(columns=['max_drawdown_abs']) trials['Profit'] = trials.apply( lambda x: '{} {}'.format( From 816bb531b32e28dee9362395167bdbb05677a583 Mon Sep 17 00:00:00 2001 From: Bruno Gouvea Date: Tue, 8 Jun 2021 02:42:55 -0300 Subject: [PATCH 5/7] Creating fake column for legacy mode on max drawdown --- freqtrade/optimize/hyperopt_tools.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/freqtrade/optimize/hyperopt_tools.py b/freqtrade/optimize/hyperopt_tools.py index 4243c182d..a739ab9b9 100644 --- a/freqtrade/optimize/hyperopt_tools.py +++ b/freqtrade/optimize/hyperopt_tools.py @@ -222,6 +222,11 @@ class HyperoptTools(): # Ensure compatibility with older versions of hyperopt results trials['results_metrics.winsdrawslosses'] = 'N/A' + if 'results_metrics.max_drawdown_abs' not in trials.columns: + # Ensure compatibility with older versions of hyperopt results + trials['results_metrics.max_drawdown_abs'] = None + trials['results_metrics.max_drawdown'] = None + legacy_mode = True if 'results_metrics.total_trades' in trials: @@ -237,20 +242,18 @@ class HyperoptTools(): 'results_metrics.max_drawdown', 'results_metrics.max_drawdown_abs', 'loss', 'is_initial_point', 'is_best']] - trials.columns = ['Best', 'Epoch', 'Trades', ' Win Draw Loss', 'Avg profit', - 'Total profit', 'Profit', 'Avg duration', 'Max Drawdown', - 'max_drawdown_abs', 'Objective', 'is_initial_point', 'is_best'] else: # Legacy mode trials = trials[['Best', 'current_epoch', 'results_metrics.trade_count', 'results_metrics.winsdrawslosses', 'results_metrics.avg_profit', 'results_metrics.total_profit', 'results_metrics.profit', - 'results_metrics.duration', 'loss', 'is_initial_point', + 'results_metrics.duration', 'results_metrics.max_drawdown', + 'results_metrics.max_drawdown_abs', 'loss', 'is_initial_point', 'is_best']] - trials.columns = ['Best', 'Epoch', 'Trades', ' Win Draw Loss', 'Avg profit', - 'Total profit', 'Profit', 'Avg duration', 'Objective', - 'is_initial_point', 'is_best'] + trials.columns = ['Best', 'Epoch', 'Trades', ' Win Draw Loss', 'Avg profit', + 'Total profit', 'Profit', 'Avg duration', 'Max Drawdown', + 'max_drawdown_abs', 'Objective', 'is_initial_point', 'is_best'] trials['is_profit'] = False trials.loc[trials['is_initial_point'], 'Best'] = '* ' @@ -284,7 +287,10 @@ class HyperoptTools(): if x['Max Drawdown'] != 0.0 else '--'.rjust(25 + len(stake_currency)), axis=1 ) - trials = trials.drop(columns=['max_drawdown_abs']) + else: + trials = trials.drop(columns=['Max Drawdown']) + + trials = trials.drop(columns=['max_drawdown_abs']) trials['Profit'] = trials.apply( lambda x: '{} {}'.format( From 3cce668353322e3d134b94442d218141e22286b5 Mon Sep 17 00:00:00 2001 From: Bruno Gouvea Date: Tue, 8 Jun 2021 02:57:44 -0300 Subject: [PATCH 6/7] Creating a control variable to determine the existence of max drawdown in the final result. --- freqtrade/optimize/hyperopt_tools.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/freqtrade/optimize/hyperopt_tools.py b/freqtrade/optimize/hyperopt_tools.py index a739ab9b9..eaea4aa4a 100644 --- a/freqtrade/optimize/hyperopt_tools.py +++ b/freqtrade/optimize/hyperopt_tools.py @@ -222,10 +222,12 @@ class HyperoptTools(): # Ensure compatibility with older versions of hyperopt results trials['results_metrics.winsdrawslosses'] = 'N/A' + has_drawdown = True if 'results_metrics.max_drawdown_abs' not in trials.columns: # Ensure compatibility with older versions of hyperopt results trials['results_metrics.max_drawdown_abs'] = None trials['results_metrics.max_drawdown'] = None + has_drawdown = False legacy_mode = True @@ -278,7 +280,7 @@ class HyperoptTools(): stake_currency = config['stake_currency'] - if not legacy_mode: + if has_drawdown: trials['Max Drawdown'] = trials.apply( lambda x: '{} {}'.format( round_coin_value(x['max_drawdown_abs'], stake_currency), From 40f1ede77549ee7a57645030812507a326378fb8 Mon Sep 17 00:00:00 2001 From: Bruno Gouvea Date: Wed, 9 Jun 2021 12:03:24 -0300 Subject: [PATCH 7/7] Simplifying HO's result function --- freqtrade/optimize/hyperopt_tools.py | 40 ++++++++++++++++------------ 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/freqtrade/optimize/hyperopt_tools.py b/freqtrade/optimize/hyperopt_tools.py index eaea4aa4a..6024422bc 100644 --- a/freqtrade/optimize/hyperopt_tools.py +++ b/freqtrade/optimize/hyperopt_tools.py @@ -206,33 +206,20 @@ class HyperoptTools(): f"Objective: {results['loss']:.5f}") @staticmethod - def get_result_table(config: dict, results: list, total_epochs: int, highlight_best: bool, - print_colorized: bool, remove_header: int) -> str: - """ - Log result table - """ - if not results: - return '' + def prepare_trials_columns(trials, legacy_mode: bool, has_drawdown: bool) -> str: - tabulate.PRESERVE_WHITESPACE = True - - trials = json_normalize(results, max_level=1) trials['Best'] = '' + if 'results_metrics.winsdrawslosses' not in trials.columns: # Ensure compatibility with older versions of hyperopt results trials['results_metrics.winsdrawslosses'] = 'N/A' - has_drawdown = True - if 'results_metrics.max_drawdown_abs' not in trials.columns: + if not has_drawdown: # Ensure compatibility with older versions of hyperopt results trials['results_metrics.max_drawdown_abs'] = None trials['results_metrics.max_drawdown'] = None - has_drawdown = False - legacy_mode = True - - if 'results_metrics.total_trades' in trials: - legacy_mode = False + if not legacy_mode: # New mode, using backtest result for metrics trials['results_metrics.winsdrawslosses'] = trials.apply( lambda x: f"{x['results_metrics.wins']} {x['results_metrics.draws']:>4} " @@ -257,6 +244,25 @@ class HyperoptTools(): 'Total profit', 'Profit', 'Avg duration', 'Max Drawdown', 'max_drawdown_abs', 'Objective', 'is_initial_point', 'is_best'] + return trials + + @staticmethod + def get_result_table(config: dict, results: list, total_epochs: int, highlight_best: bool, + print_colorized: bool, remove_header: int) -> str: + """ + Log result table + """ + if not results: + return '' + + tabulate.PRESERVE_WHITESPACE = True + trials = json_normalize(results, max_level=1) + + legacy_mode = 'results_metrics.total_trades' not in trials + has_drawdown = 'results_metrics.max_drawdown_abs' in trials.columns + + trials = HyperoptTools.prepare_trials_columns(trials, legacy_mode, has_drawdown) + trials['is_profit'] = False trials.loc[trials['is_initial_point'], 'Best'] = '* ' trials.loc[trials['is_best'], 'Best'] = 'Best'