diff --git a/freqtrade/data/metrics.py b/freqtrade/data/metrics.py index 0bee68326..1f353aab7 100644 --- a/freqtrade/data/metrics.py +++ b/freqtrade/data/metrics.py @@ -1,5 +1,6 @@ import logging import math +from dataclasses import dataclass from datetime import datetime from typing import Dict, Tuple @@ -160,14 +161,33 @@ def calculate_underwater( return max_drawdown_df -def calculate_max_drawdown( +@dataclass() +class DrawDownResult: + __slots__ = [ + "drawdown_abs", + "high_date", + "low_date", + "high_value", + "low_value", + "relative_account_drawdown", + ] + + drawdown_abs: float + high_date: datetime + low_date: datetime + high_value: float + low_value: float + relative_account_drawdown: float + + +def calc_max_drawdown( trades: pd.DataFrame, *, date_col: str = "close_date", value_col: str = "profit_abs", starting_balance: float = 0, relative: bool = False, -) -> Tuple[float, pd.Timestamp, pd.Timestamp, float, float, float]: +) -> DrawDownResult: """ Calculate max drawdown and the corresponding close dates :param trades: DataFrame containing trades (requires columns close_date and profit_ratio) @@ -201,13 +221,51 @@ def calculate_max_drawdown( low_val = max_drawdown_df.loc[idxmin, "cumulative"] max_drawdown_rel = max_drawdown_df.loc[idxmin, "drawdown_relative"] + return DrawDownResult( + drawdown_abs=abs(max_drawdown_df.loc[idxmin, "drawdown"]), + high_date=high_date, + low_date=low_date, + high_value=high_val, + low_value=low_val, + relative_account_drawdown=max_drawdown_rel, + ) + + +def calculate_max_drawdown( + trades: pd.DataFrame, + *, + date_col: str = "close_date", + value_col: str = "profit_abs", + starting_balance: float = 0, + relative: bool = False, +) -> Tuple[float, pd.Timestamp, pd.Timestamp, float, float, float]: + """ + Calculate max drawdown and the corresponding close dates + Deprecated, favor calc_max_drawdown instead! + :param trades: DataFrame containing trades (requires columns close_date and profit_ratio) + :param date_col: Column in DataFrame to use for dates (defaults to 'close_date') + :param value_col: Column in DataFrame to use for values (defaults to 'profit_abs') + :param starting_balance: Portfolio starting balance - properly calculate relative drawdown. + :return: Tuple (float, highdate, lowdate, highvalue, lowvalue, relative_drawdown) + with absolute max drawdown, high and low time and high and low value, + and the relative account drawdown + :raise: ValueError if trade-dataframe was found empty. + """ + # TODO: add deprecation warning + res = calc_max_drawdown( + trades, + date_col=date_col, + value_col=value_col, + starting_balance=starting_balance, + relative=relative, + ) return ( - abs(max_drawdown_df.loc[idxmin, "drawdown"]), - high_date, - low_date, - high_val, - low_val, - max_drawdown_rel, + res.drawdown_abs, + res.high_date, + res.low_date, + res.high_value, + res.low_value, + res.relative_account_drawdown, )