def setup_optimize_configuration(args: Dict[str, Any], method: RunMode) -> Dict[str, Any]: """ Prepare the configuration for the Hyperopt module :param args: Cli args from Arguments() :param method: Bot running mode :return: Configuration """ config = setup_utils_configuration(args, method) no_unlimited_runmodes = { RunMode.BACKTEST: 'backtesting', RunMode.HYPEROPT: 'hyperoptimization', } if method in no_unlimited_runmodes.keys(): if (config['stake_amount'] != constants.UNLIMITED_STAKE_AMOUNT and config['stake_amount'] > config['dry_run_wallet']): wallet = round_coin_value(config['dry_run_wallet'], config['stake_currency']) stake = round_coin_value(config['stake_amount'], config['stake_currency']) raise OperationalException( f"Starting balance ({wallet}) " f"is smaller than stake_amount {stake}.") return config
def text_table_add_metrics(strat_results: Dict) -> str: if len(strat_results['trades']) > 0: best_trade = max(strat_results['trades'], key=lambda x: x['profit_ratio']) worst_trade = min(strat_results['trades'], key=lambda x: x['profit_ratio']) metrics = [ ('Backtesting from', strat_results['backtest_start'].strftime(DATETIME_PRINT_FORMAT)), ('Backtesting to', strat_results['backtest_end'].strftime(DATETIME_PRINT_FORMAT)), ('Max open trades', strat_results['max_open_trades']), ('', ''), # Empty line to improve readability ('Total trades', strat_results['total_trades']), ('Total Profit %', f"{round(strat_results['profit_total'] * 100, 2)}%"), ('Trades per day', strat_results['trades_per_day']), ('', ''), # Empty line to improve readability ('Best Pair', f"{strat_results['best_pair']['key']} " f"{round(strat_results['best_pair']['profit_sum_pct'], 2)}%"), ('Worst Pair', f"{strat_results['worst_pair']['key']} " f"{round(strat_results['worst_pair']['profit_sum_pct'], 2)}%"), ('Best trade', f"{best_trade['pair']} {round(best_trade['profit_ratio'] * 100, 2)}%" ), ('Worst trade', f"{worst_trade['pair']} " f"{round(worst_trade['profit_ratio'] * 100, 2)}%"), ('Best day', f"{round(strat_results['backtest_best_day'] * 100, 2)}%"), ('Worst day', f"{round(strat_results['backtest_worst_day'] * 100, 2)}%"), ('Days win/draw/lose', f"{strat_results['winning_days']} / " f"{strat_results['draw_days']} / {strat_results['losing_days']}"), ('Avg. Duration Winners', f"{strat_results['winner_holding_avg']}"), ('Avg. Duration Loser', f"{strat_results['loser_holding_avg']}"), ('', ''), # Empty line to improve readability ('Abs Profit Min', round_coin_value(strat_results['csum_min'], strat_results['stake_currency'])), ('Abs Profit Max', round_coin_value(strat_results['csum_max'], strat_results['stake_currency'])), ('Max Drawdown', f"{round(strat_results['max_drawdown'] * 100, 2)}%"), ('Drawdown Start', strat_results['drawdown_start'].strftime(DATETIME_PRINT_FORMAT)), ('Drawdown End', strat_results['drawdown_end'].strftime(DATETIME_PRINT_FORMAT)), ('Market change', f"{round(strat_results['market_change'] * 100, 2)}%"), ] return tabulate(metrics, headers=["Metric", "Value"], tablefmt="orgtbl") else: return ''
def test_round_coin_value(): assert round_coin_value(222.222222, 'USDT') == '222.222 USDT' assert round_coin_value(222.2, 'USDT') == '222.200 USDT' assert round_coin_value(222.12745, 'EUR') == '222.127 EUR' assert round_coin_value(0.1274512123, 'BTC') == '0.12745121 BTC' assert round_coin_value(0.1274512123, 'ETH') == '0.12745 ETH' assert round_coin_value(222.222222, 'USDT', False) == '222.222' assert round_coin_value(222.2, 'USDT', False) == '222.200' assert round_coin_value(222.12745, 'EUR', False) == '222.127' assert round_coin_value(0.1274512123, 'BTC', False) == '0.12745121' assert round_coin_value(0.1274512123, 'ETH', False) == '0.12745'
def text_table_periodic_breakdown(days_breakdown_stats: List[Dict[str, Any]], stake_currency: str, period: str) -> str: """ Generate small table with Backtest results by days :param days_breakdown_stats: Days breakdown metrics :param stake_currency: Stakecurrency used :return: pretty printed table with tabulate as string """ headers = [ period.capitalize(), f'Tot Profit {stake_currency}', 'Wins', 'Draws', 'Losses', ] output = [[ d['date'], round_coin_value(d['profit_abs'], stake_currency, False), d['wins'], d['draws'], d['loses'], ] for d in days_breakdown_stats] return tabulate(output, headers=headers, tablefmt="orgtbl", stralign="right")
def text_table_exit_reason(exit_reason_stats: List[Dict[str, Any]], stake_currency: str) -> str: """ Generate small table outlining Backtest results :param sell_reason_stats: Exit reason metrics :param stake_currency: Stakecurrency used :return: pretty printed table with tabulate as string """ headers = [ 'Exit Reason', 'Exits', 'Win Draws Loss Win%', 'Avg Profit %', 'Cum Profit %', f'Tot Profit {stake_currency}', 'Tot Profit %', ] output = [[ t.get('exit_reason', t.get('sell_reason')), t['trades'], _generate_wins_draws_losses(t['wins'], t['draws'], t['losses']), t['profit_mean_pct'], t['profit_sum_pct'], round_coin_value(t['profit_total_abs'], stake_currency, False), t['profit_total_pct'], ] for t in exit_reason_stats] return tabulate(output, headers=headers, tablefmt="orgtbl", stralign="right")
def generate_strategy_comparison(all_results: Dict) -> List[Dict]: """ Generate summary per strategy :param all_results: Dict of <Strategyname: DataFrame> containing results for all strategies :return: List of Dicts containing the metrics per Strategy """ tabular_data = [] for strategy, results in all_results.items(): tabular_data.append( _generate_result_line(results['results'], results['config']['dry_run_wallet'], strategy)) try: max_drawdown_per, _, _, _, _ = calculate_max_drawdown( results['results'], value_col='profit_ratio') max_drawdown_abs, _, _, _, _ = calculate_max_drawdown( results['results'], value_col='profit_abs') except ValueError: max_drawdown_per = 0 max_drawdown_abs = 0 tabular_data[-1]['max_drawdown_per'] = round(max_drawdown_per * 100, 2) tabular_data[-1]['max_drawdown_abs'] = \ round_coin_value(max_drawdown_abs, results['config']['stake_currency'], False) return tabular_data
def text_table_sell_reason(sell_reason_stats: List[Dict[str, Any]], stake_currency: str) -> str: """ Generate small table outlining Backtest results :param sell_reason_stats: Sell reason metrics :param stake_currency: Stakecurrency used :return: pretty printed table with tabulate as string """ headers = [ 'Sell Reason', 'Sells', 'Wins', 'Draws', 'Losses', 'Avg Profit %', f'Tot Profit {stake_currency}', 'Tot Profit %', ] output = [[ t['sell_reason'], t['trades'], t['wins'], t['draws'], t['losses'], t['profit_mean_pct'], round_coin_value(t['profit_total_abs'], stake_currency, False), t['profit_total_pct'], ] for t in sell_reason_stats] return tabulate(output, headers=headers, tablefmt="orgtbl", stralign="right")
def generate_strategy_comparison(bt_stats: Dict) -> List[Dict]: """ Generate summary per strategy :param bt_stats: Dict of <Strategyname: DataFrame> containing results for all strategies :return: List of Dicts containing the metrics per Strategy """ tabular_data = [] for strategy, result in bt_stats.items(): tabular_data.append(deepcopy(result['results_per_pair'][-1])) # Update "key" to strategy (results_per_pair has it as "Total"). tabular_data[-1]['key'] = strategy tabular_data[-1]['max_drawdown_account'] = result[ 'max_drawdown_account'] tabular_data[-1]['max_drawdown_abs'] = round_coin_value( result['max_drawdown_abs'], result['stake_currency'], False) return tabular_data
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' trials.loc[trials['is_initial_point'] & trials['is_best'], 'Best'] = '* Best' trials.loc[trials['Total profit'] > 0, 'is_profit'] = True trials['Trades'] = trials['Trades'].astype(str) perc_multi = 1 if legacy_mode else 100 trials['Epoch'] = trials['Epoch'].apply(lambda x: '{}/{}'.format( str(x).rjust(len(str(total_epochs)), ' '), total_epochs)) trials['Avg profit'] = trials['Avg profit'].apply( lambda x: f'{x * perc_multi:,.2f}%'.rjust(7, ' ') if not isna(x) else "--".rjust(7, ' ')) trials['Avg duration'] = trials['Avg duration'].apply( lambda x: f'{x:,.1f} m'.rjust(7, ' ') if isinstance( x, float) else f"{x}" if not isna(x) else "--".rjust(7, ' ')) trials['Objective'] = trials['Objective'].apply( lambda x: f'{x:,.5f}'.rjust(8, ' ') if x != 100000 else "N/A".rjust(8, ' ')) stake_currency = config['stake_currency'] if has_drawdown: 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) else: trials = trials.drop(columns=['Max Drawdown']) trials = trials.drop(columns=['max_drawdown_abs']) trials['Profit'] = trials.apply(lambda x: '{} {}'.format( round_coin_value(x['Total profit'], stake_currency), '({:,.2f}%)'. format(x['Profit'] * perc_multi).rjust(10, ' ')).rjust(25 + len( stake_currency)) if x['Total profit'] != 0.0 else '--'.rjust( 25 + len(stake_currency)), axis=1) trials = trials.drop(columns=['Total profit']) if print_colorized: for i in range(len(trials)): if trials.loc[i]['is_profit']: for j in range(len(trials.loc[i]) - 3): trials.iat[i, j] = "{}{}{}".format( Fore.GREEN, str(trials.loc[i][j]), Fore.RESET) if trials.loc[i]['is_best'] and highlight_best: for j in range(len(trials.loc[i]) - 3): trials.iat[i, j] = "{}{}{}".format( Style.BRIGHT, str(trials.loc[i][j]), Style.RESET_ALL) trials = trials.drop( columns=['is_initial_point', 'is_best', 'is_profit']) if remove_header > 0: table = tabulate.tabulate(trials.to_dict(orient='list'), tablefmt='orgtbl', headers='keys', stralign="right") table = table.split("\n", remove_header)[remove_header] elif remove_header < 0: table = tabulate.tabulate(trials.to_dict(orient='list'), tablefmt='psql', headers='keys', stralign="right") table = "\n".join(table.split("\n")[0:remove_header]) else: table = tabulate.tabulate(trials.to_dict(orient='list'), tablefmt='psql', headers='keys', stralign="right") return table
def text_table_add_metrics(strat_results: Dict) -> str: if len(strat_results['trades']) > 0: best_trade = max(strat_results['trades'], key=lambda x: x['profit_ratio']) worst_trade = min(strat_results['trades'], key=lambda x: x['profit_ratio']) short_metrics = [ ('', ''), # Empty line to improve readability ('Long / Short', f"{strat_results.get('trade_count_long', 'total_trades')} / " f"{strat_results.get('trade_count_short', 0)}"), ('Total profit Long %', f"{strat_results['profit_total_long']:.2%}"), ('Total profit Short %', f"{strat_results['profit_total_short']:.2%}"), ('Absolute profit Long', round_coin_value(strat_results['profit_total_long_abs'], strat_results['stake_currency'])), ('Absolute profit Short', round_coin_value(strat_results['profit_total_short_abs'], strat_results['stake_currency'])), ] if strat_results.get('trade_count_short', 0) > 0 else [] # Newly added fields should be ignored if they are missing in strat_results. hyperopt-show # command stores these results and newer version of freqtrade must be able to handle old # results with missing new fields. metrics = [ ('Backtesting from', strat_results['backtest_start']), ('Backtesting to', strat_results['backtest_end']), ('Max open trades', strat_results['max_open_trades']), ('', ''), # Empty line to improve readability ('Total/Daily Avg Trades', f"{strat_results['total_trades']} / {strat_results['trades_per_day']}" ), ('Starting balance', round_coin_value(strat_results['starting_balance'], strat_results['stake_currency'])), ('Final balance', round_coin_value(strat_results['final_balance'], strat_results['stake_currency'])), ('Absolute profit ', round_coin_value(strat_results['profit_total_abs'], strat_results['stake_currency'])), ('Total profit %', f"{strat_results['profit_total']:.2%}"), ('Trades per day', strat_results['trades_per_day']), ('Avg. daily profit %', f"{(strat_results['profit_total'] / strat_results['backtest_days']):.2%}" ), ('Avg. stake amount', round_coin_value(strat_results['avg_stake_amount'], strat_results['stake_currency'])), ('Total trade volume', round_coin_value(strat_results['total_volume'], strat_results['stake_currency'])), *short_metrics, ('', ''), # Empty line to improve readability ('Best Pair', f"{strat_results['best_pair']['key']} " f"{strat_results['best_pair']['profit_sum']:.2%}"), ('Worst Pair', f"{strat_results['worst_pair']['key']} " f"{strat_results['worst_pair']['profit_sum']:.2%}"), ('Best trade', f"{best_trade['pair']} {best_trade['profit_ratio']:.2%}"), ('Worst trade', f"{worst_trade['pair']} " f"{worst_trade['profit_ratio']:.2%}"), ('Best day', round_coin_value(strat_results['backtest_best_day_abs'], strat_results['stake_currency'])), ('Worst day', round_coin_value(strat_results['backtest_worst_day_abs'], strat_results['stake_currency'])), ('Days win/draw/lose', f"{strat_results['winning_days']} / " f"{strat_results['draw_days']} / {strat_results['losing_days']}"), ('Avg. Duration Winners', f"{strat_results['winner_holding_avg']}"), ('Avg. Duration Loser', f"{strat_results['loser_holding_avg']}"), ('Rejected Entry signals', strat_results.get('rejected_signals', 'N/A')), ('Entry/Exit Timeouts', f"{strat_results.get('timedout_entry_orders', 'N/A')} / " f"{strat_results.get('timedout_exit_orders', 'N/A')}"), ('', ''), # Empty line to improve readability ('Min balance', round_coin_value(strat_results['csum_min'], strat_results['stake_currency'])), ('Max balance', round_coin_value(strat_results['csum_max'], strat_results['stake_currency'])), # Compatibility to show old hyperopt results ('Drawdown (Account)', f"{strat_results['max_drawdown_account']:.2%}") if 'max_drawdown_account' in strat_results else ('Drawdown', f"{strat_results['max_drawdown']:.2%}"), ('Drawdown', round_coin_value(strat_results['max_drawdown_abs'], strat_results['stake_currency'])), ('Drawdown high', round_coin_value(strat_results['max_drawdown_high'], strat_results['stake_currency'])), ('Drawdown low', round_coin_value(strat_results['max_drawdown_low'], strat_results['stake_currency'])), ('Drawdown Start', strat_results['drawdown_start']), ('Drawdown End', strat_results['drawdown_end']), ('Market change', f"{strat_results['market_change']:.2%}"), ] return tabulate(metrics, headers=["Metric", "Value"], tablefmt="orgtbl") else: start_balance = round_coin_value(strat_results['starting_balance'], strat_results['stake_currency']) stake_amount = round_coin_value( strat_results['stake_amount'], strat_results['stake_currency']) if strat_results[ 'stake_amount'] != UNLIMITED_STAKE_AMOUNT else 'unlimited' message = ("No trades made. " f"Your starting balance was {start_balance}, " f"and your stake was {stake_amount}.") return message
def text_table_add_metrics(strat_results: Dict) -> str: if len(strat_results['trades']) > 0: best_trade = max(strat_results['trades'], key=lambda x: x['profit_ratio']) worst_trade = min(strat_results['trades'], key=lambda x: x['profit_ratio']) metrics = [ ('Backtesting from', strat_results['backtest_start'].strftime(DATETIME_PRINT_FORMAT)), ('Backtesting to', strat_results['backtest_end'].strftime(DATETIME_PRINT_FORMAT)), ('Max open trades', strat_results['max_open_trades']), ('', ''), # Empty line to improve readability ('Total trades', strat_results['total_trades']), ('Starting balance', round_coin_value(strat_results['starting_balance'], strat_results['stake_currency'])), ('Final balance', round_coin_value(strat_results['final_balance'], strat_results['stake_currency'])), ('Absolute profit ', round_coin_value(strat_results['profit_total_abs'], strat_results['stake_currency'])), ('Total profit %', f"{round(strat_results['profit_total'] * 100, 2)}%"), ('Trades per day', strat_results['trades_per_day']), ('Avg. stake amount', round_coin_value(strat_results['avg_stake_amount'], strat_results['stake_currency'])), ('Total trade volume', round_coin_value(strat_results['total_volume'], strat_results['stake_currency'])), ('', ''), # Empty line to improve readability ('Best Pair', f"{strat_results['best_pair']['key']} " f"{round(strat_results['best_pair']['profit_sum_pct'], 2)}%"), ('Worst Pair', f"{strat_results['worst_pair']['key']} " f"{round(strat_results['worst_pair']['profit_sum_pct'], 2)}%"), ('Best trade', f"{best_trade['pair']} {round(best_trade['profit_ratio'] * 100, 2)}%" ), ('Worst trade', f"{worst_trade['pair']} " f"{round(worst_trade['profit_ratio'] * 100, 2)}%"), ('Best day', round_coin_value(strat_results['backtest_best_day_abs'], strat_results['stake_currency'])), ('Worst day', round_coin_value(strat_results['backtest_worst_day_abs'], strat_results['stake_currency'])), ('Days win/draw/lose', f"{strat_results['winning_days']} / " f"{strat_results['draw_days']} / {strat_results['losing_days']}"), ('Avg. Duration Winners', f"{strat_results['winner_holding_avg']}"), ('Avg. Duration Loser', f"{strat_results['loser_holding_avg']}"), ('', ''), # Empty line to improve readability ('Min balance', round_coin_value(strat_results['csum_min'], strat_results['stake_currency'])), ('Max balance', round_coin_value(strat_results['csum_max'], strat_results['stake_currency'])), ('Drawdown', f"{round(strat_results['max_drawdown'] * 100, 2)}%"), ('Drawdown', round_coin_value(strat_results['max_drawdown_abs'], strat_results['stake_currency'])), ('Drawdown high', round_coin_value(strat_results['max_drawdown_high'], strat_results['stake_currency'])), ('Drawdown low', round_coin_value(strat_results['max_drawdown_low'], strat_results['stake_currency'])), ('Drawdown Start', strat_results['drawdown_start'].strftime(DATETIME_PRINT_FORMAT)), ('Drawdown End', strat_results['drawdown_end'].strftime(DATETIME_PRINT_FORMAT)), ('Market change', f"{round(strat_results['market_change'] * 100, 2)}%"), ] return tabulate(metrics, headers=["Metric", "Value"], tablefmt="orgtbl") else: start_balance = round_coin_value(strat_results['starting_balance'], strat_results['stake_currency']) stake_amount = round_coin_value( strat_results['stake_amount'], strat_results['stake_currency']) if strat_results[ 'stake_amount'] != UNLIMITED_STAKE_AMOUNT else 'unlimited' message = ("No trades made. " f"Your starting balance was {start_balance}, " f"and your stake was {stake_amount}.") return message
def test_round_coin_value(): assert round_coin_value(222.222222, 'USDT') == '222.222 USDT' assert round_coin_value(222.2, 'USDT', keep_trailing_zeros=True) == '222.200 USDT' assert round_coin_value(222.2, 'USDT') == '222.2 USDT' assert round_coin_value(222.12745, 'EUR') == '222.127 EUR' assert round_coin_value(0.1274512123, 'BTC') == '0.12745121 BTC' assert round_coin_value(0.1274512123, 'ETH') == '0.12745 ETH' assert round_coin_value(222.222222, 'USDT', False) == '222.222' assert round_coin_value(222.2, 'USDT', False) == '222.2' assert round_coin_value(222.00, 'USDT', False) == '222' assert round_coin_value(222.12745, 'EUR', False) == '222.127' assert round_coin_value(0.1274512123, 'BTC', False) == '0.12745121' assert round_coin_value(0.1274512123, 'ETH', False) == '0.12745' assert round_coin_value(222.2, 'USDT', False, True) == '222.200'
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) trials['Best'] = '' 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: legacy_mode = False # 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} " f"{x['results_metrics.losses']:>4}", axis=1) trials = trials[[ 'Best', 'current_epoch', 'results_metrics.total_trades', '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' ]] 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' ]] trials.columns = [ 'Best', 'Epoch', 'Trades', ' Win Draw Loss', 'Avg profit', 'Total profit', 'Profit', 'Avg duration', 'Objective', 'is_initial_point', 'is_best' ] trials['is_profit'] = False trials.loc[trials['is_initial_point'], 'Best'] = '* ' trials.loc[trials['is_best'], 'Best'] = 'Best' trials.loc[trials['is_initial_point'] & trials['is_best'], 'Best'] = '* Best' trials.loc[trials['Total profit'] > 0, 'is_profit'] = True trials['Trades'] = trials['Trades'].astype(str) perc_multi = 1 if legacy_mode else 100 trials['Epoch'] = trials['Epoch'].apply(lambda x: '{}/{}'.format( str(x).rjust(len(str(total_epochs)), ' '), total_epochs)) trials['Avg profit'] = trials['Avg profit'].apply( lambda x: f'{x * perc_multi:,.2f}%'.rjust(7, ' ') if not isna(x) else "--".rjust(7, ' ')) trials['Avg duration'] = trials['Avg duration'].apply( lambda x: f'{x:,.1f} m'.rjust(7, ' ') if isinstance( x, float) else f"{x}" if not isna(x) else "--".rjust(7, ' ')) trials['Objective'] = trials['Objective'].apply( lambda x: f'{x:,.5f}'.rjust(8, ' ') if x != 100000 else "N/A".rjust(8, ' ')) stake_currency = config['stake_currency'] trials['Profit'] = trials.apply(lambda x: '{} {}'.format( round_coin_value(x['Total profit'], stake_currency), '({:,.2f}%)'. format(x['Profit'] * perc_multi).rjust(10, ' ')).rjust(25 + len( stake_currency)) if x['Total profit'] != 0.0 else '--'.rjust( 25 + len(stake_currency)), axis=1) trials = trials.drop(columns=['Total profit']) if print_colorized: for i in range(len(trials)): if trials.loc[i]['is_profit']: for j in range(len(trials.loc[i]) - 3): trials.iat[i, j] = "{}{}{}".format( Fore.GREEN, str(trials.loc[i][j]), Fore.RESET) if trials.loc[i]['is_best'] and highlight_best: for j in range(len(trials.loc[i]) - 3): trials.iat[i, j] = "{}{}{}".format( Style.BRIGHT, str(trials.loc[i][j]), Style.RESET_ALL) trials = trials.drop( columns=['is_initial_point', 'is_best', 'is_profit']) if remove_header > 0: table = tabulate.tabulate(trials.to_dict(orient='list'), tablefmt='orgtbl', headers='keys', stralign="right") table = table.split("\n", remove_header)[remove_header] elif remove_header < 0: table = tabulate.tabulate(trials.to_dict(orient='list'), tablefmt='psql', headers='keys', stralign="right") table = "\n".join(table.split("\n")[0:remove_header]) else: table = tabulate.tabulate(trials.to_dict(orient='list'), tablefmt='psql', headers='keys', stralign="right") return table
def text_table_add_metrics(strat_results: Dict) -> str: if len(strat_results['trades']) > 0: best_trade = max(strat_results['trades'], key=lambda x: x['profit_ratio']) worst_trade = min(strat_results['trades'], key=lambda x: x['profit_ratio']) # Newly added fields should be ignored if they are missing in strat_results. hyperopt-show # command stores these results and newer version of freqtrade must be able to handle old # results with missing new fields. zero_duration_trades = '--' if 'zero_duration_trades' in strat_results: zero_duration_trades_per = \ 100.0 / strat_results['total_trades'] * strat_results['zero_duration_trades'] zero_duration_trades = f'{zero_duration_trades_per:.2f}% ' \ f'({strat_results["zero_duration_trades"]})' metrics = [ ('Backtesting from', strat_results['backtest_start']), ('Backtesting to', strat_results['backtest_end']), ('Max open trades', strat_results['max_open_trades']), ('', ''), # Empty line to improve readability ('Total trades', strat_results['total_trades']), ('Starting balance', round_coin_value(strat_results['starting_balance'], strat_results['stake_currency'])), ('Final balance', round_coin_value(strat_results['final_balance'], strat_results['stake_currency'])), ('Absolute profit ', round_coin_value(strat_results['profit_total_abs'], strat_results['stake_currency'])), ('Total profit %', f"{round(strat_results['profit_total'] * 100, 2):}%"), ('Trades per day', strat_results['trades_per_day']), ('Avg. stake amount', round_coin_value(strat_results['avg_stake_amount'], strat_results['stake_currency'])), ('Total trade volume', round_coin_value(strat_results['total_volume'], strat_results['stake_currency'])), ('', ''), # Empty line to improve readability ('Best Pair', f"{strat_results['best_pair']['key']} " f"{round(strat_results['best_pair']['profit_sum_pct'], 2)}%"), ('Worst Pair', f"{strat_results['worst_pair']['key']} " f"{round(strat_results['worst_pair']['profit_sum_pct'], 2)}%"), ('Best trade', f"{best_trade['pair']} {round(best_trade['profit_ratio'] * 100, 2)}%" ), ('Worst trade', f"{worst_trade['pair']} " f"{round(worst_trade['profit_ratio'] * 100, 2)}%"), ('Best day', round_coin_value(strat_results['backtest_best_day_abs'], strat_results['stake_currency'])), ('Worst day', round_coin_value(strat_results['backtest_worst_day_abs'], strat_results['stake_currency'])), ('Days win/draw/lose', f"{strat_results['winning_days']} / " f"{strat_results['draw_days']} / {strat_results['losing_days']}"), ('Avg. Duration Winners', f"{strat_results['winner_holding_avg']}"), ('Avg. Duration Loser', f"{strat_results['loser_holding_avg']}"), ('Zero Duration Trades', zero_duration_trades), ('Rejected Buy signals', strat_results.get('rejected_signals', 'N/A')), ('', ''), # Empty line to improve readability ('Min balance', round_coin_value(strat_results['csum_min'], strat_results['stake_currency'])), ('Max balance', round_coin_value(strat_results['csum_max'], strat_results['stake_currency'])), ('Drawdown', f"{round(strat_results['max_drawdown'] * 100, 2)}%"), ('Drawdown', round_coin_value(strat_results['max_drawdown_abs'], strat_results['stake_currency'])), ('Drawdown high', round_coin_value(strat_results['max_drawdown_high'], strat_results['stake_currency'])), ('Drawdown low', round_coin_value(strat_results['max_drawdown_low'], strat_results['stake_currency'])), ('Drawdown Start', strat_results['drawdown_start']), ('Drawdown End', strat_results['drawdown_end']), ('Market change', f"{round(strat_results['market_change'] * 100, 2)}%"), ] return tabulate(metrics, headers=["Metric", "Value"], tablefmt="orgtbl") else: start_balance = round_coin_value(strat_results['starting_balance'], strat_results['stake_currency']) stake_amount = round_coin_value( strat_results['stake_amount'], strat_results['stake_currency']) if strat_results[ 'stake_amount'] != UNLIMITED_STAKE_AMOUNT else 'unlimited' message = ("No trades made. " f"Your starting balance was {start_balance}, " f"and your stake was {stake_amount}.") return message