From 07bc0c3fce4b3ed6557e93b251025ce9e2119387 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 4 Jan 2021 13:47:16 +0100 Subject: [PATCH] Improve merge_informative_pairs to properly merge correct timeframes explanation in #4073, closes #4073 --- freqtrade/strategy/strategy_helper.py | 13 +++++++++++-- tests/strategy/test_strategy_helpers.py | 15 ++++++++++++--- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/freqtrade/strategy/strategy_helper.py b/freqtrade/strategy/strategy_helper.py index ea0e234ec..d7b1327d9 100644 --- a/freqtrade/strategy/strategy_helper.py +++ b/freqtrade/strategy/strategy_helper.py @@ -24,15 +24,24 @@ def merge_informative_pair(dataframe: pd.DataFrame, informative: pd.DataFrame, :param timeframe: Timeframe of the original pair sample. :param timeframe_inf: Timeframe of the informative pair sample. :param ffill: Forwardfill missing values - optional but usually required + :return: Merged dataframe + :raise: ValueError if the secondary timeframe is shorter than the dataframe timeframe """ minutes_inf = timeframe_to_minutes(timeframe_inf) minutes = timeframe_to_minutes(timeframe) - if minutes >= minutes_inf: + if minutes == minutes_inf: # No need to forwardshift if the timeframes are identical informative['date_merge'] = informative["date"] + elif minutes < minutes_inf: + # Subtract "small" timeframe so merging is not delayed by 1 small candle + # Detailed explanation in https://github.com/freqtrade/freqtrade/issues/4073 + informative['date_merge'] = ( + informative["date"] + pd.to_timedelta(minutes_inf, 'm') - pd.to_timedelta(minutes, 'm') + ) else: - informative['date_merge'] = informative["date"] + pd.to_timedelta(minutes_inf, 'm') + raise ValueError("Tried to merge a faster timeframe to a slower timeframe." + "This would create new rows, and can throw off your regular indicators.") # Rename columns to be unique informative.columns = [f"{col}_{timeframe_inf}" for col in informative.columns] diff --git a/tests/strategy/test_strategy_helpers.py b/tests/strategy/test_strategy_helpers.py index 1d3e80d24..252288e2e 100644 --- a/tests/strategy/test_strategy_helpers.py +++ b/tests/strategy/test_strategy_helpers.py @@ -1,5 +1,6 @@ import numpy as np import pandas as pd +import pytest from freqtrade.strategy import merge_informative_pair, timeframe_to_minutes @@ -47,17 +48,17 @@ def test_merge_informative_pair(): assert 'volume_1h' in result.columns assert result['volume'].equals(data['volume']) - # First 4 rows are empty + # First 3 rows are empty assert result.iloc[0]['date_1h'] is pd.NaT assert result.iloc[1]['date_1h'] is pd.NaT assert result.iloc[2]['date_1h'] is pd.NaT - assert result.iloc[3]['date_1h'] is pd.NaT # Next 4 rows contain the starting date (0:00) + assert result.iloc[3]['date_1h'] == result.iloc[0]['date'] assert result.iloc[4]['date_1h'] == result.iloc[0]['date'] assert result.iloc[5]['date_1h'] == result.iloc[0]['date'] assert result.iloc[6]['date_1h'] == result.iloc[0]['date'] - assert result.iloc[7]['date_1h'] == result.iloc[0]['date'] # Next 4 rows contain the next Hourly date original date row 4 + assert result.iloc[7]['date_1h'] == result.iloc[4]['date'] assert result.iloc[8]['date_1h'] == result.iloc[4]['date'] @@ -86,3 +87,11 @@ def test_merge_informative_pair_same(): # Dates match 1:1 assert result['date_15m'].equals(result['date']) + + +def test_merge_informative_pair_lower(): + data = generate_test_data('1h', 40) + informative = generate_test_data('15m', 40) + + with pytest.raises(ValueError, match=r"Tried to merge a faster timeframe .*"): + merge_informative_pair(data, informative, '1h', '15m', ffill=True)