Remove compatibility layer for calculate_max_drawdown

This commit is contained in:
Matthias 2024-05-15 06:54:17 +02:00
parent c79b75ff9a
commit a6b07ec96f
8 changed files with 25 additions and 62 deletions

View File

@ -171,7 +171,7 @@ class DrawDownResult:
relative_account_drawdown: float = 0.0
def calc_max_drawdown(
def calculate_max_drawdown(
trades: pd.DataFrame,
*,
date_col: str = "close_date",
@ -185,7 +185,7 @@ def calc_max_drawdown(
: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)
:return: DrawDownResult object
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.
@ -222,44 +222,6 @@ def calc_max_drawdown(
)
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 (
res.drawdown_abs,
res.high_date,
res.low_date,
res.high_value,
res.low_value,
res.relative_account_drawdown,
)
def calculate_csum(trades: pd.DataFrame, starting_balance: float = 0) -> Tuple[float, float]:
"""
Calculate min/max cumsum of trades, to show if the wallet/stake amount ratio is sane
@ -399,7 +361,7 @@ def calculate_calmar(
# calculate max drawdown
try:
drawdown = calc_max_drawdown(
drawdown = calculate_max_drawdown(
trades, value_col="profit_abs", starting_balance=starting_balance
)
max_drawdown = drawdown.relative_account_drawdown

View File

@ -9,7 +9,7 @@ from datetime import datetime
from pandas import DataFrame
from freqtrade.data.metrics import calc_max_drawdown
from freqtrade.data.metrics import calculate_max_drawdown
from freqtrade.optimize.hyperopt import IHyperOptLoss
@ -38,7 +38,7 @@ class MaxDrawDownHyperOptLoss(IHyperOptLoss):
"""
total_profit = results["profit_abs"].sum()
try:
max_drawdown = calc_max_drawdown(results, value_col="profit_abs")
max_drawdown = calculate_max_drawdown(results, value_col="profit_abs")
except ValueError:
# No losing trade, therefore no drawdown.
return -total_profit

View File

@ -10,7 +10,7 @@ individual needs.
from pandas import DataFrame
from freqtrade.data.metrics import calc_max_drawdown
from freqtrade.data.metrics import calculate_max_drawdown
from freqtrade.optimize.hyperopt import IHyperOptLoss
@ -24,7 +24,7 @@ class ProfitDrawDownHyperOptLoss(IHyperOptLoss):
total_profit = results["profit_abs"].sum()
try:
drawdown = calc_max_drawdown(results, value_col="profit_abs")
drawdown = calculate_max_drawdown(results, value_col="profit_abs")
relative_account_drawdown = drawdown.relative_account_drawdown
except ValueError:
relative_account_drawdown = 0

View File

@ -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,12 +497,12 @@ def generate_strategy_stats(
}
try:
max_drawdown_legacy = calc_max_drawdown(results, value_col="profit_ratio")
drawdown = calc_max_drawdown(
max_drawdown_legacy = calculate_max_drawdown(results, value_col="profit_ratio")
drawdown = calculate_max_drawdown(
results, value_col="profit_abs", starting_balance=start_balance
)
# max_relative_drawdown = Underwater
underwater = calc_max_drawdown(
underwater = calculate_max_drawdown(
results, value_col="profit_abs", starting_balance=start_balance, relative=True
)

View File

@ -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 (
calc_max_drawdown,
calculate_max_drawdown,
calculate_underwater,
combine_dataframes_with_mean,
create_cum_profit,
@ -179,7 +179,7 @@ def add_max_drawdown(
Add scatter points indicating max drawdown
"""
try:
drawdown = calc_max_drawdown(trades, starting_balance=starting_balance)
drawdown = calculate_max_drawdown(trades, starting_balance=starting_balance)
drawdown = go.Scatter(
x=[drawdown.high_date, drawdown.low_date],

View File

@ -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 calc_max_drawdown
from freqtrade.data.metrics import calculate_max_drawdown
from freqtrade.persistence import Trade
from freqtrade.plugins.protections import IProtection, ProtectionReturn
@ -59,7 +59,7 @@ class MaxDrawdown(IProtection):
# Drawdown is always positive
try:
# TODO: This should use absolute profit calculation, considering account balance.
drawdown_obj = calc_max_drawdown(trades_df, value_col="close_profit")
drawdown_obj = calculate_max_drawdown(trades_df, value_col="close_profit")
drawdown = drawdown_obj.drawdown_abs
except ValueError:
return None

View File

@ -21,8 +21,8 @@ from freqtrade.constants import CANCEL_REASON, DEFAULT_DATAFRAME_COLUMNS, Config
from freqtrade.data.history import load_data
from freqtrade.data.metrics import (
DrawDownResult,
calc_max_drawdown,
calculate_expectancy,
calculate_max_drawdown,
)
from freqtrade.enums import (
CandleType,
@ -599,7 +599,7 @@ class RPC:
drawdown = DrawDownResult()
if len(trades_df) > 0:
try:
drawdown = calc_max_drawdown(
drawdown = calculate_max_drawdown(
trades_df,
value_col="profit_abs",
date_col="close_date_dt",

View File

@ -20,7 +20,6 @@ from freqtrade.data.btanalysis import (
)
from freqtrade.data.history import load_data, load_pair_history
from freqtrade.data.metrics import (
calc_max_drawdown,
calculate_cagr,
calculate_calmar,
calculate_csum,
@ -344,7 +343,7 @@ def test_create_cum_profit1(testdatadir):
def test_calculate_max_drawdown(testdatadir):
filename = testdatadir / "backtest_results/backtest-result.json"
bt_data = load_backtest_data(filename)
drawdown = calc_max_drawdown(bt_data, value_col="profit_abs")
drawdown = calculate_max_drawdown(bt_data, value_col="profit_abs")
assert isinstance(drawdown.relative_account_drawdown, float)
assert pytest.approx(drawdown.relative_account_drawdown) == 0.29753914
assert isinstance(drawdown.high_date, Timestamp)
@ -358,7 +357,7 @@ def test_calculate_max_drawdown(testdatadir):
assert isinstance(underwater, DataFrame)
with pytest.raises(ValueError, match="Trade dataframe empty."):
calc_max_drawdown(DataFrame())
calculate_max_drawdown(DataFrame())
with pytest.raises(ValueError, match="Trade dataframe empty."):
calculate_underwater(DataFrame())
@ -508,7 +507,7 @@ def test_calculate_max_drawdown2():
# sort by profit and reset index
df = df.sort_values("profit").reset_index(drop=True)
df1 = df.copy()
drawdown = calc_max_drawdown(df, date_col="open_date", value_col="profit")
drawdown = calculate_max_drawdown(df, date_col="open_date", value_col="profit")
# Ensure df has not been altered.
assert df.equals(df1)
@ -522,12 +521,12 @@ def test_calculate_max_drawdown2():
df = DataFrame(zip(values[:5], dates[:5]), columns=["profit", "open_date"])
with pytest.raises(ValueError, match="No losing trade, therefore no drawdown."):
calc_max_drawdown(df, date_col="open_date", value_col="profit")
calculate_max_drawdown(df, date_col="open_date", value_col="profit")
df1 = DataFrame(zip(values[:5], dates[:5]), columns=["profit", "open_date"])
df1.loc[:, "profit"] = df1["profit"] * -1
# No winning trade ...
drawdown = calc_max_drawdown(df1, date_col="open_date", value_col="profit")
drawdown = calculate_max_drawdown(df1, date_col="open_date", value_col="profit")
assert drawdown.drawdown_abs == 0.043965
@ -550,7 +549,9 @@ def test_calculate_max_drawdown_abs(profits, relative, highd, lowdays, result, r
# sort by profit and reset index
df = df.sort_values("profit_abs").reset_index(drop=True)
df1 = df.copy()
drawdown = calc_max_drawdown(df, date_col="open_date", starting_balance=1000, relative=relative)
drawdown = calculate_max_drawdown(
df, date_col="open_date", starting_balance=1000, relative=relative
)
# Ensure df has not been altered.
assert df.equals(df1)