diff --git a/freqtrade/data/metrics.py b/freqtrade/data/metrics.py index 738129939..45b9dbdea 100644 --- a/freqtrade/data/metrics.py +++ b/freqtrade/data/metrics.py @@ -30,8 +30,24 @@ def calculate_market_change(data: Dict[str, pd.DataFrame], column: str = "close" return float(np.mean(tmp_means)) -def combine_dataframes_with_mean(data: Dict[str, pd.DataFrame], - column: str = "close") -> pd.DataFrame: +def combine_dataframes_by_column( + data: Dict[str, pd.DataFrame], column: str = "close") -> pd.DataFrame: + """ + Combine multiple dataframes "column" + :param data: Dict of Dataframes, dict key should be pair. + :param column: Column in the original dataframes to use + :return: DataFrame with the column renamed to the dict key. + :raise: ValueError if no data is provided. + """ + if not data: + raise ValueError("No data provided.") + df_comb = pd.concat([data[pair].set_index('date').rename( + {column: pair}, axis=1)[pair] for pair in data], axis=1) + return df_comb + + +def combined_dataframes_with_rel_mean( + data: Dict[str, pd.DataFrame], column: str = "close") -> pd.DataFrame: """ Combine multiple dataframes "column" :param data: Dict of Dataframes, dict key should be pair. @@ -40,8 +56,24 @@ def combine_dataframes_with_mean(data: Dict[str, pd.DataFrame], named mean, containing the mean of all pairs. :raise: ValueError if no data is provided. """ - df_comb = pd.concat([data[pair].set_index('date').rename( - {column: pair}, axis=1)[pair] for pair in data], axis=1) + df_comb = combine_dataframes_by_column(data, column) + df_comb['count'] = df_comb.count(axis=1) + df_comb['mean'] = df_comb.mean(axis=1) + df_comb['rel_mean'] = df_comb['mean'].pct_change().fillna(0) + return df_comb[['mean', 'rel_mean', 'count']] + + +def combine_dataframes_with_mean( + data: Dict[str, pd.DataFrame], column: str = "close") -> pd.DataFrame: + """ + Combine multiple dataframes "column" + :param data: Dict of Dataframes, dict key should be pair. + :param column: Column in the original dataframes to use + :return: DataFrame with the column renamed to the dict key, and a column + named mean, containing the mean of all pairs. + :raise: ValueError if no data is provided. + """ + df_comb = combine_dataframes_by_column(data, column) df_comb['mean'] = df_comb.mean(axis=1) diff --git a/tests/data/test_btanalysis.py b/tests/data/test_btanalysis.py index 554ee261a..f465af1c7 100644 --- a/tests/data/test_btanalysis.py +++ b/tests/data/test_btanalysis.py @@ -16,7 +16,7 @@ from freqtrade.data.metrics import (calculate_cagr, calculate_calmar, calculate_ calculate_expectancy, calculate_market_change, calculate_max_drawdown, calculate_sharpe, calculate_sortino, calculate_underwater, combine_dataframes_with_mean, - create_cum_profit) + combined_dataframes_with_rel_mean, create_cum_profit) from freqtrade.exceptions import OperationalException from freqtrade.util import dt_utc from tests.conftest import CURRENT_TEST_STRATEGY, create_mock_trades @@ -251,10 +251,22 @@ def test_combine_dataframes_with_mean(testdatadir): assert "mean" in df.columns +def test_combined_dataframes_with_rel_mean(testdatadir): + pairs = ["ETH/BTC", "ADA/BTC"] + data = load_data(datadir=testdatadir, pairs=pairs, timeframe='5m') + df = combined_dataframes_with_rel_mean(data) + assert isinstance(df, DataFrame) + assert "ETH/BTC" not in df.columns + assert "ADA/BTC" not in df.columns + assert "mean" in df.columns + assert "rel_mean" in df.columns + assert "count" in df.columns + + def test_combine_dataframes_with_mean_no_data(testdatadir): pairs = ["ETH/BTC", "ADA/BTC"] data = load_data(datadir=testdatadir, pairs=pairs, timeframe='6m') - with pytest.raises(ValueError, match=r"No objects to concatenate"): + with pytest.raises(ValueError, match=r"No data provided\."): combine_dataframes_with_mean(data)