Expand calculate_max_drawdown() to return the current drawdown data and use it instead of calculate_current_drawdown()
This commit is contained in:
+54
-68
@@ -174,12 +174,18 @@ def calculate_underwater(
|
|||||||
|
|
||||||
@dataclass()
|
@dataclass()
|
||||||
class DrawDownResult:
|
class DrawDownResult:
|
||||||
drawdown_abs: float = 0.0
|
# Max drawdown fields
|
||||||
high_date: pd.Timestamp = None
|
high_date: pd.Timestamp = None
|
||||||
low_date: pd.Timestamp = None
|
low_date: pd.Timestamp = None
|
||||||
high_value: float = 0.0
|
high_value: float = 0.0
|
||||||
low_value: float = 0.0
|
low_value: float = 0.0
|
||||||
|
drawdown_abs: float = 0.0
|
||||||
relative_account_drawdown: float = 0.0
|
relative_account_drawdown: float = 0.0
|
||||||
|
# Current drawdown fields
|
||||||
|
current_high_date: pd.Timestamp = None
|
||||||
|
current_high_value: float = 0.0
|
||||||
|
current_drawdown_abs: float = 0.0
|
||||||
|
current_relative_account_drawdown: float = 0.0
|
||||||
|
|
||||||
|
|
||||||
def calculate_max_drawdown(
|
def calculate_max_drawdown(
|
||||||
@@ -191,88 +197,68 @@ def calculate_max_drawdown(
|
|||||||
relative: bool = False,
|
relative: bool = False,
|
||||||
) -> DrawDownResult:
|
) -> DrawDownResult:
|
||||||
"""
|
"""
|
||||||
Calculate max drawdown and the corresponding close dates
|
Calculate max drawdown and current drawdown with corresponding dates
|
||||||
:param trades: DataFrame containing trades (requires columns close_date and profit_ratio)
|
:param trades: DataFrame containing trades (requires columns close_date and profit_abs)
|
||||||
:param date_col: Column in DataFrame to use for dates (defaults to 'close_date')
|
: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 value_col: Column in DataFrame to use for values (defaults to 'profit_abs')
|
||||||
:param starting_balance: Portfolio starting balance - properly calculate relative drawdown.
|
:param starting_balance: Portfolio starting balance - properly calculate relative drawdown.
|
||||||
|
:param relative: If True, use relative drawdown for max calculation instead of absolute
|
||||||
:return: DrawDownResult object
|
:return: DrawDownResult object
|
||||||
with absolute max drawdown, high and low time and high and low value,
|
with absolute max drawdown, high and low time and high and low value,
|
||||||
and the relative account drawdown
|
relative account drawdown, and current drawdown information.
|
||||||
:raise: ValueError if trade-dataframe was found empty.
|
:raise: ValueError if trade-dataframe was found empty.
|
||||||
"""
|
"""
|
||||||
if len(trades) == 0:
|
|
||||||
raise ValueError("Trade dataframe empty.")
|
|
||||||
profit_results = trades.sort_values(date_col).reset_index(drop=True)
|
|
||||||
max_drawdown_df = _calc_drawdown_series(
|
|
||||||
profit_results, date_col=date_col, value_col=value_col, starting_balance=starting_balance
|
|
||||||
)
|
|
||||||
|
|
||||||
idxmin = (
|
|
||||||
max_drawdown_df["drawdown_relative"].idxmax()
|
|
||||||
if relative
|
|
||||||
else max_drawdown_df["drawdown"].idxmin()
|
|
||||||
)
|
|
||||||
|
|
||||||
high_idx = max_drawdown_df.iloc[: idxmin + 1]["high_value"].idxmax()
|
|
||||||
high_date = profit_results.loc[high_idx, date_col]
|
|
||||||
low_date = profit_results.loc[idxmin, date_col]
|
|
||||||
high_val = max_drawdown_df.loc[high_idx, "cumulative"]
|
|
||||||
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_current_drawdown(trades: pd.DataFrame, starting_balance: float):
|
|
||||||
"""
|
|
||||||
Calculates the current drawdown (loss from historical maximum) based on closed trades.
|
|
||||||
|
|
||||||
:param trades: DataFrame containing trades (requires columns close_date_dt and profit_abs)
|
|
||||||
:param starting_balance: Initial account balance
|
|
||||||
:return: DrawDownResult object including:
|
|
||||||
- drawdown_abs: Drawdown in absolute terms
|
|
||||||
- relative_account_drawdown: Drawdown relative to max balance
|
|
||||||
- high_value: Maximum profit reached
|
|
||||||
- high_date: Date when the max profit was reached
|
|
||||||
"""
|
|
||||||
|
|
||||||
if len(trades) == 0:
|
if len(trades) == 0:
|
||||||
raise ValueError("Trade dataframe empty.")
|
raise ValueError("Trade dataframe empty.")
|
||||||
|
|
||||||
# Sort trades by close date
|
# Sort trades by close date
|
||||||
sorted_df = trades.sort_values("close_date_dt").reset_index(drop=True)
|
profit_results = trades.sort_values(date_col).reset_index(drop=True)
|
||||||
|
|
||||||
# Calculate cumulative profit
|
# Get drawdown data
|
||||||
cum_profit = sorted_df["profit_abs"].cumsum()
|
max_drawdown_df = _calc_drawdown_series(
|
||||||
|
profit_results, date_col=date_col, value_col=value_col, starting_balance=starting_balance
|
||||||
# Find historical maximum profit and its date
|
|
||||||
max_profit_idx = cum_profit.idxmax()
|
|
||||||
max_profit = cum_profit.iloc[max_profit_idx]
|
|
||||||
max_date = sorted_df.iloc[max_profit_idx]["close_date_dt"]
|
|
||||||
|
|
||||||
# Calculate current and max balance
|
|
||||||
current_balance = starting_balance + cum_profit.iloc[-1]
|
|
||||||
max_balance = starting_balance + max_profit
|
|
||||||
|
|
||||||
# Calculate drawdown
|
|
||||||
drawdown_abs = max_balance - current_balance
|
|
||||||
drawdown_relative = drawdown_abs / max_balance
|
|
||||||
|
|
||||||
return DrawDownResult(
|
|
||||||
drawdown_abs=drawdown_abs,
|
|
||||||
relative_account_drawdown=drawdown_relative,
|
|
||||||
high_value=max_profit,
|
|
||||||
high_date=max_date,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Calculate maximum drawdown
|
||||||
|
idxmin = (
|
||||||
|
max_drawdown_df["drawdown_relative"].idxmax()
|
||||||
|
if relative
|
||||||
|
else max_drawdown_df["drawdown"].idxmin()
|
||||||
|
)
|
||||||
|
high_idx = max_drawdown_df.iloc[: idxmin + 1]["high_value"].idxmax()
|
||||||
|
high_date = profit_results.loc[high_idx, date_col]
|
||||||
|
low_date = profit_results.loc[idxmin, date_col]
|
||||||
|
high_val = max_drawdown_df.loc[high_idx, "cumulative"]
|
||||||
|
low_val = max_drawdown_df.loc[idxmin, "cumulative"]
|
||||||
|
max_drawdown_abs = abs(max_drawdown_df.loc[idxmin, "drawdown"])
|
||||||
|
max_drawdown_rel = max_drawdown_df.loc[idxmin, "drawdown_relative"]
|
||||||
|
|
||||||
|
# Calculate current drawdown
|
||||||
|
current_high_idx = max_drawdown_df["high_value"].iloc[:-1].idxmax()
|
||||||
|
current_high_date = profit_results.loc[current_high_idx, date_col]
|
||||||
|
current_high_value = max_drawdown_df.iloc[-1]["high_value"]
|
||||||
|
current_cumulative = max_drawdown_df.iloc[-1]["cumulative"]
|
||||||
|
current_drawdown_abs = current_high_value - current_cumulative
|
||||||
|
current_drawdown_relative = max_drawdown_df.iloc[-1]["drawdown_relative"]
|
||||||
|
|
||||||
|
result = DrawDownResult(
|
||||||
|
# Max drawdown
|
||||||
|
high_date=high_date,
|
||||||
|
low_date=low_date,
|
||||||
|
high_value=high_val,
|
||||||
|
low_value=low_val,
|
||||||
|
drawdown_abs=max_drawdown_abs,
|
||||||
|
relative_account_drawdown=max_drawdown_rel,
|
||||||
|
# Current drawdown
|
||||||
|
current_high_date=current_high_date,
|
||||||
|
current_high_value=current_high_value,
|
||||||
|
current_drawdown_abs=current_drawdown_abs,
|
||||||
|
current_relative_account_drawdown=current_drawdown_relative,
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
def calculate_csum(trades: pd.DataFrame, starting_balance: float = 0) -> tuple[float, float]:
|
def calculate_csum(trades: pd.DataFrame, starting_balance: float = 0) -> tuple[float, float]:
|
||||||
"""
|
"""
|
||||||
|
|||||||
+6
-18
@@ -19,12 +19,7 @@ from freqtrade import __version__
|
|||||||
from freqtrade.configuration.timerange import TimeRange
|
from freqtrade.configuration.timerange import TimeRange
|
||||||
from freqtrade.constants import CANCEL_REASON, DEFAULT_DATAFRAME_COLUMNS, Config
|
from freqtrade.constants import CANCEL_REASON, DEFAULT_DATAFRAME_COLUMNS, Config
|
||||||
from freqtrade.data.history import load_data
|
from freqtrade.data.history import load_data
|
||||||
from freqtrade.data.metrics import (
|
from freqtrade.data.metrics import DrawDownResult, calculate_expectancy, calculate_max_drawdown
|
||||||
DrawDownResult,
|
|
||||||
calculate_current_drawdown,
|
|
||||||
calculate_expectancy,
|
|
||||||
calculate_max_drawdown,
|
|
||||||
)
|
|
||||||
from freqtrade.enums import (
|
from freqtrade.enums import (
|
||||||
CandleType,
|
CandleType,
|
||||||
ExitCheckTuple,
|
ExitCheckTuple,
|
||||||
@@ -616,9 +611,7 @@ class RPC:
|
|||||||
)
|
)
|
||||||
|
|
||||||
expectancy, expectancy_ratio = calculate_expectancy(trades_df)
|
expectancy, expectancy_ratio = calculate_expectancy(trades_df)
|
||||||
|
|
||||||
max_drawdown = DrawDownResult()
|
max_drawdown = DrawDownResult()
|
||||||
current_drawdown = DrawDownResult()
|
|
||||||
|
|
||||||
if len(trades_df) > 0:
|
if len(trades_df) > 0:
|
||||||
try:
|
try:
|
||||||
@@ -631,11 +624,6 @@ class RPC:
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
|
||||||
current_drawdown = calculate_current_drawdown(trades_df, starting_balance)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
profit_all_fiat = (
|
profit_all_fiat = (
|
||||||
self._fiat_converter.convert_amount(
|
self._fiat_converter.convert_amount(
|
||||||
profit_all_coin_sum, stake_currency, fiat_display_currency
|
profit_all_coin_sum, stake_currency, fiat_display_currency
|
||||||
@@ -692,11 +680,11 @@ class RPC:
|
|||||||
"max_drawdown_end_timestamp": dt_ts_def(max_drawdown.low_date),
|
"max_drawdown_end_timestamp": dt_ts_def(max_drawdown.low_date),
|
||||||
"drawdown_high": max_drawdown.high_value,
|
"drawdown_high": max_drawdown.high_value,
|
||||||
"drawdown_low": max_drawdown.low_value,
|
"drawdown_low": max_drawdown.low_value,
|
||||||
"current_drawdown": current_drawdown.relative_account_drawdown,
|
"current_drawdown": max_drawdown.current_relative_account_drawdown,
|
||||||
"current_drawdown_abs": current_drawdown.drawdown_abs,
|
"current_drawdown_abs": max_drawdown.current_drawdown_abs,
|
||||||
"current_drawdown_high": current_drawdown.high_value,
|
"current_drawdown_high": max_drawdown.current_high_value,
|
||||||
"current_drawdown_start": format_date(current_drawdown.high_date),
|
"current_drawdown_start": format_date(max_drawdown.current_high_date),
|
||||||
"current_drawdown_start_timestamp": dt_ts_def(current_drawdown.high_date),
|
"current_drawdown_start_timestamp": dt_ts_def(max_drawdown.current_high_date),
|
||||||
"trading_volume": trading_volume,
|
"trading_volume": trading_volume,
|
||||||
"bot_start_timestamp": dt_ts_def(bot_start, 0),
|
"bot_start_timestamp": dt_ts_def(bot_start, 0),
|
||||||
"bot_start_date": format_date(bot_start),
|
"bot_start_date": format_date(bot_start),
|
||||||
|
|||||||
Reference in New Issue
Block a user