From 94786454b75a1bdc62e5d7a21f1b53383a85ccca Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 14 May 2024 19:37:41 +0200 Subject: [PATCH] Use calc_drawdown method throughout the bot --- freqtrade/data/metrics.py | 3 +- .../hyperopt_loss_max_drawdown.py | 6 +-- .../optimize_reports/optimize_reports.py | 32 ++++++++-------- freqtrade/plot/plotting.py | 16 ++++---- .../protections/max_drawdown_protection.py | 5 ++- freqtrade/rpc/rpc.py | 37 ++++++++----------- 6 files changed, 45 insertions(+), 54 deletions(-) diff --git a/freqtrade/data/metrics.py b/freqtrade/data/metrics.py index 1f353aab7..87a60daf0 100644 --- a/freqtrade/data/metrics.py +++ b/freqtrade/data/metrics.py @@ -408,9 +408,10 @@ def calculate_calmar( # calculate max drawdown try: - _, _, _, _, _, max_drawdown = calculate_max_drawdown( + drawdown = calc_max_drawdown( trades, value_col="profit_abs", starting_balance=starting_balance ) + max_drawdown = drawdown.relative_account_drawdown except ValueError: max_drawdown = 0 diff --git a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_max_drawdown.py b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_max_drawdown.py index 4d6a7efac..1e065d8ad 100644 --- a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_max_drawdown.py +++ b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_max_drawdown.py @@ -9,7 +9,7 @@ from datetime import datetime from pandas import DataFrame -from freqtrade.data.metrics import calculate_max_drawdown +from freqtrade.data.metrics import calc_max_drawdown from freqtrade.optimize.hyperopt import IHyperOptLoss @@ -38,8 +38,8 @@ class MaxDrawDownHyperOptLoss(IHyperOptLoss): """ total_profit = results["profit_abs"].sum() try: - max_drawdown = calculate_max_drawdown(results, value_col="profit_abs") + max_drawdown = calc_max_drawdown(results, value_col="profit_abs") except ValueError: # No losing trade, therefore no drawdown. return -total_profit - return -total_profit / max_drawdown[0] + return -total_profit / max_drawdown.drawdown_abs diff --git a/freqtrade/optimize/optimize_reports/optimize_reports.py b/freqtrade/optimize/optimize_reports/optimize_reports.py index 1fcf7b271..4f818c21b 100644 --- a/freqtrade/optimize/optimize_reports/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports/optimize_reports.py @@ -8,12 +8,12 @@ from pandas import DataFrame, Series, concat, to_datetime from freqtrade.constants import BACKTEST_BREAKDOWNS, DATETIME_PRINT_FORMAT from freqtrade.data.metrics import ( + calc_max_drawdown, calculate_cagr, calculate_calmar, calculate_csum, calculate_expectancy, calculate_market_change, - calculate_max_drawdown, calculate_sharpe, calculate_sortino, ) @@ -497,29 +497,27 @@ def generate_strategy_stats( } try: - max_drawdown_legacy, _, _, _, _, _ = calculate_max_drawdown( - results, value_col="profit_ratio" - ) - (drawdown_abs, drawdown_start, drawdown_end, high_val, low_val, max_drawdown) = ( - calculate_max_drawdown(results, value_col="profit_abs", starting_balance=start_balance) + max_drawdown_legacy = calc_max_drawdown(results, value_col="profit_ratio") + drawdown = calc_max_drawdown( + results, value_col="profit_abs", starting_balance=start_balance ) # max_relative_drawdown = Underwater - (_, _, _, _, _, max_relative_drawdown) = calculate_max_drawdown( + underwater = calc_max_drawdown( results, value_col="profit_abs", starting_balance=start_balance, relative=True ) strat_stats.update( { - "max_drawdown": max_drawdown_legacy, # Deprecated - do not use - "max_drawdown_account": max_drawdown, - "max_relative_drawdown": max_relative_drawdown, - "max_drawdown_abs": drawdown_abs, - "drawdown_start": drawdown_start.strftime(DATETIME_PRINT_FORMAT), - "drawdown_start_ts": drawdown_start.timestamp() * 1000, - "drawdown_end": drawdown_end.strftime(DATETIME_PRINT_FORMAT), - "drawdown_end_ts": drawdown_end.timestamp() * 1000, - "max_drawdown_low": low_val, - "max_drawdown_high": high_val, + "max_drawdown": max_drawdown_legacy.drawdown_abs, # Deprecated - do not use + "max_drawdown_account": drawdown.relative_account_drawdown, + "max_relative_drawdown": underwater.relative_account_drawdown, + "max_drawdown_abs": drawdown.drawdown_abs, + "drawdown_start": drawdown.high_date.strftime(DATETIME_PRINT_FORMAT), + "drawdown_start_ts": drawdown.high_date.timestamp() * 1000, + "drawdown_end": drawdown.low_date.strftime(DATETIME_PRINT_FORMAT), + "drawdown_end_ts": drawdown.low_date.timestamp() * 1000, + "max_drawdown_low": drawdown.low_value, + "max_drawdown_high": drawdown.high_value, } ) diff --git a/freqtrade/plot/plotting.py b/freqtrade/plot/plotting.py index acb3a1999..0f0e9d527 100644 --- a/freqtrade/plot/plotting.py +++ b/freqtrade/plot/plotting.py @@ -16,7 +16,7 @@ from freqtrade.data.converter import trim_dataframe from freqtrade.data.dataprovider import DataProvider from freqtrade.data.history import get_timerange, load_data from freqtrade.data.metrics import ( - calculate_max_drawdown, + calc_max_drawdown, calculate_underwater, combine_dataframes_with_mean, create_cum_profit, @@ -179,19 +179,17 @@ def add_max_drawdown( Add scatter points indicating max drawdown """ try: - _, highdate, lowdate, _, _, max_drawdown = calculate_max_drawdown( - trades, starting_balance=starting_balance - ) + drawdown = calc_max_drawdown(trades, starting_balance=starting_balance) drawdown = go.Scatter( - x=[highdate, lowdate], + x=[drawdown.high_date, drawdown.low_date], y=[ - df_comb.loc[timeframe_to_prev_date(timeframe, highdate), "cum_profit"], - df_comb.loc[timeframe_to_prev_date(timeframe, lowdate), "cum_profit"], + df_comb.loc[timeframe_to_prev_date(timeframe, drawdown.high_date), "cum_profit"], + df_comb.loc[timeframe_to_prev_date(timeframe, drawdown.low_date), "cum_profit"], ], mode="markers", - name=f"Max drawdown {max_drawdown:.2%}", - text=f"Max drawdown {max_drawdown:.2%}", + name=f"Max drawdown {drawdown.relative_account_drawdown:.2%}", + text=f"Max drawdown {drawdown.relative_account_drawdown:.2%}", marker=dict(symbol="square-open", size=9, line=dict(width=2), color="green"), ) fig.add_trace(drawdown, row, 1) diff --git a/freqtrade/plugins/protections/max_drawdown_protection.py b/freqtrade/plugins/protections/max_drawdown_protection.py index 3e252185f..852e2dca5 100644 --- a/freqtrade/plugins/protections/max_drawdown_protection.py +++ b/freqtrade/plugins/protections/max_drawdown_protection.py @@ -5,7 +5,7 @@ from typing import Any, Dict, Optional import pandas as pd from freqtrade.constants import Config, LongShort -from freqtrade.data.metrics import calculate_max_drawdown +from freqtrade.data.metrics import calc_max_drawdown from freqtrade.persistence import Trade from freqtrade.plugins.protections import IProtection, ProtectionReturn @@ -59,7 +59,8 @@ class MaxDrawdown(IProtection): # Drawdown is always positive try: # TODO: This should use absolute profit calculation, considering account balance. - drawdown, _, _, _, _, _ = calculate_max_drawdown(trades_df, value_col="close_profit") + drawdown_obj = calc_max_drawdown(trades_df, value_col="close_profit") + drawdown = drawdown_obj.drawdown_abs except ValueError: return None diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index bcc262194..c949caea4 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -19,7 +19,11 @@ from freqtrade import __version__ from freqtrade.configuration.timerange import TimeRange from freqtrade.constants import CANCEL_REASON, DEFAULT_DATAFRAME_COLUMNS, Config from freqtrade.data.history import load_data -from freqtrade.data.metrics import calculate_expectancy, calculate_max_drawdown +from freqtrade.data.metrics import ( + DrawDownResult, + calc_max_drawdown, + calculate_expectancy, +) from freqtrade.enums import ( CandleType, ExitCheckTuple, @@ -592,21 +596,10 @@ class RPC: expectancy, expectancy_ratio = calculate_expectancy(trades_df) - max_drawdown_abs = 0.0 - max_drawdown = 0.0 - drawdown_start: Optional[datetime] = None - drawdown_end: Optional[datetime] = None - dd_high_val = dd_low_val = 0.0 + drawdown = DrawDownResult(0.0, 0.0, None, None, 0.0) if len(trades_df) > 0: try: - ( - max_drawdown_abs, - drawdown_start, - drawdown_end, - dd_high_val, - dd_low_val, - max_drawdown, - ) = calculate_max_drawdown( + drawdown = calc_max_drawdown( trades_df, value_col="profit_abs", date_col="close_date_dt", @@ -663,14 +656,14 @@ class RPC: "winrate": winrate, "expectancy": expectancy, "expectancy_ratio": expectancy_ratio, - "max_drawdown": max_drawdown, - "max_drawdown_abs": max_drawdown_abs, - "max_drawdown_start": format_date(drawdown_start), - "max_drawdown_start_timestamp": dt_ts_def(drawdown_start), - "max_drawdown_end": format_date(drawdown_end), - "max_drawdown_end_timestamp": dt_ts_def(drawdown_end), - "drawdown_high": dd_high_val, - "drawdown_low": dd_low_val, + "max_drawdown": drawdown.relative_account_drawdown, + "max_drawdown_abs": drawdown.drawdown_abs, + "max_drawdown_start": format_date(drawdown.high_date), + "max_drawdown_start_timestamp": dt_ts_def(drawdown.high_date), + "max_drawdown_end": format_date(drawdown.low_date), + "max_drawdown_end_timestamp": dt_ts_def(drawdown.low_date), + "drawdown_high": drawdown.high_value, + "drawdown_low": drawdown.low_value, "trading_volume": trading_volume, "bot_start_timestamp": dt_ts_def(bot_start, 0), "bot_start_date": format_date(bot_start),