Fix Ichimoku look-ahead bias: lag Senkou Spans by 26 bars

Senkou Span A and B are plotted 26 periods ahead of calculation.
Comparing current price to iloc[-1] cloud means comparing against the
cloud 26 bars in the future — a textbook look-ahead bias that inflates
signal grades in backtests. Now uses iloc[-(kijun+1)] so the cloud
boundaries reflect where the cloud actually is at the current candle.
TK cross (tenkan_val/kijun_val) stays at iloc[-1] — that is a current
condition, not a projected one.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Harwinder
2026-05-06 18:13:59 -04:00
parent ced4efa96d
commit 8df42cd384
+9 -3
View File
@@ -544,11 +544,17 @@ class TechnicalEngine:
tenkan_val = tenkan.iloc[-1]
kijun_val = kijun.iloc[-1]
# Current (unshifted) cloud
sa = (tenkan.iloc[-1] + kijun.iloc[-1]) / 2
# Senkou Spans are plotted 26 bars ahead of their calculation date, so
# the cloud boundaries at the *current* bar are the values computed 26
# bars ago. Using iloc[-1] would compare price to the future cloud
# (look-ahead bias). iloc[-27] gives the correctly lagged cloud.
lag = c.ichimoku_kijun # 26 by default
sb_raw = (high.rolling(c.ichimoku_senkou_b).max() +
low.rolling(c.ichimoku_senkou_b).min()) / 2
sb = sb_raw.iloc[-1]
if len(sb_raw) < lag + 1:
return
sa = (tenkan.iloc[-(lag + 1)] + kijun.iloc[-(lag + 1)]) / 2
sb = sb_raw.iloc[-(lag + 1)]
if pd.isna(sa) or pd.isna(sb) or pd.isna(tenkan_val) or pd.isna(kijun_val):
return