From e8376d5b7991779f625744f816ad3b461028ebf1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 6 Dec 2024 20:42:04 +0100 Subject: [PATCH 1/3] feat: add timeframe_to_DateOffset --- freqtrade/data/converter/orderflow.py | 27 ++++++++++++++++++++++++++ tests/data/test_converter_orderflow.py | 12 ++++++++++++ 2 files changed, 39 insertions(+) diff --git a/freqtrade/data/converter/orderflow.py b/freqtrade/data/converter/orderflow.py index 50b298c75..d1e9c0f64 100644 --- a/freqtrade/data/converter/orderflow.py +++ b/freqtrade/data/converter/orderflow.py @@ -50,6 +50,33 @@ def _init_dataframe_with_trades_columns(dataframe: pd.DataFrame): dataframe[column] = dataframe[column].astype(object) +def timeframe_to_DateOffset(timeframe: str) -> pd.DateOffset: + """ + Translates the timeframe interval value written in the human readable + form ('1m', '5m', '1h', '1d', '1w', etc.) to the number + of seconds for one timeframe interval. + """ + from freqtrade.exchange import ( + timeframe_to_seconds, + ) + + timeframe_seconds = timeframe_to_seconds(timeframe) + timeframe_minutes = timeframe_seconds // 60 + if timeframe_minutes < 1: + return pd.DateOffset(seconds=timeframe_seconds) + elif 59 < timeframe_minutes < 1440: + return pd.DateOffset(hours=timeframe_minutes // 60) + elif 1440 <= timeframe_minutes < 10080: + return pd.DateOffset(days=timeframe_minutes // 1440) + elif 10000 < timeframe_minutes < 43200: + return pd.DateOffset(weeks=1) + elif timeframe_minutes >= 43200 and timeframe_minutes < 525600: + return pd.DateOffset(months=1) + elif timeframe == "1y": + return pd.DateOffset(years=1) + else: + return pd.DateOffset(minutes=timeframe_minutes) + def _calculate_ohlcv_candle_start_and_end(df: pd.DataFrame, timeframe: str): from freqtrade.exchange import timeframe_to_next_date, timeframe_to_resample_freq diff --git a/tests/data/test_converter_orderflow.py b/tests/data/test_converter_orderflow.py index 96f550020..656c1eab3 100644 --- a/tests/data/test_converter_orderflow.py +++ b/tests/data/test_converter_orderflow.py @@ -6,6 +6,7 @@ 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, + timeframe_to_DateOffset, trades_to_volumeprofile_with_total_delta_bid_ask, ) from freqtrade.data.converter.trade_converter import trades_list_to_df @@ -564,3 +565,14 @@ def test_analyze_with_orderflow( lastval_of2 = df2.at[len(df2) - 1, "orderflow"] assert isinstance(lastval_of2, dict) + + +def test_timeframe_to_DateOffset(): + assert timeframe_to_DateOffset("1s") == pd.DateOffset(seconds=1) + assert timeframe_to_DateOffset("1m") == pd.DateOffset(minutes=1) + assert timeframe_to_DateOffset("5m") == pd.DateOffset(minutes=5) + assert timeframe_to_DateOffset("1h") == pd.DateOffset(hours=1) + assert timeframe_to_DateOffset("1d") == pd.DateOffset(days=1) + assert timeframe_to_DateOffset("1w") == pd.DateOffset(weeks=1) + assert timeframe_to_DateOffset("1M") == pd.DateOffset(months=1) + assert timeframe_to_DateOffset("1y") == pd.DateOffset(years=1) From 9129266f54de5315a1673a9cb82775addb2e939b Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 13 Dec 2024 14:28:26 +0100 Subject: [PATCH 2/3] feat: greatly improve performance of orderflow by not using apply --- freqtrade/data/converter/orderflow.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/freqtrade/data/converter/orderflow.py b/freqtrade/data/converter/orderflow.py index d1e9c0f64..8f753a668 100644 --- a/freqtrade/data/converter/orderflow.py +++ b/freqtrade/data/converter/orderflow.py @@ -77,18 +77,20 @@ def timeframe_to_DateOffset(timeframe: str) -> pd.DateOffset: else: return pd.DateOffset(minutes=timeframe_minutes) -def _calculate_ohlcv_candle_start_and_end(df: pd.DataFrame, timeframe: str): - from freqtrade.exchange import timeframe_to_next_date, timeframe_to_resample_freq - timeframe_frequency = timeframe_to_resample_freq(timeframe) - # calculate ohlcv candle start and end +def _calculate_ohlcv_candle_start_and_end(df: pd.DataFrame, timeframe: str): + from freqtrade.exchange import ( + timeframe_to_resample_freq, + ) + if df is not None and not df.empty: + timeframe_frequency = timeframe_to_resample_freq(timeframe) + dofs = timeframe_to_DateOffset(timeframe) + # calculate ohlcv candle start and end df["datetime"] = pd.to_datetime(df["date"], unit="ms") df["candle_start"] = df["datetime"].dt.floor(timeframe_frequency) # used in _now_is_time_to_refresh_trades - df["candle_end"] = df["candle_start"].apply( - lambda candle_start: timeframe_to_next_date(timeframe, candle_start) - ) + df["candle_end"] = df["candle_start"] + dofs df.drop(columns=["datetime"], inplace=True) From 016cabb7b2d4d4392637f041a0353912bbbff4f4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 13 Dec 2024 14:59:35 +0100 Subject: [PATCH 3/3] chore: simplify imports --- freqtrade/data/converter/orderflow.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/freqtrade/data/converter/orderflow.py b/freqtrade/data/converter/orderflow.py index 8f753a668..a51394ce9 100644 --- a/freqtrade/data/converter/orderflow.py +++ b/freqtrade/data/converter/orderflow.py @@ -56,9 +56,7 @@ def timeframe_to_DateOffset(timeframe: str) -> pd.DateOffset: form ('1m', '5m', '1h', '1d', '1w', etc.) to the number of seconds for one timeframe interval. """ - from freqtrade.exchange import ( - timeframe_to_seconds, - ) + from freqtrade.exchange import timeframe_to_seconds timeframe_seconds = timeframe_to_seconds(timeframe) timeframe_minutes = timeframe_seconds // 60 @@ -79,9 +77,7 @@ def timeframe_to_DateOffset(timeframe: str) -> pd.DateOffset: def _calculate_ohlcv_candle_start_and_end(df: pd.DataFrame, timeframe: str): - from freqtrade.exchange import ( - timeframe_to_resample_freq, - ) + from freqtrade.exchange import timeframe_to_resample_freq if df is not None and not df.empty: timeframe_frequency = timeframe_to_resample_freq(timeframe)