test done

This commit is contained in:
Guitheg 2021-12-13 10:15:34 +01:00
parent 91e57f64d4
commit d08b0918ad
2 changed files with 59 additions and 48 deletions

View File

@ -390,6 +390,7 @@ def calculate_max_drawdown(trades: pd.DataFrame, *, date_col: str = 'close_date'
low_val = max_drawdown_df.loc[idxmin, 'cumulative'] low_val = max_drawdown_df.loc[idxmin, 'cumulative']
return abs(min(max_drawdown_df['drawdown'])), high_date, low_date, high_val, low_val return abs(min(max_drawdown_df['drawdown'])), high_date, low_date, high_val, low_val
# TODO : is supposed to work only with long positions
def calculate_trades_mdd(data: dict, trades: pd.DataFrame) -> float : def calculate_trades_mdd(data: dict, trades: pd.DataFrame) -> float :
""" """
Calculate Trades MDD (Max DrawDown) : Calculate Trades MDD (Max DrawDown) :
@ -409,57 +410,55 @@ def calculate_trades_mdd(data: dict, trades: pd.DataFrame) -> float :
trades_mdd_pair_list = [] trades_mdd_pair_list = []
for pair, df in data.items(): for pair, df in data.items():
if df is None: if isinstance(df, pd.DataFrame):
break # Gather the opening and closing trade dates into one Dates DataFrame
open_close_trades = trades.loc[trades['pair']==pair][["open_date","close_date"]]
open_close_trades = pd.concat(
[open_close_trades.rename(columns={'open_date':'date'})[['date']],
open_close_trades.rename(columns={'close_date':'date'})[['date']]]
).sort_values(by='date')
# Mark the dates and join it to the current candle dataframe.
# This allow to determine the open and close trade dates in the current
# candle dataframe.
open_close_trades['open_close_mark'] = 1
data_join = df.set_index('date').join(open_close_trades.set_index('date'))
del open_close_trades
# Gather the opening and closing trade dates into one Dates DataFrame # Gather, mark and join only the opening trade dates into the current candle
open_close_trades = trades.loc[trades['pair']==pair][["open_date","close_date"]] # dataframe.
open_close_trades = pd.concat( # This allow to classify trades using the cumsum and split by classes
[open_close_trades.rename(columns={'open_date':'date'})[['date']], # with groupby in order to process a cummax on each trades independantly.
open_close_trades.rename(columns={'close_date':'date'})[['date']]] open_trades = trades.loc[trades['pair']==pair][["open_date"]]
).sort_values(by='date') open_trades = open_trades.rename(columns={'open_date':'date'})
open_trades['open_mark'] = 1
# Mark the dates and join it to the current candle dataframe. data_join = data_join.join(open_trades.set_index('date'))
# This allow to determine the open and close trade dates in the current del open_trades
# candle dataframe.
open_close_trades['open_close_mark'] = 1
data_join = df.set_index('date').join(open_close_trades.set_index('date'))
del open_close_trades
# Gather, mark and join only the opening trade dates into the current candle # Set all unmarked date to 0
# dataframe. data_join[["open_close_mark",'open_mark']] = data_join[
# This allow to classify trades using the cumsum and split by classes ["open_close_mark",'open_mark']].fillna(0).astype(int)
# with groupby in order to process a cummax on each trades independantly.
open_trades = trades.loc[trades['pair']==pair][["open_date"]]
open_trades = open_trades.rename(columns={'open_date':'date'})
open_trades['open_mark'] = 1
data_join = data_join.join(open_trades.set_index('date'))
del open_trades
# Set all unmarked date to 0 # Mark with one all dates between an opening date trades and a closing date trades.
data_join[["open_close_mark",'open_mark']] = data_join[ data_join['is_in_trade'] = data_join.open_close_mark.cumsum()&1 # &1 <=> %2
["open_close_mark",'open_mark']].fillna(0).astype(int) data_join.loc[data_join['open_close_mark'] == 1, 'is_in_trade'] = 1
# Perform a cummax in each trades independtly
data_join['close_cummax'] = 0
data_join['close_cummax'] = data_join.groupby(
data_join['open_mark'].cumsum()
)['close'].cummax()
data_join.loc[data_join['is_in_trade'] == 0, 'close_cummax'] = 0
# Mark with one all dates between an opening date trades and a closing date trades. # Compute the drawdown at each time of each trades
data_join['is_in_trade'] = data_join.open_close_mark.cumsum()&1 # &1 <=> %2 data_join = data_join.rename(columns={'open_mark':'drawdown'})
data_join.loc[data_join['open_close_mark'] == 1, 'is_in_trade'] = 1 data_join.loc[data_join['is_in_trade'] == 1, 'drawdown'] = \
(data_join['close_cummax'] - data_join['close']) \
# Perform a cummax in each trades independtly / data_join['close_cummax']
data_join['close_cummax'] = 0
data_join['close_cummax'] = data_join.groupby(
data_join['open_mark'].cumsum()
)['close'].cummax()
data_join.loc[data_join['is_in_trade'] == 0, 'close_cummax'] = 0
# Compute the drawdown at each time of each trades mdd_pair = data_join['drawdown'].max()
data_join = data_join.rename(columns={'open_mark':'drawdown'}) trades_mdd_pair_list.append(mdd_pair)
data_join.loc[data_join['is_in_trade'] == 1, 'drawdown'] = \
(data_join['close_cummax'] - data_join['close']) \
/ data_join['close_cummax']
mdd_pair = data_join['drawdown'].max()
trades_mdd_pair_list.append(mdd_pair)
if trades_mdd_pair_list == []: if trades_mdd_pair_list == []:
raise ValueError("All dataframe in candle data are None") raise ValueError("All dataframe in candle data are None")

View File

@ -1,7 +1,7 @@
from math import isclose from math import isclose
from pathlib import Path from pathlib import Path
from unittest.mock import MagicMock from unittest.mock import MagicMock
import numpy as np
import pytest import pytest
from arrow import Arrow from arrow import Arrow
from pandas import DataFrame, DateOffset, Timestamp, to_datetime from pandas import DataFrame, DateOffset, Timestamp, to_datetime
@ -10,7 +10,7 @@ from freqtrade.configuration import TimeRange
from freqtrade.constants import LAST_BT_RESULT_FN from freqtrade.constants import LAST_BT_RESULT_FN
from freqtrade.data.btanalysis import (BT_DATA_COLUMNS, BT_DATA_COLUMNS_MID, BT_DATA_COLUMNS_OLD, from freqtrade.data.btanalysis import (BT_DATA_COLUMNS, BT_DATA_COLUMNS_MID, BT_DATA_COLUMNS_OLD,
analyze_trade_parallelism, calculate_csum, analyze_trade_parallelism, calculate_csum,
calculate_market_change, calculate_max_drawdown, calculate_market_change, calculate_max_drawdown, calculate_trades_mdd,
combine_dataframes_with_mean, create_cum_profit, combine_dataframes_with_mean, create_cum_profit,
extract_trades_of_period, get_latest_backtest_filename, extract_trades_of_period, get_latest_backtest_filename,
get_latest_hyperopt_file, load_backtest_data, load_trades, get_latest_hyperopt_file, load_backtest_data, load_trades,
@ -332,3 +332,15 @@ def test_calculate_max_drawdown2():
df = DataFrame(zip(values[:5], dates[:5]), columns=['profit', 'open_date']) df = DataFrame(zip(values[:5], dates[:5]), columns=['profit', 'open_date'])
with pytest.raises(ValueError, match='No losing trade, therefore no drawdown.'): with pytest.raises(ValueError, match='No losing trade, therefore no drawdown.'):
calculate_max_drawdown(df, date_col='open_date', value_col='profit') calculate_max_drawdown(df, date_col='open_date', value_col='profit')
def test_calculate_trades_mdd(testdatadir):
backtest_file = testdatadir / "backtest-result_test.json"
trades = load_backtest_data(backtest_file)
pairlist = set(trades["pair"])
with pytest.raises(ValueError, match='All dataframe in candle data are None'):
calculate_trades_mdd({"BTC/BUSD" : None}, trades)
data = load_data(datadir=testdatadir, pairs=pairlist, timeframe='5m')
trades_mdd = calculate_trades_mdd(data, trades)
assert np.round(trades_mdd, 6) == 0.138943