Skip to content

Commit ea0c51c

Browse files
authored
Merge pull request freqtrade#12201 from mihalt/fix_merge_informative_pair
Fix the truncation of values by merge_ordered in merge_informative_pair
2 parents 2649ba0 + a9447e7 commit ea0c51c

File tree

2 files changed

+42
-2
lines changed

2 files changed

+42
-2
lines changed

freqtrade/strategy/strategy_helper.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,21 @@ def merge_informative_pair(
9292
right_on=date_merge,
9393
how="left",
9494
)
95+
96+
if len(dataframe) > 1 and len(informative) > 0 and pd.isnull(dataframe.at[0, date_merge]):
97+
# If the start dates of the dataframes are not aligned, the first rows will be NaN
98+
# We can fill these with the last available informative candle before the start date
99+
# while still avoiding lookahead bias - as only past data is used.
100+
first_valid_idx = dataframe[date_merge].first_valid_index()
101+
if first_valid_idx:
102+
first_valid_date_merge = dataframe.at[first_valid_idx, date_merge]
103+
matching_informative_raws = informative[
104+
informative[date_merge] < first_valid_date_merge
105+
]
106+
if not matching_informative_raws.empty:
107+
dataframe.loc[: first_valid_idx - 1] = dataframe.loc[
108+
: first_valid_idx - 1
109+
].fillna(matching_informative_raws.iloc[-1])
95110
else:
96111
dataframe = pd.merge(
97112
dataframe, informative, left_on="date", right_on=date_merge, how="left"

tests/strategy/test_strategy_helpers.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ def test_merge_informative_pair():
3434
assert "volume_1h" in result.columns
3535
assert result["volume"].equals(data["volume"])
3636

37-
# First 3 rows are empty
37+
# First 3 rows are empty.
38+
# Pre-fillup doesn't happen as there is no prior candlw in the informative dataframe
3839
assert result.iloc[0]["date_1h"] is pd.NaT
3940
assert result.iloc[1]["date_1h"] is pd.NaT
4041
assert result.iloc[2]["date_1h"] is pd.NaT
@@ -109,13 +110,37 @@ def test_merge_informative_pair_monthly():
109110
# Candle is empty, as the start-date did fail.
110111
candle3 = result.loc[(result["date"] == "2022-11-30T22:00:00.000Z")]
111112
assert candle3.iloc[0]["date"] == pd.Timestamp("2022-11-30T22:00:00.000Z")
112-
assert candle3.iloc[0]["date_1M"] is pd.NaT
113+
# Merged on prior month
114+
assert candle3.iloc[0]["date_1M"] == pd.Timestamp("2022-10-01T00:00:00.000Z")
113115

114116
# First candle with 1M data merged.
115117
candle4 = result.loc[(result["date"] == "2022-11-30T23:00:00.000Z")]
116118
assert candle4.iloc[0]["date"] == pd.Timestamp("2022-11-30T23:00:00.000Z")
117119
assert candle4.iloc[0]["date_1M"] == pd.Timestamp("2022-11-01T00:00:00.000Z")
118120

121+
# Very first candle in the result dataframe
122+
# Merged the latest informative candle before the start-date
123+
candle5 = result.iloc[0]
124+
assert candle5["date"] == pd.Timestamp("2022-11-28T00:00:00.000Z")
125+
assert candle5["date_1M"] == pd.Timestamp("2022-10-01T00:00:00.000Z")
126+
127+
128+
def test_merge_informative_pair_no_overlap():
129+
# Covers roughly a day
130+
data = generate_test_data("1m", 1440, "2022-11-28")
131+
# Data stops WAY before the main data starts
132+
informative = generate_test_data("1h", 40, "2022-11-01")
133+
134+
result = merge_informative_pair(data, informative, "1m", "1h", ffill=True)
135+
136+
assert isinstance(result, pd.DataFrame)
137+
assert len(result) == len(data)
138+
assert "date" in result.columns
139+
assert result["date"].equals(data["date"])
140+
assert "date_1h" in result.columns
141+
# If there's no overlap, forward filling should not fill anything
142+
assert result["date_1h"].isnull().all()
143+
119144

120145
def test_merge_informative_pair_same():
121146
data = generate_test_data("15m", 40)

0 commit comments

Comments
 (0)