Correctly handle identical timerame merges

This commit is contained in:
Matthias 2020-09-04 20:09:02 +02:00
parent 7bc8927914
commit cc684c5141
3 changed files with 40 additions and 7 deletions

View File

@ -518,10 +518,10 @@ class SampleStrategy(IStrategy):
# Use the helper function merge_informative_pair to safely merge the pair # Use the helper function merge_informative_pair to safely merge the pair
# Automatically renames the columns and merges a shorter timeframe dataframe and a longer timeframe informative pair # Automatically renames the columns and merges a shorter timeframe dataframe and a longer timeframe informative pair
# FFill to have the 1d value available in every row throughout the day. # use ffill to have the 1d value available in every row throughout the day.
# Without this, comparisons would only work once per day. # Without this, comparisons between columns of the original and the informative pair would only work once per day.
# Full documentation of this method, see below # Full documentation of this method, see below
dataframe = merge_informative_pair(dataframe, informative_pairs, inf_tf, ffill=True) dataframe = merge_informative_pair(dataframe, informative_pairs, self.timeframe, inf_tf, ffill=True)
# Calculate rsi of the original dataframe (5m timeframe) # Calculate rsi of the original dataframe (5m timeframe)
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14) dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
@ -589,6 +589,7 @@ All columns of the informative dataframe will be available on the returning data
# This is necessary since the data is always the "open date" # This is necessary since the data is always the "open date"
# and a 15m candle starting at 12:15 should not know the close of the 1h candle from 12:00 to 13:00 # and a 15m candle starting at 12:15 should not know the close of the 1h candle from 12:00 to 13:00
minutes = timeframe_to_minutes(inf_tf) minutes = timeframe_to_minutes(inf_tf)
# Only do this if the timeframes are different:
informative['date_merge'] = informative["date"] + pd.to_timedelta(minutes, 'm') informative['date_merge'] = informative["date"] + pd.to_timedelta(minutes, 'm')
# Combine the 2 dataframes # Combine the 2 dataframes

View File

@ -3,7 +3,7 @@ from freqtrade.exchange import timeframe_to_minutes
def merge_informative_pair(dataframe: pd.DataFrame, informative: pd.DataFrame, def merge_informative_pair(dataframe: pd.DataFrame, informative: pd.DataFrame,
timeframe_inf: str, ffill: bool = True) -> pd.DataFrame: timeframe: str, timeframe_inf: str, ffill: bool = True) -> pd.DataFrame:
""" """
Correctly merge informative samples to the original dataframe, avoiding lookahead bias. Correctly merge informative samples to the original dataframe, avoiding lookahead bias.
@ -20,13 +20,18 @@ def merge_informative_pair(dataframe: pd.DataFrame, informative: pd.DataFrame,
:param dataframe: Original dataframe :param dataframe: Original dataframe
:param informative: Informative pair, most likely loaded via dp.get_pair_dataframe :param informative: Informative pair, most likely loaded via dp.get_pair_dataframe
:param timeframe: Timeframe of the original pair sample.
:param timeframe_inf: Timeframe of the informative pair sample. :param timeframe_inf: Timeframe of the informative pair sample.
:param ffill: Forwardfill missing values - optional but usually required :param ffill: Forwardfill missing values - optional but usually required
""" """
# Rename columns to be unique # Rename columns to be unique
minutes = timeframe_to_minutes(timeframe_inf) minutes_inf = timeframe_to_minutes(timeframe_inf)
informative['date_merge'] = informative["date"] + pd.to_timedelta(minutes, 'm') if timeframe == timeframe_inf:
# No need to forwardshift if the timeframes are identical
informative['date_merge'] = informative["date"]
else:
informative['date_merge'] = informative["date"] + pd.to_timedelta(minutes_inf, 'm')
informative.columns = [f"{col}_{timeframe_inf}" for col in informative.columns] informative.columns = [f"{col}_{timeframe_inf}" for col in informative.columns]

View File

@ -28,7 +28,7 @@ def test_merge_informative_pair():
data = generate_test_data('15m', 40) data = generate_test_data('15m', 40)
informative = generate_test_data('1h', 40) informative = generate_test_data('1h', 40)
result = merge_informative_pair(data, informative, '1h', ffill=True) result = merge_informative_pair(data, informative, '15m', '1h', ffill=True)
assert isinstance(result, pd.DataFrame) assert isinstance(result, pd.DataFrame)
assert len(result) == len(data) assert len(result) == len(data)
assert 'date' in result.columns assert 'date' in result.columns
@ -59,3 +59,30 @@ def test_merge_informative_pair():
assert result.iloc[7]['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 # Next 4 rows contain the next Hourly date original date row 4
assert result.iloc[8]['date_1h'] == result.iloc[4]['date'] assert result.iloc[8]['date_1h'] == result.iloc[4]['date']
def test_merge_informative_pair_same():
data = generate_test_data('15m', 40)
informative = generate_test_data('15m', 40)
result = merge_informative_pair(data, informative, '15m', '15m', ffill=True)
assert isinstance(result, pd.DataFrame)
assert len(result) == len(data)
assert 'date' in result.columns
assert result['date'].equals(data['date'])
assert 'date_15m' in result.columns
assert 'open' in result.columns
assert 'open_15m' in result.columns
assert result['open'].equals(data['open'])
assert 'close' in result.columns
assert 'close_15m' in result.columns
assert result['close'].equals(data['close'])
assert 'volume' in result.columns
assert 'volume_15m' in result.columns
assert result['volume'].equals(data['volume'])
# Dates match 1:1
assert result['date_15m'].equals(result['date'])