Smart Ichimoku

Category: Indicators By: Iván González Created: July 21, 2026, 11:27 AM
July 21, 2026, 11:27 AM
Indicators
0 Comments

1. Introduction

A classic Ichimoku cloud is built from the midpoints of highs and lows over fixed windows. It works, but it produces a blocky, laggy envelope, and – more to the point – it treats every cloud break the same way. Price pokes above the cloud, you get a signal, and a good share of those signals are noise.

This indicator, adapted to ProBuilder from the “Smart Ichimoku | GainzAlgo” pinescript, changes two things. First, it rebuilds the whole cloud with Hull moving averages instead of the classic max/min midpoints, which gives a smoother and more responsive envelope. Second, and this is the real idea, it does not accept every cloud break at face value: each break is scored by a small classifier that weighs four momentum and volatility features, and only the breaks whose probability clears a threshold are marked.

On top of that, every fresh break projects a three-level target plan (Conservative / Standard / Aggressive) derived from the recent distribution of price moves, and a quality badge rates how convincing the setup is.

 

2. How It Works

The smoothed cloud. All four Ichimoku lines are Hull moving averages (average[n, 7] in ProBuilder) over the median price hl2:

  • Tenkan = HMA(hl2, 9)
  • Kijun = HMA(hl2, 26)
  • Senkou A = HMA((Tenkan + Kijun) / 2, 26)
  • Senkou B = HMA(hl2, 52)

The cloud used for the logic is displaced by disp bars (senkouA[disp], senkouB[disp]), so what you see over the current candle is the cloud computed disp bars ago – exactly the segment the original plots with its forward offset. cloudTop and cloudBot are the upper and lower edges of that band.

Cloud breaks. A bearish break is a close below cloudBot when the previous close was at or above it; a bullish break is the mirror above cloudTop. Nothing is drawn yet – a break is only a candidate.

The breakout classifier. Four features are computed and normalised so they live on a comparable scale:

  • f_rsi – RSI(14) recentred and scaled around 50
  • f_stoch – stochastic %K(14) recentred and scaled around 50
  • f_zscore – z-score of close vs its 20-bar mean
  • f_dist – distance from price to the cloud edge, measured in ATR(14)

They are combined into a single linear score and squashed through a logistic (sigmoid) function into a probability between 0 and 1, one for the sell side and one for the buy side:

prob = 1 / (1 + exp(-z))

The interesting part is where the weights come from. They are self-calibrated: each feature’s weight is the absolute value of its recent rolling correlation with the next-bar return, over calibLen bars, scaled by 4. A feature that has actually been predictive lately gets more say; a feature that hasn’t is turned down toward zero. During warm-up, or when a feature has no variance, its weight falls back to 1. A break is confirmed only when its probability is at or above threshold.

The target plan. When a break happens, the indicator looks at the last tpLookback bars of absolute per-bar moves and extracts three magnitudes: the mean move, an approximate median (found by counting how many moves fall under successive fractions of the mean), and the modal move (found by binning the moves in buckets of 0.25 x ATR). Each is projected from the breakout close, scaled by tpScale, giving three levels labelled Conservative, Standard and Aggressive.

The quality badge. The latest break is graded by how close its probability sits to the threshold: Bullish / Bearish Breakout (confirmed), Nearly Confirmed (within 0.10 below), Watch Setup (within 0.25), or Weak Setup.

 

3. Reading the Indicator

  • The cloud: two lines (Senkou A in aqua, Senkou B in pink) with a shaded fill. The fill turns aqua when Senkou A is above Senkou B (bullish structure) and pink otherwise.
  • White line: the Kijun, a mid-reference for the trend.
  • Green up-triangle / pink down-triangle: a confirmed cloud break – i.e. a break whose classifier probability cleared the threshold. Unconfirmed crosses are deliberately left unmarked.
  • Three horizontal lines to the right of the last break: the target plan. They are colour-coded and labelled Conservative / Standard / Aggressive.
  • Badge at the last break: the quality tier plus the probability as a percentage.

4. Trading Applications

  • A breakout filter, first and foremost. The classifier exists to skip cloud crosses that lack momentum and volatility backing. If you already trade Ichimoku breaks, use the confirmed arrows as a noise gate over your existing rule.
  • Trend context at a glance. The aqua/pink cloud gives the background regime and the Kijun gives a mid line to lean on; the two together frame whether a break is with or against the larger structure.
  • A ready-made scale-out map. The three targets are a natural template for partial exits: take something at Aggressive, more at Standard, leave a runner for Conservative.
  • Rejections are information too. A cloud cross that appears without a confirming arrow is the indicator telling you the move had weak internals – often exactly the failed breaks you want to avoid or fade.

5. Parameters

  • lenTenkan / lenKijun / lenSenkou (9 / 26 / 52): the Hull lengths of the three cloud components. Same defaults as classic Ichimoku.
  • disp (26): displacement of the cloud, in bars.
  • calibLen (100): the window over which each feature’s weight is recalibrated from its correlation with future returns. Shorter adapts faster and noisier; longer is steadier.
  • threshold (0.60): the probability a break must reach to be confirmed. Raise it for fewer, higher-conviction arrows; lower it for more.
  • tpLookback (60): how many bars of price moves feed the target statistics.
  • tpScale (3.0): multiplier applied to the mean/median/mode moves when projecting the three targets.

6. Smart Ichimoku Code

//--------------------------------------------
// PRC_Smart-Ichimoku (by GainzAlgo)
// version = 0
// 21.07.2026
// Iván González @ www.prorealcode.com
// Sharing ProRealTime knowledge
//--------------------------------------------
// Ichimoku suavizado (HMA) + clasificador de rupturas de nube
// con pesos autocalibrados por correlacion, y plan de targets
// del ultimo cruce.
//--------------------------------------------
DEFPARAM DRAWONLASTBARONLY = TRUE
//=== INPUTS ===
lenTenkan  = 9      // Tenkan
lenKijun   = 26     // Kijun
lenSenkou  = 52     // Senkou
disp       = 26     // Displacement
calibLen   = 100    // ventana de autocalibracion (20..300)
threshold  = 0.60   // umbral de probabilidad de ruptura (0.5..1.0)
tpLookback = 60     // lookback de estadistica de movimiento (10..200)
tpScale    = 3.0    // multiplicador de target (0.5..10.0)

//=== ICHIMOKU SUAVIZADO (nube HMA) ===
srcHL   = (high + low) / 2
tenkan  = average[lenTenkan, 7](srcHL)
kijun   = average[lenKijun, 7](srcHL)
tkAvg   = (tenkan + kijun) / 2
senkouA = average[lenKijun, 7](tkAvg)
senkouB = average[lenSenkou, 7](srcHL)

// nube "actual" = senkou calculado hace disp barras (equivale al offset de Pine)
senkouAd = senkouA[disp]
senkouBd = senkouB[disp]
cloudTop = max(senkouAd, senkouBd)
cloudBot = min(senkouAd, senkouBd)

//=== CRUCES DE NUBE ===
crossBelow = close < cloudBot and close[1] >= cloudBot[1]
crossAbove = close > cloudTop and close[1] <= cloudTop[1]
anyCross   = crossBelow or crossAbove

//=== FEATURES DEL CLASIFICADOR ===
myatr = averagetruerange[14](close)
frsi  = (rsi[14](close) - 50) / 25

llow  = lowest[14](low)
hhigh = highest[14](high)
if hhigh - llow <> 0 then
   stochK = 100 * (close - llow) / (hhigh - llow)
else
   stochK = 50
endif
fstoch = (stochK - 50) / 25

sd20 = std[20](close)
if sd20 = 0 then
   fzscore = 0
else
   fzscore = (close - average[20](close)) / sd20
endif

if myatr = 0 then
   fdistBear = 0
   fdistBull = 0
else
   fdistBear = (cloudBot - close) / myatr
   fdistBull = (close - cloudTop) / myatr
endif

//=== PESOS AUTOCALIBRADOS ===
// r = (avg(x*y) - avg(x)*avg(y)) / (std(x)*std(y))
fwdret = close - close[1]
avgFwd = average[calibLen](fwdret)
stdFwd = std[calibLen](fwdret)

xrsi = frsi[1]
prsi = xrsi * fwdret
if barindex > calibLen and std[calibLen](xrsi) * stdFwd <> 0 then
   corrRsi = (average[calibLen](prsi) - average[calibLen](xrsi) * avgFwd) / (std[calibLen](xrsi) * stdFwd)
   wrsi = abs(corrRsi) * 4
else
   wrsi = 1
endif

xstoch = fstoch[1]
pstoch = xstoch * fwdret
if barindex > calibLen and std[calibLen](xstoch) * stdFwd <> 0 then
   corrStoch = (average[calibLen](pstoch) - average[calibLen](xstoch) * avgFwd) / (std[calibLen](xstoch) * stdFwd)
   wstoch = abs(corrStoch) * 4
else
   wstoch = 1
endif

xzscore = fzscore[1]
pzscore = xzscore * fwdret
if barindex > calibLen and std[calibLen](xzscore) * stdFwd <> 0 then
   corrZscore = (average[calibLen](pzscore) - average[calibLen](xzscore) * avgFwd) / (std[calibLen](xzscore) * stdFwd)
   wzscore = abs(corrZscore) * 4
else
   wzscore = 1
endif

xdbull = fdistBull[1]
pdbull = xdbull * fwdret
if barindex > calibLen and std[calibLen](xdbull) * stdFwd <> 0 then
   corrDbull = (average[calibLen](pdbull) - average[calibLen](xdbull) * avgFwd) / (std[calibLen](xdbull) * stdFwd)
   wdbull = abs(corrDbull) * 4
else
   wdbull = 1
endif

xdbear = fdistBear[1]
pdbear = xdbear * fwdret
if barindex > calibLen and std[calibLen](xdbear) * stdFwd <> 0 then
   corrDbear = (average[calibLen](pdbear) - average[calibLen](xdbear) * avgFwd) / (std[calibLen](xdbear) * stdFwd)
   wdbear = abs(corrDbear) * 4
else
   wdbear = 1
endif

//=== COMBINACION LINEAL + SIGMOIDE ===
zsell = wrsi * frsi + wstoch * fstoch + wzscore * fzscore + wdbear * fdistBear
zbuy  = wdbull * fdistBull - wrsi * frsi - wstoch * fstoch - wzscore * fzscore
probSell = 1 / (1 + exp(-zsell))
probBuy  = 1 / (1 + exp(-zbuy))

confirmedBull = crossAbove and probBuy  >= threshold
confirmedBear = crossBelow and probSell >= threshold

//=== ESTADISTICA DE MOVIMIENTO ===
barMove  = abs(close - close[1])
meanMove = average[tpLookback](barMove)

once lastCrossBar = 0
once lastClose    = 0
once lastIsBull   = 0
once lastProb     = 0.0
once lastBadgeY   = 0.0
once lastMean     = 0.0
once lastMedian   = 0.0
once lastMode     = 0.0

if anyCross then
   lastCrossBar = barindex
   lastClose = close
   if crossAbove then
      lastIsBull = 1
      lastProb = probBuy
      lastBadgeY = low - myatr * 0.8
   else
      lastIsBull = 0
      lastProb = probSell
      lastBadgeY = high + myatr * 0.8
   endif
   lastMean = meanMove
   
   // -- mediana aproximada por conteo de umbrales --
   cnt25  = 0
   cnt50  = 0
   cnt75  = 0
   cnt100 = 0
   cnt150 = 0
   for i = 0 to tpLookback - 1 do
      mv = abs(close[i] - close[i + 1])
      if mv < meanMove * 0.25 then
         cnt25 = cnt25 + 1
      endif
      if mv < meanMove * 0.50 then
         cnt50 = cnt50 + 1
      endif
      if mv < meanMove * 0.75 then
         cnt75 = cnt75 + 1
      endif
      if mv < meanMove * 1.00 then
         cnt100 = cnt100 + 1
      endif
      if mv < meanMove * 1.50 then
         cnt150 = cnt150 + 1
      endif
   next
   halfN = tpLookback / 2
   medianMult = 1.75
   if cnt150 >= halfN then
      medianMult = 1.25
   endif
   if cnt100 >= halfN then
      medianMult = 0.875
   endif
   if cnt75 >= halfN then
      medianMult = 0.625
   endif
   if cnt50 >= halfN then
      medianMult = 0.375
   endif
   if cnt25 >= halfN then
      medianMult = 0.25
   endif
   lastMedian = meanMove * medianMult
   
   // -- moda por binning en cubos de 0.25*ATR --
   binW = myatr * 0.25
   bb0 = 0
   bb1 = 0
   bb2 = 0
   bb3 = 0
   bb4 = 0
   bb5 = 0
   for i = 0 to tpLookback - 1 do
      mv = abs(close[i] - close[i + 1])
      if binW > 0 then
         idx = floor(mv / binW)
      else
         idx = 0
      endif
      if idx = 0 then
         bb0 = bb0 + 1
      elsif idx = 1 then
         bb1 = bb1 + 1
      elsif idx = 2 then
         bb2 = bb2 + 1
      elsif idx = 3 then
         bb3 = bb3 + 1
      elsif idx = 4 then
         bb4 = bb4 + 1
      else
         bb5 = bb5 + 1
      endif
   next
   modeBin = 5
   if bb4 >= bb5 then
      modeBin = 4
   endif
   if bb3 >= bb4 and bb3 >= bb5 then
      modeBin = 3
   endif
   if bb2 >= bb3 and bb2 >= bb4 and bb2 >= bb5 then
      modeBin = 2
   endif
   if bb1 >= bb2 and bb1 >= bb3 and bb1 >= bb4 and bb1 >= bb5 then
      modeBin = 1
   endif
   if bb0 >= bb1 and bb0 >= bb2 and bb0 >= bb3 and bb0 >= bb4 and bb0 >= bb5 then
      modeBin = 0
   endif
   lastMode = (modeBin + 0.5) * binW
endif

//=== REGISTRO DE SEÑALES CONFIRMADAS (arrays, X fija) ===
once nSig = 0
if confirmedBull then
   $sigX[nSig] = barindex
   $sigY[nSig] = low - myatr * 0.5
   $sigType[nSig] = 1
   nSig = nSig + 1
elsif confirmedBear then
   $sigX[nSig] = barindex
   $sigY[nSig] = high + myatr * 0.5
   $sigType[nSig] = 2
   nSig = nSig + 1
endif

//=== NUBE: relleno dinamico ===
if senkouAd > senkouBd then
   cr = 0
   cg = 229
   cb = 255
else
   cr = 255
   cg = 0
   cb = 127
endif
colorbetween(senkouAd, senkouBd, cr, cg, cb, 20)

//=== DIBUJO EN LA ULTIMA BARRA ===
if islastbarupdate then
   // -- flechas de rupturas confirmadas (redibujo desde arrays) --
   // solo las ultimas 250 señales
   startK = 0
   if nSig > 250 then
      startK = nSig - 250
   endif
   for k = startK to nSig - 1 do
      if $sigType[k] = 1 then
         drawtext("▲", $sigX[k], $sigY[k]) coloured(57, 255, 20)
      else
         drawtext("▼", $sigX[k], $sigY[k]) coloured(255, 0, 127)
      endif
   next
   
   // -- plan de targets del ultimo cruce --
   if lastCrossBar > 0 then
      if lastIsBull = 1 then
         dirSign = 1
      else
         dirSign = -1
      endif
      tCons = lastClose + dirSign * lastMean   * tpScale
      tStd  = lastClose + dirSign * lastMedian * tpScale
      tAggr = lastClose + dirSign * lastMode   * tpScale
      
      lvlTop = max(tCons, max(tStd, tAggr))
      lvlBot = min(tCons, min(tStd, tAggr))
      lvlMid = tCons + tStd + tAggr - lvlTop - lvlBot
      
      x1 = lastCrossBar
      x2 = lastCrossBar + 60
      
      if lastIsBull = 1 then
         // bull: top=Aggressive(rosa), mid=Standard(aqua), bot=Conservative(amarillo)
         drawsegment(x1, lvlTop, x2, lvlTop) coloured(255, 0, 127) style(dottedline, 2)
         drawsegment(x1, lvlMid, x2, lvlMid) coloured(0, 229, 255) style(dottedline2, 2)
         drawsegment(x1, lvlBot, x2, lvlBot) coloured(255, 234, 0) style(line, 2)
         drawtext("Aggressive",   x2, lvlTop+0.15*myatr) coloured(255, 0, 127)
         drawtext("Standard",     x2, lvlMid+0.15*myatr) coloured(0, 229, 255)
         drawtext("Conservative", x2, lvlBot+0.15*myatr) coloured(255, 234, 0)
      else
         // bear: top=Conservative(amarillo), mid=Standard(aqua), bot=Aggressive(rosa)
         drawsegment(x1, lvlTop, x2, lvlTop) coloured(255, 234, 0) style(line, 2)
         drawsegment(x1, lvlMid, x2, lvlMid) coloured(0, 229, 255) style(dottedline2, 2)
         drawsegment(x1, lvlBot, x2, lvlBot) coloured(255, 0, 127) style(dottedline, 2)
         drawtext("Conservative", x2, lvlTop+0.15*myatr) coloured(255, 234, 0)
         drawtext("Standard",     x2, lvlMid+0.15*myatr) coloured(0, 229, 255)
         drawtext("Aggressive",   x2, lvlBot+0.15*myatr) coloured(255, 0, 127)
      endif
      
      // -- badge de calidad de la ultima señal --
      pctv = round(lastProb * 100)
      gap = threshold - lastProb
      if lastProb >= threshold then
         if lastIsBull = 1 then
            drawtext("Bullish Breakout #pctv#%", x1, lastBadgeY) coloured(57, 255, 20)
         else
            drawtext("Bearish Breakout #pctv#%", x1, lastBadgeY) coloured(255, 0, 127)
         endif
      elsif gap <= 0.10 then
         drawtext("Nearly Confirmed #pctv#%", x1, lastBadgeY) coloured(0, 176, 255)
      elsif gap <= 0.25 then
         drawtext("Watch Setup #pctv#%", x1, lastBadgeY) coloured(255, 109, 0)
      else
         drawtext("Weak Setup #pctv#%", x1, lastBadgeY) coloured(255, 193, 7)
      endif
   endif
endif

return senkouAd coloured(0, 229, 255, 89) style(line, 1) as "Senkou A", senkouBd coloured(255, 0, 127, 89) style(line, 1) as "Senkou B", kijun coloured(255, 255, 255, 102) style(line, 1) as "Kijun"

Download
Filename: PRC_Smart-Ichimoku.itf
Downloads: 18
Iván González Legend
Operating in the shadows, I hack problems one by one. My bio is currently encrypted by a complex algorithm. Decryption underway...
Author’s Profile

Comments

Logo Logo
Loading...