From 44843910c64c042d9a2a1b6177580befe5c96a93 Mon Sep 17 00:00:00 2001 From: Guitheg Date: Mon, 13 Dec 2021 11:03:32 +0100 Subject: [PATCH] pep8 --- freqtrade/data/btanalysis.py | 43 +++++++++++++------------- freqtrade/optimize/optimize_reports.py | 6 ++-- tests/data/test_btanalysis.py | 14 +++++---- 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index bb2fd4591..83aac8455 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -390,8 +390,9 @@ def calculate_max_drawdown(trades: pd.DataFrame, *, date_col: str = 'close_date' low_val = max_drawdown_df.loc[idxmin, 'cumulative'] 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) : 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: :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. - Returns: :return: (float) Give the maximum drawdown among each trades. :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: raise ValueError("Trade dataframe empty") - trades_mdd_pair_list = [] - - for pair, df in data.items(): + for pair, df in data.items(): if isinstance(df, pd.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.rename(columns={'open_date':'date'})[['date']], - open_close_trades.rename(columns={'close_date':'date'})[['date']]] + [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 + # 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')) @@ -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 # 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. - open_trades = trades.loc[trades['pair']==pair][["open_date"]] - open_trades = open_trades.rename(columns={'open_date':'date'}) + 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 - data_join[["open_close_mark",'open_mark']] = data_join[ - ["open_close_mark",'open_mark']].fillna(0).astype(int) + data_join[["open_close_mark", 'open_mark']] = data_join[ + ["open_close_mark", 'open_mark']].fillna(0).astype(int) # 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 - + # Perform a cummax in each trades independtly data_join['close_cummax'] = 0 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 # Compute the drawdown at each time of each trades - data_join = data_join.rename(columns={'open_mark':'drawdown'}) - data_join.loc[data_join['is_in_trade'] == 1, 'drawdown'] = \ - (data_join['close_cummax'] - data_join['close']) \ - / data_join['close_cummax'] + data_join = data_join.rename(columns={'open_mark': 'drawdown'}) + 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 == []: raise ValueError("All dataframe in candle data are None") trades_mdd_pair_list = np.array(trades_mdd_pair_list) return trades_mdd_pair_list.max() + 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 diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index d920c035c..9f5c6ce3a 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -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( results, value_col='profit_abs') strat_stats.update({ - 'trades_mdd' : trades_mdd, + 'trades_mdd': trades_mdd, 'max_drawdown': max_drawdown, 'max_drawdown_abs': drawdown_abs, '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'])), ('Max balance', round_coin_value(strat_results['csum_max'], 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 Total', f"{strat_results['max_drawdown']:.2%}"), ('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'], strat_results['stake_currency'])), ('Drawdown low', round_coin_value(strat_results['max_drawdown_low'], diff --git a/tests/data/test_btanalysis.py b/tests/data/test_btanalysis.py index 384a71e7d..3d4a5b166 100644 --- a/tests/data/test_btanalysis.py +++ b/tests/data/test_btanalysis.py @@ -10,7 +10,8 @@ from freqtrade.configuration import TimeRange from freqtrade.constants import LAST_BT_RESULT_FN from freqtrade.data.btanalysis import (BT_DATA_COLUMNS, BT_DATA_COLUMNS_MID, BT_DATA_COLUMNS_OLD, 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, extract_trades_of_period, get_latest_backtest_filename, 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.'): 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) + 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) - + 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 \ No newline at end of file + assert np.round(trades_mdd, 6) == 0.138943