Ichimoku Cloud
A multi-component system that packages trend direction, support/ resistance, and momentum into one indicator set — more involved than anything so far, but each component is simple.
def ichimoku(df: pd.DataFrame, tenkan_period=9, kijun_period=26, senkou_b_period=52, displacement=26) -> pd.DataFrame:
def midpoint(period):
return (df["high"].rolling(period).max() + df["low"].rolling(period).min()) / 2
tenkan_sen = midpoint(tenkan_period) # conversion line — fast
kijun_sen = midpoint(kijun_period) # base line — slow
senkou_span_a = ((tenkan_sen + kijun_sen) / 2).shift(displacement) # leading span A
senkou_span_b = midpoint(senkou_b_period).shift(displacement) # leading span B
chikou_span = df["close"].shift(-displacement) # lagging span
return pd.DataFrame({
"tenkan_sen": tenkan_sen, "kijun_sen": kijun_sen,
"senkou_span_a": senkou_span_a, "senkou_span_b": senkou_span_b,
"chikou_span": chikou_span,
}, index=df.index)
The five lines, in plain terms
- Tenkan-sen (conversion line) — fast average, similar role to a short EMA.
- Kijun-sen (base line) — slower average, similar role to a medium EMA; also commonly used as a standalone support/resistance/trailing stop level.
- Senkou Span A/B — plotted
displacementbars *forward*, forming the "cloud" (Kumo) — the gap between them is the cloud itself. - Chikou Span — current close plotted
displacementbars *backward*, used to check for confirmation against price action from that many bars ago.
Standard signals
def ichimoku_signal(df: pd.DataFrame, ichi: pd.DataFrame) -> pd.Series:
signal = pd.Series(0, index=df.index)
price_above_cloud = df["close"] > ichi[["senkou_span_a", "senkou_span_b"]].max(axis=1)
price_below_cloud = df["close"] < ichi[["senkou_span_a", "senkou_span_b"]].min(axis=1)
tk_bullish = ichi["tenkan_sen"] > ichi["kijun_sen"]
signal[price_above_cloud & tk_bullish] = 1
signal[price_below_cloud & ~tk_bullish] = -1
return signal
This requiring both "price above/below cloud" AND "Tenkan/Kijun cross agreeing" is itself confluence logic (chapter 115) — Ichimoku is really a bundle of pre-designed confluence rules rather than one raw indicator value.
Why the forward/backward shifts matter for backtesting correctness
senkou_span_a/b are plotted displacement bars into the *future* relative to the data that computed them — meaning at the current bar, the cloud you visually see extending ahead of price was computed from data available displacement bars ago, not future information (not a look-ahead violation, chapter 83) — but a careless backtest implementation that misaligns the shift direction can accidentally introduce one. Always verify: does the value at index i in your computed cloud series depend only on data at or before index i - displacement? If yes, it's safe; if the shift direction is flipped, it silently leaks future data.
Practical note
Ichimoku's default periods (9, 26, 52) were designed for the historical Japanese trading week structure — some practitioners adjust these for 5-day-week markets like NSE, others use the defaults unchanged. Validate via backtesting (chapter 82) rather than assuming either choice is automatically correct for Indian markets.