diff --git a/freqtrade/data/metrics.py b/freqtrade/data/metrics.py index eccb8a04d..00168bbfa 100644 --- a/freqtrade/data/metrics.py +++ b/freqtrade/data/metrics.py @@ -287,8 +287,8 @@ def calculate_sharpe(trades: pd.DataFrame, return sharp_ratio -def calculate_calmar(trades: pd.DataFrame, - min_date: datetime, max_date: datetime) -> float: +def calculate_calmar(trades: pd.DataFrame, min_date: datetime, max_date: datetime, + starting_balance: float) -> float: """ Calculate calmar :param trades: DataFrame containing trades (requires columns close_date and profit_ratio) @@ -297,17 +297,17 @@ def calculate_calmar(trades: pd.DataFrame, if (len(trades) == 0) or (min_date is None) or (max_date is None) or (min_date == max_date): return 0 - total_profit = trades["profit_ratio"] - days_period = (max_date - min_date).days + total_profit = trades['profit_abs'].sum() / starting_balance + days_period = max(1, (max_date - min_date).days) # adding slippage of 0.1% per trade # total_profit = total_profit - 0.0005 - expected_returns_mean = total_profit.sum() / days_period * 100 + expected_returns_mean = total_profit / days_period * 100 # calculate max drawdown try: _, _, _, _, _, max_drawdown = calculate_max_drawdown( - trades, value_col="profit_abs" + trades, value_col="profit_abs", starting_balance=starting_balance ) except ValueError: max_drawdown = 0 diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 8ad37e7d8..eb635cde6 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -9,8 +9,9 @@ from tabulate import tabulate from freqtrade.constants import (DATETIME_PRINT_FORMAT, LAST_BT_RESULT_FN, UNLIMITED_STAKE_AMOUNT, Config) -from freqtrade.data.metrics import (calculate_cagr, calculate_csum, calculate_market_change, - calculate_max_drawdown) +from freqtrade.data.metrics import (calculate_cagr, calculate_calmar, calculate_csum, + calculate_expectancy, calculate_market_change, + calculate_max_drawdown, calculate_sharpe, calculate_sortino) from freqtrade.misc import decimals_per_coin, file_dump_joblib, file_dump_json, round_coin_value from freqtrade.optimize.backtest_caching import get_backtest_metadata_filename @@ -448,6 +449,10 @@ def generate_strategy_stats(pairlist: List[str], 'profit_total_long_abs': results.loc[~results['is_short'], 'profit_abs'].sum(), 'profit_total_short_abs': results.loc[results['is_short'], 'profit_abs'].sum(), 'cagr': calculate_cagr(backtest_days, start_balance, content['final_balance']), + 'expectancy': calculate_expectancy(results), + 'sortino': calculate_sortino(results, min_date, max_date), + 'sharpe': calculate_sharpe(results, min_date, max_date), + 'calmar': calculate_calmar(results, min_date, max_date, start_balance), 'profit_factor': profit_factor, 'backtest_start': min_date.strftime(DATETIME_PRINT_FORMAT), 'backtest_start_ts': int(min_date.timestamp() * 1000), @@ -785,6 +790,9 @@ def text_table_add_metrics(strat_results: Dict) -> str: strat_results['stake_currency'])), ('Total profit %', f"{strat_results['profit_total']:.2%}"), ('CAGR %', f"{strat_results['cagr']:.2%}" if 'cagr' in strat_results else 'N/A'), + ('Sortino', f"{strat_results['sortino']:.2f}" if 'sortino' in strat_results else 'N/A'), + ('Sharpe', f"{strat_results['sharpe']:.2f}" if 'sharpe' in strat_results else 'N/A'), + ('Calmar', f"{strat_results['calmar']:.2f}" if 'calmar' in strat_results else 'N/A'), ('Profit factor', f'{strat_results["profit_factor"]:.2f}' if 'profit_factor' in strat_results else 'N/A'), ('Trades per day', strat_results['trades_per_day']),