Indicator · Pine Script v6 · On the chart

Modern Ichimoku Cloud [GBB]

by ZhijuCen

Modern Ichimoku Cloud [GBB] is an advanced trend and momentum indicator that enhances classic Ichimoku Kinko Hyo with multi-layered structural analysis.

View on GitHub

GitHub stars2on the repository
Pine versionv6current
Lines of code410
Settings32inputs
LicenceMIT
Last update2 weeks ago12 Oct 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

410 lines of Pine Script v6 from skills/mql5-from-pinescript/assets/pine-scripts/modern-ichimoku-cloud.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

modern-ichimoku-cloud.pine
//@version=6
// Modern Ichimoku Cloud [GBB]  v0.5  2026-09-19
// Layer 0: the built-in Ichimoku Kinko Hyo plot-for-plot (Classic mode).
// Layer 1: normalised geometry.  Layer 2: qualified signals.  Layer 3: flat-line levels.
// Layer 4: HTF wash, stats table, alerts.
indicator("Modern Ichimoku Cloud [GBB]", "MKumo", overlay = true, max_lines_count = 500, max_labels_count = 50)


// ---------- Inputs ----------
grpC = "Classic"
classicMode  = input.bool(false, "Classic mode (built-in Ichimoku; forces Layers 1-3 off)", group = grpC)
tenkanLen    = input.int(9, "Tenkan-sen", minval = 1, group = grpC)
kijunLen     = input.int(26, "Kijun-sen", minval = 1, group = grpC)
senkouBLen   = input.int(52, "Senkou B", minval = 1, group = grpC)
displacement = input.int(26, "Displacement", minval = 1, group = grpC)

grpG = "Geometry (Layer 1)"
inGeom  = input.bool(true, "Normalised geometry (ATR units, percentile grades)", group = grpG)
atrLen  = input.int(0, "ATR length (0 = Kijun)", minval = 0, group = grpG)
pctLen  = input.int(150, "Percentile window", minval = 10, group = grpG)
pctThin = input.int(30, "Thin <= pct", minval = 0, maxval = 100, group = grpG)
pctThk  = input.int(70, "Thick >= pct", minval = 0, maxval = 100, group = grpG)
pctVThk = input.int(90, "Very thick >= pct", minval = 0, maxval = 100, group = grpG)
showGradeLabel = input.bool(true, "Grade label on last bar", group = grpG)

grpS = "Signals (Layer 2)"
inQualified = input.bool(true, "Qualified signals", group = grpS)
pcMin       = input.float(1.0, "Min price-to-cloud distance (ATR), KUMO events", minval = 0.0, step = 0.05, group = grpS)
chkMin      = input.float(1.0, "Min Chikou momentum (ATR)", minval = 0.0, step = 0.05, group = grpS)
useHtfFilt  = input.bool(false, "Require HTF cloud agreement", group = grpS)
showMarkers = input.bool(true, "Show event markers", group = grpS)
showRaw     = input.bool(true, "Show unqualified events", group = grpS)

grpF = "Flat levels (Layer 3)"
inFlat    = input.bool(true, "Flat-line levels", group = grpF)
flatMinK  = input.int(6, "Kijun flat min bars", minval = 2, group = grpF)
flatMinB  = input.int(8, "Senkou B flat min bars", minval = 2, group = grpF)
touchTol  = input.float(0.05, "Touch tolerance (ATR)", minval = 0.0, step = 0.05, group = grpF)
maxAgeMul = input.int(3, "Max age (x Kijun bars)", minval = 1, group = grpF)
maxLevels = input.int(60, "Max live level objects", minval = 5, maxval = 400, group = grpF)
hideExpired = input.bool(true, "Hide expired levels", group = grpF)

grpH = "HTF & table (Layer 4)"
inHtf     = input.bool(true, "HTF wash", group = grpH)
htfSel    = input.timeframe("", "HTF (blank = auto, 4x chart)", group = grpH)
showTable = input.bool(false, "Stats table", group = grpH)
statsH2   = input.int(10, "Second stats horizon (bars)", minval = 1, maxval = 500, group = grpH)
tableExpanded = input.bool(false, "Expanded stats table (counts)", group = grpH)

grpV = "Style"
paletteSel = input.string("GBB", "Palette", options = ["GBB", "Classic", "Mono"], group = grpV)
themeSel   = input.string("Auto", "Theme", options = ["Auto", "Dark", "Light"], group = grpV)

// Classic mode forces Layers 1-3 off; Layer 4 stays available.
bool useL1 = not classicMode and inGeom
bool useL2 = not classicMode and inQualified
bool useL3 = not classicMode and inFlat
int  off   = displacement - 1
int  atrN  = atrLen > 0 ? atrLen : kijunLen
int  maxAge = maxAgeMul * kijunLen

// ---------- Palette ----------
float bgLum = (0.299 * color.r(chart.bg_color) + 0.587 * color.g(chart.bg_color) + 0.114 * color.b(chart.bg_color)) / 255
bool lightTheme = themeSel == "Light" or (themeSel == "Auto" and bgLum > 0.5)
color cTenkan = paletteSel == "Classic" ? #2962FF : paletteSel == "Mono" ? (lightTheme ? #424242 : #e0e0e0) : lightTheme ? #0d9488 : #2dd4bf
color cKijun  = paletteSel == "Classic" ? #B71C1C : paletteSel == "Mono" ? (lightTheme ? #757575 : #9e9e9e) : lightTheme ? #b45309 : #ffb020
color cSpanA  = paletteSel == "Classic" ? #A5D6A7 : paletteSel == "Mono" ? (lightTheme ? #616161 : #bdbdbd) : lightTheme ? #b8860b : #ffd60a
color cSpanB  = paletteSel == "Classic" ? #EF9A9A : paletteSel == "Mono" ? (lightTheme ? #9e9e9e : #757575) : lightTheme ? #d92507 : #ff3814
color cChikou = paletteSel == "Classic" ? #43A047 : paletteSel == "Mono" ? (lightTheme ? #212121 : #ffffff) : lightTheme ? #1d6fb8 : #94d2ff
color cBull   = paletteSel == "Classic" ? #43A047 : paletteSel == "Mono" ? (lightTheme ? #212121 : #ffffff) : lightTheme ? #a16207 : #ffd60a
color cBear   = paletteSel == "Classic" ? #F44336 : paletteSel == "Mono" ? (lightTheme ? #9e9e9e : #bdbdbd) : lightTheme ? #cc2000 : #ff3814
color cRaw    = color.new(#9e9e9e, 55)
color cTwist  = paletteSel == "Mono" ? (lightTheme ? #424242 : #e0e0e0) : lightTheme ? #d6336c : #ff8fab
color cWashUp = paletteSel == "Mono" ? #9e9e9e : lightTheme ? #b8860b : #ffd60a
color cWashDn = paletteSel == "Mono" ? #616161 : lightTheme ? #d92507 : #ff3814
color cWashIn = paletteSel == "Mono" ? #757575 : lightTheme ? #b45309 : #ffb020

// ---------- Layer 0: the five lines ----------
// One function so the same stack runs on the chart and inside request.security.
f_lines() =>
    float t = (ta.highest(high, tenkanLen) + ta.lowest(low, tenkanLen)) / 2
    float k = (ta.highest(high, kijunLen) + ta.lowest(low, kijunLen)) / 2
    float a = (t + k) / 2
    float b = (ta.highest(high, senkouBLen) + ta.lowest(low, senkouBLen)) / 2
    [t, k, a, b]

[tenkan, kijun, senkouA, senkouB] = f_lines()

// Cloud under the current bar: the span computed `displacement - 1` bars ago.
float spanAcur = senkouA[off]
float spanBcur = senkouB[off]
float upperC = math.max(spanAcur, spanBcur)
float lowerC = math.min(spanAcur, spanBcur)
int   cloudPos = na(upperC) ? 0 : close > upperC ? 1 : close < lowerC ? -1 : 0

// ---------- Layer 1: normalised geometry ----------
float A = ta.atr(atrN)
float thick = A > 0 ? math.abs(spanAcur - spanBcur) / A : na
float tk    = A > 0 ? (tenkan - kijun) / A : na
float pc    = A > 0 and not na(upperC) ? (close > upperC ? (close - upperC) / A : close < lowerC ? (close - lowerC) / A : 0.0) : na
float chk   = A > 0 ? (close - close[off]) / A : na
// Projected thickness (at computation time) for the fill transparency of the drawn cloud.
float thickProj = A > 0 ? math.abs(senkouA - senkouB) / A : na

// Nearest-rank percentiles, guarded for the warm-up.
float p30raw = ta.percentile_nearest_rank(thick, pctLen, pctThin)
float p70raw = ta.percentile_nearest_rank(thick, pctLen, pctThk)
float p90raw = ta.percentile_nearest_rank(thick, pctLen, pctVThk)
float q30raw = ta.percentile_nearest_rank(thickProj, pctLen, pctThin)
float q70raw = ta.percentile_nearest_rank(thickProj, pctLen, pctThk)
float q90raw = ta.percentile_nearest_rank(thickProj, pctLen, pctVThk)
bool  pctReady = bar_index >= pctLen
f_grade(float x, float lo, float mid, float hi) =>
    na(x) or na(lo) or na(mid) or na(hi) ? -1 : x >= hi ? 3 : x >= mid ? 2 : x <= lo ? 0 : 1
int grade     = useL1 and pctReady ? f_grade(thick, p30raw, p70raw, p90raw) : -1
int gradeProj = useL1 and pctReady ? f_grade(thickProj, q30raw, q70raw, q90raw) : -1
string gradeTxt = grade == 0 ? "thin" : grade == 1 ? "normal" : grade == 2 ? "thick" : grade == 3 ? "very thick" : "n/a"

// ---------- Plots (Layer 0 visuals, Layer 1 transparency) ----------
plot(tenkan, "Tenkan-sen", color = cTenkan, linewidth = 2)
plot(kijun, "Kijun-sen", color = cKijun, linewidth = 3)
plot(close, "Chikou", color = color.new(cChikou, 25), offset = -off, linewidth = 1)
pA = plot(senkouA, "Senkou A", color = cSpanA, offset = off, linewidth = 2)
pB = plot(senkouB, "Senkou B", color = cSpanB, offset = off, linewidth = 2)
// Fill density follows the projected thickness grade.
int cloudTransp = useL1 ? (gradeProj == 3 ? 50 : gradeProj == 2 ? 58 : gradeProj == 1 ? 68 : gradeProj == 0 ? 78 : 74) : 68
color cloudUp = paletteSel == "Classic" ? color.new(#43A047, cloudTransp) : color.new(cSpanA, cloudTransp)
color cloudDn = paletteSel == "Classic" ? color.new(#F44336, cloudTransp) : color.new(cSpanB, cloudTransp)
fill(pA, pB, color = senkouA > senkouB ? cloudUp : cloudDn, title = "Kumo")

// ---------- Layer 4a: HTF cloud position from closed HTF bars ----------
f_htf() =>
    [hT, hK, hA, hB] = f_lines()
    float sA = hA[off]
    float sB = hB[off]
    [sA[1], sB[1], close[1]]

string htfTf = htfSel == "" ? timeframe.from_seconds(4 * timeframe.in_seconds()) : htfSel
bool htfActive = inHtf and timeframe.in_seconds(htfTf) > timeframe.in_seconds()
[htfA, htfB, htfC] = request.security(syminfo.tickerid, htfTf, f_htf(), lookahead = barmerge.lookahead_off)
int htfPos = na(htfA) or na(htfB) or na(htfC) ? 0 : htfC > math.max(htfA, htfB) ? 1 : htfC < math.min(htfA, htfB) ? -1 : 0
color htfWash = not htfActive ? na : htfPos > 0 ? color.new(cWashUp, 96) : htfPos < 0 ? color.new(cWashDn, 96) : color.new(cWashIn, 97)
bgcolor(htfWash, title = "HTF wash")

var label htfNote = na
if inHtf and not htfActive and barstate.islast
    if na(htfNote)
        htfNote := label.new(bar_index, close, "HTF wash off: HTF " + htfTf + " is not above the chart timeframe",
             style = label.style_label_left, color = color.new(color.gray, 70), textcolor = color.white, size = size.small)
    else
        label.set_xy(htfNote, bar_index, close)

// ---------- Layer 2: raw events and qualification ----------
bool tkBull = ta.crossover(tenkan, kijun)
bool tkBear = ta.crossunder(tenkan, kijun)
bool kumoUp = ta.crossover(close, upperC)
bool kumoDn = ta.crossunder(close, lowerC)
bool twBull = ta.crossover(senkouA, senkouB)
bool twBear = ta.crossunder(senkouA, senkouB)
// Classic grade of a TK cross: strong / neutral / weak by price above / inside / below the cloud.
int tkGrade = tkBull ? (cloudPos > 0 ? 2 : cloudPos == 0 ? 1 : 0) : tkBear ? (cloudPos < 0 ? 2 : cloudPos == 0 ? 1 : 0) : -1

int barDir = int(math.sign(close - open))
f_qual(int dir, bool isKumo) =>
    bool okDir = barDir == dir
    bool okPc  = isKumo ? (not na(pc) and math.abs(pc) >= pcMin) : (not na(pc) and pc != 0)
    bool okChk = not na(chk) and math.sign(chk) == dir and math.abs(chk) >= chkMin
    bool okHtf = not useHtfFilt or (htfActive and htfPos == dir)
    okDir and okPc and okChk and okHtf

bool qBull = f_qual(1, false)
bool qBear = f_qual(-1, false)
bool qUp   = f_qual(1, true)
bool qDn   = f_qual(-1, true)
// Layer 2 off: qualified = raw.
bool tkBullQ = tkBull and (not useL2 or qBull)
bool tkBearQ = tkBear and (not useL2 or qBear)
bool kumoUpQ = kumoUp and (not useL2 or qUp)
bool kumoDnQ = kumoDn and (not useL2 or qDn)
int  qualDir = tkBullQ or kumoUpQ ? 1 : tkBearQ or kumoDnQ ? -1 : 0

bool mk = showMarkers and not classicMode
// Kumo breaks are the headline markers; TK crosses are smaller; twists and raw events are ambient.
plotshape(mk and tkBullQ, "TK bull (qualified)", style = shape.triangleup, location = location.belowbar, color = cBull, size = size.small)
plotshape(mk and tkBearQ, "TK bear (qualified)", style = shape.triangledown, location = location.abovebar, color = cBear, size = size.small)
plotshape(mk and kumoUpQ, "KUMO up (qualified)", style = shape.triangleup, location = location.belowbar, color = cBull, size = size.normal)
plotshape(mk and kumoDnQ, "KUMO down (qualified)", style = shape.triangledown, location = location.abovebar, color = cBear, size = size.normal)
plotshape(mk and showRaw and useL2 and ((tkBull and not tkBullQ) or (kumoUp and not kumoUpQ)), "Unqualified bull event", style = shape.circle, location = location.belowbar, color = cRaw, size = size.tiny)
plotshape(mk and showRaw and useL2 and ((tkBear and not tkBearQ) or (kumoDn and not kumoDnQ)), "Unqualified bear event", style = shape.circle, location = location.abovebar, color = cRaw, size = size.tiny)
plotshape(mk and twBull, "Twist bull", style = shape.diamond, location = location.bottom, color = color.new(cTwist, 20), size = size.tiny)
plotshape(mk and twBear, "Twist bear", style = shape.diamond, location = location.top, color = color.new(cTwist, 20), size = size.tiny)

// ---------- Layer 3: flat-line levels ----------
// Run length: number of consecutive bars with exactly the same line value (first bar counts 1).
int flatK = 0
flatK := kijun == kijun[1] ? nz(flatK[1]) + 1 : 1
int flatB = 0
flatB := senkouB == senkouB[1] ? nz(flatB[1]) + 1 : 1

var array<line>  lvLine  = array.new<line>()
var array<float> lvVal   = array.new<float>()
var array<int>   lvAct   = array.new<int>()
var array<int>   lvKind  = array.new<int>()     // 0 kijun, 1 senkou B
var array<int>   lvState = array.new<int>()     // 0 live, 1 touched, 2 expired
var int nLvlK = 0
var int nLvlB = 0
var int nTouchK = 0
var int nTouchB = 0
var int nExpK = 0
var int nExpB = 0
bool flatTouch = false

f_addLevel(float lvl, int seg, int kind) =>
    int flatMin = kind == 0 ? flatMinK : flatMinB
    int w = seg >= 2 * flatMin ? 2 : 1
    color col = kind == 0 ? cKijun : cSpanB
    line id = line.new(bar_index - seg, lvl, bar_index, lvl, xloc = xloc.bar_index, color = color.new(col, 15),
         style = line.style_solid, width = w)
    array.push(lvLine, id)
    array.push(lvVal, lvl)
    array.push(lvAct, bar_index)
    array.push(lvKind, kind)
    array.push(lvState, 0)
    if array.size(lvLine) > maxLevels
        line.delete(array.shift(lvLine))
        array.shift(lvVal)
        array.shift(lvAct)
        array.shift(lvKind)
        array.shift(lvState)

if useL3 and barstate.isconfirmed
    // 1. Live levels: touch on this bar (window starts the bar after activation), else expiry.
    int nL = array.size(lvLine)
    if nL > 0
        for i = 0 to nL - 1
            if array.get(lvState, i) == 0
                float lvl = array.get(lvVal, i)
                line id = array.get(lvLine, i)
                int kind = array.get(lvKind, i)
                float tol = touchTol * A
                bool touched = not na(A) and low - tol <= lvl and lvl <= high + tol
                if touched
                    array.set(lvState, i, 1)
                    line.set_x2(id, bar_index)
                    line.set_color(id, color.new(kind == 0 ? cKijun : cSpanB, 0))
                    flatTouch := true
                    if kind == 0
                        nTouchK += 1
                    else
                        nTouchB += 1
                else if bar_index - array.get(lvAct, i) >= maxAge
                    array.set(lvState, i, 2)
                    line.set_x2(id, bar_index)
                    line.set_style(id, line.style_dotted)
                    line.set_color(id, color.new(kind == 0 ? cKijun : cSpanB, hideExpired ? 100 : 80))
                else
                    line.set_x2(id, bar_index)
    // 2. New levels on the first bar the line moves after a run of at least flatMin bars.
    if kijun != kijun[1] and nz(flatK[1]) >= flatMinK and not na(kijun[1])
        f_addLevel(kijun[1], nz(flatK[1]), 0)
        nLvlK += 1
    if senkouB != senkouB[1] and nz(flatB[1]) >= flatMinB and not na(senkouB[1])
        f_addLevel(senkouB[1], nz(flatB[1]), 1)
        nLvlB += 1

// ---------- Grade label ----------
var label gradeLbl = na
if useL1 and showGradeLabel and barstate.islast
    string txt = "Kumo " + gradeTxt + (na(thick) ? "" : " (" + str.tostring(thick, "0.00") + " ATR)") +
         (na(pc) ? "" : "  ·  price " + str.tostring(pc, "0.00") + " ATR from cloud") +
         (na(chk) ? "" : "  ·  chikou " + str.tostring(chk, "0.00") + " ATR")
    if na(gradeLbl)
        gradeLbl := label.new(bar_index, upperC, txt, style = label.style_label_left,
             color = color.new(#0a0c10, 85), textcolor = color.new(color.white, 20), size = size.small)
    else
        label.set_xy(gradeLbl, bar_index, upperC)
        label.set_text(gradeLbl, txt)

// ---------- Data-window plots (not drawn; used by alert placeholders) ----------
plot(tenkan, "Tenkan", display = display.data_window)
plot(kijun, "Kijun", display = display.data_window)
plot(senkouA, "SenkouA", display = display.data_window)
plot(senkouB, "SenkouB", display = display.data_window)
plot(thick, "Thick", display = display.data_window)
plot(tk, "TK", display = display.data_window)
plot(pc, "PC", display = display.data_window)
plot(chk, "CHK", display = display.data_window)
plot(grade, "Grade", display = display.data_window)
plot(qualDir, "QualDir", display = display.data_window)
plot(tkGrade, "TKGrade", display = display.data_window)

// ---------- Layer 4b: stats table ----------
// Running counts on loaded bars; each event scored once, H bars after it, on confirmed bars.
var int nTkRaw = 0
var int nTkQ = 0
var int nKuRaw = 0
var int nKuQ = 0
var int nTw = 0
var int nScored1 = 0
var int nHit1 = 0
var int nScored2 = 0
var int nHit2 = 0
var float sumFwdAll = 0.0
var int nFwdAll = 0
var float sumFwdEv = 0.0
var int nFwdEv = 0
int H1 = displacement
int H2 = statsH2
float atrH1 = A[H1]
float fwdRange = na(atrH1) or atrH1 == 0 ? na : (ta.highest(high, H1) - ta.lowest(low, H1)) / atrH1
if barstate.isconfirmed
    if tkBull or tkBear
        nTkRaw += 1
    if tkBullQ or tkBearQ
        nTkQ += 1
    if kumoUp or kumoDn
        nKuRaw += 1
    if kumoUpQ or kumoDnQ
        nKuQ += 1
    if twBull or twBear
        nTw += 1
    if bar_index >= H1
        int d1 = nz(qualDir[H1])
        if d1 != 0
            nScored1 += 1
            if math.sign(close - close[H1]) == d1
                nHit1 += 1
        if not na(fwdRange)
            sumFwdAll += fwdRange
            nFwdAll += 1
            if d1 != 0
                sumFwdEv += fwdRange
                nFwdEv += 1
    if bar_index >= H2
        int d2 = nz(qualDir[H2])
        if d2 != 0
            nScored2 += 1
            if math.sign(close - close[H2]) == d2
                nHit2 += 1

// Compact table: key rates only; counts behind the "Expanded stats table" input.
var table stats = na
f_cell(int c, int r, string txt, bool left) =>
    table.cell(stats, c, r, txt, text_color = left ? color.new(color.white, 40) : color.white,
         text_size = size.small, text_halign = left ? text.align_left : text.align_right)

if showTable and barstate.islast
    if na(stats)
        stats := table.new(position.top_right, 2, 10, bgcolor = color.new(#0a0c10, 28), border_width = 0)
    float hit1 = nScored1 > 0 ? 100.0 * nHit1 / nScored1 : na
    float hit2 = nScored2 > 0 ? 100.0 * nHit2 / nScored2 : na
    float rangeMult = nFwdEv > 0 and nFwdAll > 0 and sumFwdAll > 0 ? (sumFwdEv / nFwdEv) / (sumFwdAll / nFwdAll) : na
    // expired = created - touched - still live (per kind)
    int liveK = 0
    int liveB = 0
    int nL = array.size(lvLine)
    if nL > 0
        for i = 0 to nL - 1
            if array.get(lvState, i) == 0
                if array.get(lvKind, i) == 0
                    liveK += 1
                else
                    liveB += 1
    nExpK := math.max(nLvlK - nTouchK - liveK, 0)
    nExpB := math.max(nLvlB - nTouchB - liveB, 0)
    float touchRate = (nTouchK + nTouchB + nExpK + nExpB) > 0 ? 100.0 * (nTouchK + nTouchB) / (nTouchK + nTouchB + nExpK + nExpB) : na
    string qLbl = useL2 ? "qualified" : "raw"
    table.cell(stats, 0, 0, "Hit rate @" + str.tostring(H1) + " (" + qLbl + ")", text_color = color.new(color.white, 40),
         text_size = size.small, text_halign = text.align_left,
         tooltip = "Running counts on loaded bars, not a backtest. Range multiple is a mean. Reset on settings change and reload. No costs.")
    table.cell(stats, 1, 0, na(hit1) ? "-" : str.tostring(hit1, "0.0") + "% (" + str.tostring(nScored1) + ")",
         text_color = na(hit1) ? color.new(color.white, 40) : hit1 >= 50 ? cBull : color.white, text_size = size.small, text_halign = text.align_right)
    f_cell(0, 1, "Hit rate @" + str.tostring(H2), true)
    table.cell(stats, 1, 1, na(hit2) ? "-" : str.tostring(hit2, "0.0") + "% (" + str.tostring(nScored2) + ")",
         text_color = na(hit2) ? color.new(color.white, 40) : hit2 >= 50 ? cBull : color.white, text_size = size.small, text_halign = text.align_right)
    f_cell(0, 2, "Range multiple @" + str.tostring(H1), true)
    f_cell(1, 2, na(rangeMult) ? "-" : str.tostring(rangeMult, "0.00") + "x", false)
    f_cell(0, 3, "Touch rate (retired levels)", true)
    f_cell(1, 3, na(touchRate) ? "-" : str.tostring(touchRate, "0.0") + "%", false)
    f_cell(0, 4, "HTF " + htfTf, true)
    table.cell(stats, 1, 4, not htfActive ? "off" : htfPos > 0 ? "above cloud" : htfPos < 0 ? "below cloud" : "inside cloud",
         text_color = not htfActive ? color.new(color.white, 40) : htfPos > 0 ? cWashUp : htfPos < 0 ? cWashDn : cWashIn,
         text_size = size.small, text_halign = text.align_right)
    if tableExpanded
        f_cell(0, 5, "TK cross raw / " + qLbl, true)
        f_cell(1, 5, str.tostring(nTkRaw) + " / " + str.tostring(nTkQ), false)
        f_cell(0, 6, "Kumo break raw / " + qLbl, true)
        f_cell(1, 6, str.tostring(nKuRaw) + " / " + str.tostring(nKuQ), false)
        f_cell(0, 7, "Twists", true)
        f_cell(1, 7, str.tostring(nTw), false)
        f_cell(0, 8, "Kijun levels created / touched / expired", true)
        f_cell(1, 8, str.tostring(nLvlK) + " / " + str.tostring(nTouchK) + " / " + str.tostring(nExpK), false)
        f_cell(0, 9, "Senkou B levels created / touched / expired", true)
        f_cell(1, 9, str.tostring(nLvlB) + " / " + str.tostring(nTouchB) + " / " + str.tostring(nExpB), false)

// ---------- Alerts: confirmed bars only ----------
bool alTkBull = barstate.isconfirmed and tkBullQ
bool alTkBear = barstate.isconfirmed and tkBearQ
bool alKuUp   = barstate.isconfirmed and kumoUpQ
bool alKuDn   = barstate.isconfirmed and kumoDnQ
bool alTwBull = barstate.isconfirmed and twBull
bool alTwBear = barstate.isconfirmed and twBear
bool alTouch  = barstate.isconfirmed and flatTouch
alertcondition(alTkBull, "Qualified TK cross - bull", 'MKumo {{ticker}} {{interval}}: qualified TK cross BULL, grade {{plot("Grade")}}')
alertcondition(alTkBear, "Qualified TK cross - bear", 'MKumo {{ticker}} {{interval}}: qualified TK cross BEAR, grade {{plot("Grade")}}')
alertcondition(alKuUp, "Qualified Kumo breakout - up", 'MKumo {{ticker}} {{interval}}: qualified Kumo breakout UP, grade {{plot("Grade")}}')
alertcondition(alKuDn, "Qualified Kumo breakout - down", 'MKumo {{ticker}} {{interval}}: qualified Kumo breakout DOWN, grade {{plot("Grade")}}')
alertcondition(alTwBull, "Kumo twist - bull", 'MKumo {{ticker}} {{interval}}: Kumo twist BULL (projected cloud)')
alertcondition(alTwBear, "Kumo twist - bear", 'MKumo {{ticker}} {{interval}}: Kumo twist BEAR (projected cloud)')
alertcondition(alTouch, "Flat level touched", 'MKumo {{ticker}} {{interval}}: flat level touched')

Overview

Modern Ichimoku Cloud [GBB] plots traditional Tenkan-sen, Kijun-sen, Senkou Spans, and Chikou Span on the price chart while offering ATR-normalized geometry and cloud percentile thickness grades. The indicator filters qualified signals using price-to-cloud distance and Chikou momentum, identifies support and resistance levels from flat lines, and features a higher timeframe cloud wash. Configurable inputs adjust lengths, ATR metrics, signal thresholds, and timeframe parameters.

Details

Published by

ZhijuCen on GitHub

Type

Indicator, Pine Script v6

Draws

On the price chart

Category

Trend, Support & resistance, Oscillators & momentum

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Classic mode (built-in Ichimoku; forces Layers 1-3 off)boolfalseclassicMode
Tenkan-senint9tenkanLen
Kijun-senint26kijunLen
Senkou Bint52senkouBLen
Displacementint26displacement
Normalised geometry (ATR units, percentile grades)booltrueinGeom
ATR length (0 = Kijun)int0atrLen
Percentile windowint150pctLen
Thin <= pctint30pctThin
Thick >= pctint70pctThk
Very thick >= pctint90pctVThk
Grade label on last barbooltrueshowGradeLabel
Show all 32 settings
SettingTypeDefaultVariable
Qualified signalsbooltrueinQualified
Min price-to-cloud distance (ATR), KUMO eventsfloat1.0pcMin
Min Chikou momentum (ATR)float1.0chkMin
Require HTF cloud agreementboolfalseuseHtfFilt
Show event markersbooltrueshowMarkers
Show unqualified eventsbooltrueshowRaw
Flat-line levelsbooltrueinFlat
Kijun flat min barsint6flatMinK
Senkou B flat min barsint8flatMinB
Touch tolerance (ATR)float0.05touchTol
Max age (x Kijun bars)int3maxAgeMul
Max live level objectsint60maxLevels
Hide expired levelsbooltruehideExpired
HTF washbooltrueinHtf
HTF (blank = auto, 4x chart)timeframehtfSel
Stats tableboolfalseshowTable
Second stats horizon (bars)int10statsH2
Expanded stats table (counts)boolfalsetableExpanded
PalettestringGBBpaletteSel
ThemestringAutothemeSel
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

114 stars

This indicator calculates key support and resistance levels by analyzing the first and second momentum derivatives of a Double Exponential Moving Average (DEMA). When the second derivative (momentum of momentum) crosses zero, it identifies local turning points

Indicator v4 Support & resistanceOscillators & momentum
Updated 1 year ago · None stated GitHub repository of Support and Resistance Levels

Moon Dev Lunar Sniper

by moondevonyt
92 stars

Moon Dev Lunar Sniper is a multi-indicator overlay that scores confluence across fast and slow EMAs, RSI, MACD, DMI, and BB width to fire signals only when score meets the minimum threshold. It plots buy and sell signals on the price chart, highlights cosmic b

Indicator v6 TrendOscillators & momentum Repaints
Updated 8 weeks ago · Custom licence GitHub repository of Moon Dev Lunar Sniper
14 stars

Self-Aware Trend System calculates volatility-adaptive ATR trailing bands using a Trend Quality Index engine that evaluates market efficiency, momentum persistence, and structural pivots. It plots adaptive trend bands and character-flip trend signals directly

Indicator v6 TrendVolatility & bands
Updated 2 weeks ago · MIT GitHub repository of Self-Aware Trend System [WillyAlgoTrader]

SPY 0DTE Scalper - 15min

by chris-c-thomas
14 stars

This intraday overlay establishes directional bias and high-conviction swing setups for SPY on the 15-minute timeframe. It computes a weighted confluence score combining an EMA ribbon, a 50 EMA anchor, session VWAP bands, RSI divergence, ADX, TTM Squeeze, cand

Indicator v6 TrendOscillators & momentum
Updated 6 months ago · MIT GitHub repository of SPY 0DTE Scalper - 15min

Market Trend

by azamiftikhar1000
12 stars

Market Trend is an overlay indicator that identifies market direction and key price levels. It calculates a Relative Strength Index with Bollinger Bands to construct a 20-step color gradient reflecting momentum shifts. The script incorporates exponential movin

Indicator v4 TrendOscillators & momentum
Updated 3 years ago · None stated GitHub repository of Market Trend

BTE Acc AO SMIO

by f-cksociety
11 stars

This script provides an indicator-based backtesting engine framework that simulates trade entries, exits, and filtering directly on the price chart. It evaluates selected entry rules and multi-layered filters, including moving average trends, volume increases,

Indicator v5 TrendOscillators & momentum
Updated 4 years ago · MPL-2.0 GitHub repository of BTE Acc AO SMIO

More indicators

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers