pep8
This commit is contained in:
parent
d08b0918ad
commit
44843910c6
@ -390,8 +390,9 @@ 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
|
# 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) :
|
||||||
Give the max drawdown given each trades and the history candles.
|
Give the max drawdown given each trades and the history candles.
|
||||||
@ -399,7 +400,6 @@ def calculate_trades_mdd(data: dict, trades: pd.DataFrame) -> float :
|
|||||||
Args:
|
Args:
|
||||||
:param data: (dict) dictionnary of candle dataframe per pair used to calculate the mdd.
|
:param data: (dict) dictionnary of candle dataframe per pair used to calculate the mdd.
|
||||||
:param trades: (pd.DataFrame) trades used to find the intervals dates.
|
:param trades: (pd.DataFrame) trades used to find the intervals dates.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
:return: (float) Give the maximum drawdown among each trades.
|
:return: (float) Give the maximum drawdown among each trades.
|
||||||
:raise: (ValueError) if trade-dataframe was found empty.
|
:raise: (ValueError) if trade-dataframe was found empty.
|
||||||
@ -407,20 +407,18 @@ def calculate_trades_mdd(data: dict, trades: pd.DataFrame) -> float :
|
|||||||
"""
|
"""
|
||||||
if len(trades) == 0:
|
if len(trades) == 0:
|
||||||
raise ValueError("Trade dataframe empty")
|
raise ValueError("Trade dataframe empty")
|
||||||
|
|
||||||
trades_mdd_pair_list = []
|
trades_mdd_pair_list = []
|
||||||
|
for pair, df in data.items():
|
||||||
for pair, df in data.items():
|
|
||||||
if isinstance(df, pd.DataFrame):
|
if isinstance(df, pd.DataFrame):
|
||||||
# Gather the opening and closing trade dates into one Dates DataFrame
|
# 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 = trades.loc[trades['pair'] == pair][["open_date", "close_date"]]
|
||||||
open_close_trades = pd.concat(
|
open_close_trades = pd.concat(
|
||||||
[open_close_trades.rename(columns={'open_date':'date'})[['date']],
|
[open_close_trades.rename(columns={'open_date': 'date'})[['date']],
|
||||||
open_close_trades.rename(columns={'close_date':'date'})[['date']]]
|
open_close_trades.rename(columns={'close_date': 'date'})[['date']]]
|
||||||
).sort_values(by='date')
|
).sort_values(by='date')
|
||||||
|
|
||||||
# Mark the dates and join it to the current candle dataframe.
|
# Mark the dates and join it to the current candle dataframe.
|
||||||
# This allow to determine the open and close trade dates in the current
|
# This allow to determine the open and close trade dates in the current
|
||||||
# candle dataframe.
|
# candle dataframe.
|
||||||
open_close_trades['open_close_mark'] = 1
|
open_close_trades['open_close_mark'] = 1
|
||||||
data_join = df.set_index('date').join(open_close_trades.set_index('date'))
|
data_join = df.set_index('date').join(open_close_trades.set_index('date'))
|
||||||
@ -428,22 +426,22 @@ def calculate_trades_mdd(data: dict, trades: pd.DataFrame) -> float :
|
|||||||
|
|
||||||
# Gather, mark and join only the opening trade dates into the current candle
|
# Gather, mark and join only the opening trade dates into the current candle
|
||||||
# dataframe.
|
# dataframe.
|
||||||
# This allow to classify trades using the cumsum and split by classes
|
# This allow to classify trades using the cumsum and split by classes
|
||||||
# with groupby in order to process a cummax on each trades independantly.
|
# with groupby in order to process a cummax on each trades independantly.
|
||||||
open_trades = trades.loc[trades['pair']==pair][["open_date"]]
|
open_trades = trades.loc[trades['pair'] == pair][["open_date"]]
|
||||||
open_trades = open_trades.rename(columns={'open_date':'date'})
|
open_trades = open_trades.rename(columns={'open_date': 'date'})
|
||||||
open_trades['open_mark'] = 1
|
open_trades['open_mark'] = 1
|
||||||
data_join = data_join.join(open_trades.set_index('date'))
|
data_join = data_join.join(open_trades.set_index('date'))
|
||||||
del open_trades
|
del open_trades
|
||||||
|
|
||||||
# Set all unmarked date to 0
|
# Set all unmarked date to 0
|
||||||
data_join[["open_close_mark",'open_mark']] = data_join[
|
data_join[["open_close_mark", 'open_mark']] = data_join[
|
||||||
["open_close_mark",'open_mark']].fillna(0).astype(int)
|
["open_close_mark", 'open_mark']].fillna(0).astype(int)
|
||||||
|
|
||||||
# Mark with one all dates between an opening date trades and a closing date trades.
|
# Mark with one all dates between an opening date trades and a closing date trades.
|
||||||
data_join['is_in_trade'] = data_join.open_close_mark.cumsum()&1 # &1 <=> %2
|
data_join['is_in_trade'] = data_join.open_close_mark.cumsum() & 1 # &1 <=> %2
|
||||||
data_join.loc[data_join['open_close_mark'] == 1, 'is_in_trade'] = 1
|
data_join.loc[data_join['open_close_mark'] == 1, 'is_in_trade'] = 1
|
||||||
|
|
||||||
# Perform a cummax in each trades independtly
|
# Perform a cummax in each trades independtly
|
||||||
data_join['close_cummax'] = 0
|
data_join['close_cummax'] = 0
|
||||||
data_join['close_cummax'] = data_join.groupby(
|
data_join['close_cummax'] = data_join.groupby(
|
||||||
@ -452,20 +450,21 @@ def calculate_trades_mdd(data: dict, trades: pd.DataFrame) -> float :
|
|||||||
data_join.loc[data_join['is_in_trade'] == 0, 'close_cummax'] = 0
|
data_join.loc[data_join['is_in_trade'] == 0, 'close_cummax'] = 0
|
||||||
|
|
||||||
# Compute the drawdown at each time of each trades
|
# Compute the drawdown at each time of each trades
|
||||||
data_join = data_join.rename(columns={'open_mark':'drawdown'})
|
data_join = data_join.rename(columns={'open_mark': 'drawdown'})
|
||||||
data_join.loc[data_join['is_in_trade'] == 1, 'drawdown'] = \
|
data_join.loc[data_join['is_in_trade'] == 1, 'drawdown'] = ((
|
||||||
(data_join['close_cummax'] - data_join['close']) \
|
data_join['close_cummax'] - data_join['close'])
|
||||||
/ data_join['close_cummax']
|
/ data_join['close_cummax'])
|
||||||
|
|
||||||
mdd_pair = data_join['drawdown'].max()
|
mdd_pair = data_join['drawdown'].max()
|
||||||
trades_mdd_pair_list.append(mdd_pair)
|
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")
|
||||||
|
|
||||||
trades_mdd_pair_list = np.array(trades_mdd_pair_list)
|
trades_mdd_pair_list = np.array(trades_mdd_pair_list)
|
||||||
return trades_mdd_pair_list.max()
|
return trades_mdd_pair_list.max()
|
||||||
|
|
||||||
|
|
||||||
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]:
|
||||||
"""
|
"""
|
||||||
Calculate min/max cumsum of trades, to show if the wallet/stake amount ratio is sane
|
Calculate min/max cumsum of trades, to show if the wallet/stake amount ratio is sane
|
||||||
|
@ -468,7 +468,7 @@ def generate_strategy_stats(btdata: Dict[str, DataFrame],
|
|||||||
drawdown_abs, drawdown_start, drawdown_end, high_val, low_val = calculate_max_drawdown(
|
drawdown_abs, drawdown_start, drawdown_end, high_val, low_val = calculate_max_drawdown(
|
||||||
results, value_col='profit_abs')
|
results, value_col='profit_abs')
|
||||||
strat_stats.update({
|
strat_stats.update({
|
||||||
'trades_mdd' : trades_mdd,
|
'trades_mdd': trades_mdd,
|
||||||
'max_drawdown': max_drawdown,
|
'max_drawdown': max_drawdown,
|
||||||
'max_drawdown_abs': drawdown_abs,
|
'max_drawdown_abs': drawdown_abs,
|
||||||
'drawdown_start': drawdown_start.strftime(DATETIME_PRINT_FORMAT),
|
'drawdown_start': drawdown_start.strftime(DATETIME_PRINT_FORMAT),
|
||||||
@ -718,11 +718,11 @@ def text_table_add_metrics(strat_results: Dict) -> str:
|
|||||||
strat_results['stake_currency'])),
|
strat_results['stake_currency'])),
|
||||||
('Max balance', round_coin_value(strat_results['csum_max'],
|
('Max balance', round_coin_value(strat_results['csum_max'],
|
||||||
strat_results['stake_currency'])),
|
strat_results['stake_currency'])),
|
||||||
('', ''), # Empty line to improve readability
|
('', ''), # Empty line to improve readability
|
||||||
('Max Drawdown (in trades)', f"{strat_results['trades_mdd']:.2%}"),
|
('Max Drawdown (in trades)', f"{strat_results['trades_mdd']:.2%}"),
|
||||||
('Max Drawdown Total', f"{strat_results['max_drawdown']:.2%}"),
|
('Max Drawdown Total', f"{strat_results['max_drawdown']:.2%}"),
|
||||||
('Max Drawdown Total', round_coin_value(strat_results['max_drawdown_abs'],
|
('Max Drawdown Total', round_coin_value(strat_results['max_drawdown_abs'],
|
||||||
strat_results['stake_currency'])),
|
strat_results['stake_currency'])),
|
||||||
('Drawdown high', round_coin_value(strat_results['max_drawdown_high'],
|
('Drawdown high', round_coin_value(strat_results['max_drawdown_high'],
|
||||||
strat_results['stake_currency'])),
|
strat_results['stake_currency'])),
|
||||||
('Drawdown low', round_coin_value(strat_results['max_drawdown_low'],
|
('Drawdown low', round_coin_value(strat_results['max_drawdown_low'],
|
||||||
|
@ -10,7 +10,8 @@ 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_trades_mdd,
|
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,
|
||||||
@ -333,14 +334,15 @@ def test_calculate_max_drawdown2():
|
|||||||
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):
|
def test_calculate_trades_mdd(testdatadir):
|
||||||
backtest_file = testdatadir / "backtest-result_test.json"
|
backtest_file = testdatadir / "backtest-result_test.json"
|
||||||
trades = load_backtest_data(backtest_file)
|
trades = load_backtest_data(backtest_file)
|
||||||
pairlist = set(trades["pair"])
|
pairlist = set(trades["pair"])
|
||||||
|
|
||||||
with pytest.raises(ValueError, match='All dataframe in candle data are None'):
|
with pytest.raises(ValueError, match='All dataframe in candle data are None'):
|
||||||
calculate_trades_mdd({"BTC/BUSD" : None}, trades)
|
calculate_trades_mdd({"BTC/BUSD": None}, trades)
|
||||||
|
|
||||||
data = load_data(datadir=testdatadir, pairs=pairlist, timeframe='5m')
|
data = load_data(datadir=testdatadir, pairs=pairlist, timeframe='5m')
|
||||||
trades_mdd = calculate_trades_mdd(data, trades)
|
trades_mdd = calculate_trades_mdd(data, trades)
|
||||||
assert np.round(trades_mdd, 6) == 0.138943
|
assert np.round(trades_mdd, 6) == 0.138943
|
||||||
|
Loading…
Reference in New Issue
Block a user