From 12adbeb7f3cbbfa68deff4e550a449b964e424a3 Mon Sep 17 00:00:00 2001 From: Joe Schr <8218910+TheJoeSchr@users.noreply.github.com> Date: Fri, 3 Jan 2025 18:23:36 +0100 Subject: [PATCH] fix: don't sort stacked imbalances, return empty list if no found... ... also removes helper functions `stacked_imbalance_bid` & `stacked_imbalance_ask` --- freqtrade/data/converter/orderflow.py | 37 +++++++---------------- tests/data/test_converter_orderflow.py | 41 +++++++++++++------------- 2 files changed, 31 insertions(+), 47 deletions(-) diff --git a/freqtrade/data/converter/orderflow.py b/freqtrade/data/converter/orderflow.py index 6d2df7d3d..2d0ada211 100644 --- a/freqtrade/data/converter/orderflow.py +++ b/freqtrade/data/converter/orderflow.py @@ -164,12 +164,12 @@ def populate_dataframe_with_trades( dataframe.at[index, "imbalances"] = imbalances.to_dict(orient="index") stacked_imbalance_range = config_orderflow["stacked_imbalance_range"] - dataframe.at[index, "stacked_imbalances_bid"] = stacked_imbalance_bid( - imbalances, stacked_imbalance_range=stacked_imbalance_range + dataframe.at[index, "stacked_imbalances_bid"] = stacked_imbalance( + imbalances, label="bid", stacked_imbalance_range=stacked_imbalance_range ) - dataframe.at[index, "stacked_imbalances_ask"] = stacked_imbalance_ask( - imbalances, stacked_imbalance_range=stacked_imbalance_range + dataframe.at[index, "stacked_imbalances_ask"] = stacked_imbalance( + imbalances, label="ask", stacked_imbalance_range=stacked_imbalance_range ) bid = np.where( @@ -256,9 +256,7 @@ def trades_orderflow_to_imbalances(df: pd.DataFrame, imbalance_ratio: int, imbal return dataframe -def stacked_imbalance( - df: pd.DataFrame, label: str, stacked_imbalance_range: int, should_reverse: bool -): +def stacked_imbalance(df: pd.DataFrame, label: str, stacked_imbalance_range: int): """ y * (y.groupby((y != y.shift()).cumsum()).cumcount() + 1) https://stackoverflow.com/questions/27626542/counting-consecutive-positive-values-in-python-pandas-array @@ -268,27 +266,14 @@ def stacked_imbalance( # Group consecutive True values and get their counts groups = (int_series != int_series.shift()).cumsum() counts = int_series.groupby(groups).cumsum() - + # Find indices where count meets or exceeds the range requirement valid_indices = counts[counts >= stacked_imbalance_range].index - + stacked_imbalance_prices = [] if not valid_indices.empty: # Get all prices from valid indices from beginning of the range - valid_prices = [imbalance.index.values[idx-(stacked_imbalance_range-1)] for idx in valid_indices] - # Sort prices according to direction - stacked_imbalance_prices = ( - sorted(valid_prices) - if not should_reverse - else sorted(valid_prices, reverse=True) - ) - - return stacked_imbalance_prices if stacked_imbalance_prices else [np.nan] - - -def stacked_imbalance_ask(df: pd.DataFrame, stacked_imbalance_range: int): - return stacked_imbalance(df, "ask", stacked_imbalance_range, should_reverse=True) - - -def stacked_imbalance_bid(df: pd.DataFrame, stacked_imbalance_range: int): - return stacked_imbalance(df, "bid", stacked_imbalance_range, should_reverse=False) + stacked_imbalance_prices = [ + imbalance.index.values[idx - (stacked_imbalance_range - 1)] for idx in valid_indices + ] + return stacked_imbalance_prices if stacked_imbalance_prices else [] diff --git a/tests/data/test_converter_orderflow.py b/tests/data/test_converter_orderflow.py index 792daea45..b097c93d9 100644 --- a/tests/data/test_converter_orderflow.py +++ b/tests/data/test_converter_orderflow.py @@ -5,9 +5,9 @@ from freqtrade.constants import DEFAULT_TRADES_COLUMNS from freqtrade.data.converter import populate_dataframe_with_trades from freqtrade.data.converter.orderflow import ( ORDERFLOW_ADDED_COLUMNS, + stacked_imbalance, timeframe_to_DateOffset, trades_to_volumeprofile_with_total_delta_bid_ask, - stacked_imbalance, ) from freqtrade.data.converter.trade_converter import trades_list_to_df from freqtrade.data.dataprovider import DataProvider @@ -185,8 +185,8 @@ def test_public_trades_mock_populate_dataframe_with_trades__check_orderflow( assert results["max_delta"] == 17.298 # Assert that stacked imbalances are NaN (not applicable in this test) - assert results["stacked_imbalances_bid"] == [np.nan] - assert results["stacked_imbalances_ask"] == [np.nan] + assert results["stacked_imbalances_bid"] == [] + assert results["stacked_imbalances_ask"] == [] # Repeat assertions for the third from last row results = df.iloc[-2] @@ -201,8 +201,8 @@ def test_public_trades_mock_populate_dataframe_with_trades__check_orderflow( assert pytest.approx(results["delta"]) == -49.302 assert results["min_delta"] == -70.222 assert pytest.approx(results["max_delta"]) == 11.213 - assert results["stacked_imbalances_bid"] == [np.nan] - assert results["stacked_imbalances_ask"] == [np.nan] + assert results["stacked_imbalances_bid"] == [] + assert results["stacked_imbalances_ask"] == [] def test_public_trades_trades_mock_populate_dataframe_with_trades__check_trades( @@ -575,34 +575,33 @@ def test_stacked_imbalances_multiple_prices(): # Test with empty result df_no_stacks = pd.DataFrame( { - 'bid_imbalance': [False, False, True, False], - 'ask_imbalance': [False, True, False, False] + "bid_imbalance": [False, False, True, False], + "ask_imbalance": [False, True, False, False], }, - index=[234.95, 234.96, 234.97, 234.98] + index=[234.95, 234.96, 234.97, 234.98], ) - no_stacks = stacked_imbalance(df_no_stacks, "bid", stacked_imbalance_range=2, should_reverse=False) - assert no_stacks == [np.nan] - + no_stacks = stacked_imbalance(df_no_stacks, "bid", stacked_imbalance_range=2) + assert no_stacks == [] + # Create a sample DataFrame with known imbalances df = pd.DataFrame( { - 'bid_imbalance': [True, True, True, False, False, True, True, False, True], - 'ask_imbalance': [False, False, True, True, True, False, False, True, True] + "bid_imbalance": [True, True, True, False, False, True, True, False, True], + "ask_imbalance": [False, False, True, True, True, False, False, True, True], }, - index=[234.95, 234.96, 234.97, 234.98, 234.99, 235.00, 235.01, 235.02, 235.03] + index=[234.95, 234.96, 234.97, 234.98, 234.99, 235.00, 235.01, 235.02, 235.03], ) # Test bid imbalances (should return prices in ascending order) - bid_prices = stacked_imbalance(df, "bid", stacked_imbalance_range=2, should_reverse=False) + bid_prices = stacked_imbalance(df, "bid", stacked_imbalance_range=2) assert bid_prices == [234.95, 234.96, 235.00] - + # Test ask imbalances (should return prices in descending order) - ask_prices = stacked_imbalance(df, "ask", stacked_imbalance_range=2, should_reverse=True) - assert ask_prices == [235.02, 234.98, 234.97] - + ask_prices = stacked_imbalance(df, "ask", stacked_imbalance_range=2) + assert ask_prices == [234.97, 234.98, 235.02] + # Test with higher stacked_imbalance_range - bid_prices_higher = stacked_imbalance(df, "bid", stacked_imbalance_range=3, should_reverse=False) + bid_prices_higher = stacked_imbalance(df, "bid", stacked_imbalance_range=3) assert bid_prices_higher == [234.95] - def test_timeframe_to_DateOffset():