Indicator · Pine Script v6 · On the chart

EMA + Supertrend + OBV

by vedkanani123

A price-chart indicator that stacks a 21, 50 and 200 EMA ribbon with a Supertrend line and an ATR-based volatility stop.

View on GitHub

GitHub stars1on the repository
Pine versionv6current
Lines of code506
Settings27inputs
LicenceNone statedfile: MPL-2.0
Last update2 months ago23 Aug 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

506 lines of Pine Script v6 from indicator/olg_7_6_26/ALL_2/codex/indicator/6/EMA Crossover Buy/Trend Engine_32.txt, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

Trend Engine_32.txt
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/

//@version=6
indicator("EMA + Supertrend + OBV", shorttitle="EMA + Supertrend + OBV", overlay=true, max_labels_count=50)

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// INPUTS
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

i_emaFast   = input.int(21, "Fast EMA", minval=1, group="⚙ EMA Stack")
i_emaMid    = input.int(50, "Mid EMA", minval=1, group="⚙ EMA Stack")
i_emaSlow   = input.int(200, "Slow EMA", minval=1, group="⚙ EMA Stack")
i_emaFill   = input.bool(true, "Show ribbon fill", group="⚙ EMA Stack")

i_stFactor  = input.float(3.0, "Factor", minval=0.5, step=0.1, group="⚙ Supertrend")
i_stAtr     = input.int(10, "ATR Period", minval=1, group="⚙ Supertrend")
i_stShow    = input.bool(true, "Show Supertrend line", group="⚙ Supertrend")

i_vsAtrLen  = input.int(20, "ATR Period", minval=1, group="⚙ Vol Stop")
i_vsMult    = input.float(3.25, "ATR Multiplier", minval=0.5, step=0.05, group="⚙ Vol Stop")
i_vsShow    = input.bool(true, "Show Vol Stop line", group="⚙ Vol Stop")

i_obvMaLen  = input.int(20, "OBV MA Length", minval=2, group="⚙ OBV")
i_obvLook   = input.int(5, "Slope lookback", minval=1, group="⚙ OBV")

i_volAtrLen = input.int(14, "ATR Length", minval=1, group="⚙ Volatility")
i_volLook   = input.int(100, "Percentile Lookback", minval=10, group="⚙ Volatility")
i_discLow      = input.float(1.00, "Discount — Low Vol", minval=0.0, maxval=1.5, step=0.05, group="⚙ Volatility")
i_discNormal    = input.float(1.00, "Discount — Normal Vol", minval=0.0, maxval=1.5, step=0.05, group="⚙ Volatility")
i_discElevated  = input.float(0.75, "Discount — Elevated Vol", minval=0.0, maxval=1.5, step=0.05, group="⚙ Volatility")
i_discExtreme   = input.float(0.50, "Discount — Extreme Vol", minval=0.0, maxval=1.5, step=0.05, group="⚙ Volatility")

i_tf1       = input.timeframe("60", "Timeframe 1", group="📊 MTF Heatmap")
i_tf2       = input.timeframe("1D", "Timeframe 2", group="📊 MTF Heatmap")
i_tf3       = input.timeframe("1W", "Timeframe 3", group="📊 MTF Heatmap")
i_tf4       = input.timeframe("1M", "Timeframe 4", group="📊 MTF Heatmap")
i_showHM    = input.bool(true, "Show heatmap", group="📊 MTF Heatmap")
i_netPctLook = input.int(100, "Net Score Percentile Lookback", minval=10, group="📊 MTF Heatmap")
i_hmPos     = input.string("Middle Right", "Position", options=["Top Right", "Top Left", "Bottom Right", "Bottom Left", "Middle Right", "Middle Left"], group="📊 MTF Heatmap")
i_hmSize    = input.string("Normal", "Text size", options=["Tiny", "Small", "Normal", "Large", "Huge"], group="📊 MTF Heatmap")

i_showCross = input.bool(true, "Show GC / DC labels", group="📊 Chart")

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// CORE CALCULATIONS (evaluated per-TF via request.security)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

// --- EMA ---
emaF = ta.ema(close, i_emaFast)
emaM = ta.ema(close, i_emaMid)
emaS = ta.ema(close, i_emaSlow)

bullStack = emaF > emaM and emaM > emaS
bearStack = emaF < emaM and emaM < emaS
pAboveAll = close > emaF and close > emaM and close > emaS
pBelowAll = close < emaF and close < emaM and close < emaS

goldenCross = ta.crossover(emaM, emaS)
deathCross  = ta.crossunder(emaM, emaS)

emaScore   = bullStack and pAboveAll ? 2 : bullStack ? 1 : bearStack and pBelowAll ? -2 : bearStack ? -1 : close > emaS ? 1 : close < emaS ? -1 : 0
pVs200     = close > emaS ? 1 : -1

// --- Supertrend ---
[stValue, stDir] = ta.supertrend(i_stFactor, i_stAtr)
stBull     = stDir == -1
stFlipBull = stBull and not stBull[1]
stFlipBear = not stBull and stBull[1]
stScore    = stBull ? 1 : -1

// --- Vol Stop (Chandelier-style ATR trailing stop, period 20 / mult 3.25 by default) ---
vsAtr           = i_vsMult * ta.atr(i_vsAtrLen)
vsLongStop      = ta.highest(high, i_vsAtrLen) - vsAtr
vsLongStopPrev  = nz(vsLongStop[1], vsLongStop)
vsLongStop     := close[1] > vsLongStopPrev ? math.max(vsLongStop, vsLongStopPrev) : vsLongStop
vsShortStop     = ta.lowest(low, i_vsAtrLen) + vsAtr
vsShortStopPrev = nz(vsShortStop[1], vsShortStop)
vsShortStop    := close[1] < vsShortStopPrev ? math.min(vsShortStop, vsShortStopPrev) : vsShortStop

var int vsDir = 1
vsDir := close > vsShortStopPrev ? 1 : close < vsLongStopPrev ? -1 : vsDir
vsFlipBull = vsDir == 1 and vsDir[1] == -1
vsFlipBear = vsDir == -1 and vsDir[1] == 1
vsScore    = vsDir

// --- Heikin-Ashi Candle Color ---
haClose = (open + high + low + close) / 4
var float haOpen = na
haOpen := na(haOpen[1]) ? (open + close) / 2 : (haOpen[1] + haClose[1]) / 2
haBull  = haClose > haOpen
haScore = haBull ? 1 : -1

// --- OBV (ta.cum — MTF safe) ---
obvRaw     = ta.cum(ta.change(close) > 0 ? volume : ta.change(close) < 0 ? -volume : 0.0)
obvMa      = ta.sma(obvRaw, i_obvMaLen)
obvAbv     = obvRaw > obvMa
obvSlope   = ta.change(obvMa, i_obvLook)
obvRise    = obvSlope > 0
obvFall    = obvSlope < 0
obvScore   = obvAbv and obvRise ? 1 : not obvAbv and obvFall ? -1 : 0

// Extra data for detailed table
obvAbvInt  = obvAbv ? 1 : 0
obvSlopeN  = obvRise ? 1 : obvFall ? -1 : 0

// --- Volatility (ATR percentile regime) ---
// Ranks current ATR against its own trailing history (0-100). Low percentile = calm/favorable,
// high percentile = turbulent/unfavorable for trend-confluence purposes.
atrVal   = ta.atr(i_volAtrLen)
atrPct   = ta.percentrank(atrVal, i_volLook)
volScore = atrPct >= 75 ? -2 : atrPct >= 50 ? -1 : atrPct >= 25 ? 1 : 2   // Extreme/Elevated negative, Normal/Low positive
atrPctR  = math.round(atrPct)

// Confidence discount multiplier — same regime buckets shown in the table
volMult(pct) =>
    pct >= 75 ? i_discExtreme : pct >= 50 ? i_discElevated : pct >= 25 ? i_discNormal : i_discLow

discCurrent = volMult(atrPctR)

// --- Totals ---
totalScore = emaScore + stScore + obvScore + vsScore + haScore
confScore  = totalScore * discCurrent   // volatility-adjusted confluence score

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// MTF DATA (6 values per timeframe)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[e1, s1, o1, p1, oa1, os1, v1, ap1, vs1, ha1] = request.security(syminfo.tickerid, i_tf1, [emaScore, stScore, obvScore, pVs200, obvAbvInt, obvSlopeN, volScore, atrPctR, vsScore, haScore], barmerge.gaps_off, barmerge.lookahead_off)
[e2, s2, o2, p2, oa2, os2, v2, ap2, vs2, ha2] = request.security(syminfo.tickerid, i_tf2, [emaScore, stScore, obvScore, pVs200, obvAbvInt, obvSlopeN, volScore, atrPctR, vsScore, haScore], barmerge.gaps_off, barmerge.lookahead_off)
[e3, s3, o3, p3, oa3, os3, v3, ap3, vs3, ha3] = request.security(syminfo.tickerid, i_tf3, [emaScore, stScore, obvScore, pVs200, obvAbvInt, obvSlopeN, volScore, atrPctR, vsScore, haScore], barmerge.gaps_off, barmerge.lookahead_off)
[e4, s4, o4, p4, oa4, os4, v4, ap4, vs4, ha4] = request.security(syminfo.tickerid, i_tf4, [emaScore, stScore, obvScore, pVs200, obvAbvInt, obvSlopeN, volScore, atrPctR, vsScore, haScore], barmerge.gaps_off, barmerge.lookahead_off)

t1 = math.round(e1 + s1 + o1 + vs1 + ha1)
t2 = math.round(e2 + s2 + o2 + vs2 + ha2)
t3 = math.round(e3 + s3 + o3 + vs3 + ha3)
t4 = math.round(e4 + s4 + o4 + vs4 + ha4)

// Net score across all timeframes — Daily and Weekly weighted 2x, each leg discounted by its own volatility regime
// Max possible per TF is now 6 (EMA ±2, Supertrend ±1, OBV ±1, Vol Stop ±1, HA Candle ±1)
// Max total: |t1|=6 (1H) + |t2|*2=12 (Daily) + |t3|*2=12 (Weekly) + |t4|=6 (Monthly) = 36
netScoreMax = 36
dT1 = t1 * volMult(ap1)
dT2 = t2 * volMult(ap2)
dT3 = t3 * volMult(ap3)
dT4 = t4 * volMult(ap4)
netScore    = dT1 + (2 * dT2) + (2 * dT3) + dT4
netScorePct = int(math.round((netScore / netScoreMax) * 100))

// Net Score percentile — ranks today's reading against its own trailing history,
// which is a more honest "how extreme is this right now" read than % of theoretical max
netScorePctile = int(math.round(ta.percentrank(netScore, i_netPctLook)))

// Alignment
bullTFs = (t1 > 0 ? 1 : 0) + (t2 > 0 ? 1 : 0) + (t3 > 0 ? 1 : 0) + (t4 > 0 ? 1 : 0)
bearTFs = (t1 < 0 ? 1 : 0) + (t2 < 0 ? 1 : 0) + (t3 < 0 ? 1 : 0) + (t4 < 0 ? 1 : 0)

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// REGIME
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

// Max total score is now 6 (EMA ±2, Supertrend ±1, OBV ±1, Vol Stop ±1, HA Candle ±1)
isStrongBull = confScore >= 5
isBull       = confScore >= 1 and confScore < 5
isNeutral    = confScore == 0
isBear       = confScore <= -1 and confScore > -5
isStrongBear = confScore <= -5

var int prevC = 0
currC        = isStrongBull ? 4 : isBull ? 3 : isNeutral ? 2 : isBear ? 1 : 0
trendChanged = currC != prevC
prevC       := currC

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// HELPER FUNCTIONS
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

// Heatmap palette
cBS = #00E676    // strong bull
cBM = #4CAF50    // bull
cBW = #81C784    // weak bull
cN  = #546E7A    // neutral
cRW = #E57373    // weak bear
cRM = #F44336    // bear
cRS = #FF1744    // strong bear

hmCol(int score, int mx) =>
    r = mx != 0 ? score / mx : 0.0
    r >= 0.8 ? cBS : r >= 0.4 ? cBM : r > 0 ? cBW : r == 0 ? cN : r > -0.4 ? cRW : r > -0.8 ? cRM : cRS

// EMA stack label
emaLbl(int sc) =>
    sc == 2 ? "FULL BULL ▲▲" : sc == 1 ? "BULLISH ▲" : sc == -1 ? "BEARISH ▼" : sc == -2 ? "FULL BEAR ▼▼" : "MIXED ◆"

// Supertrend label
stLbl(int sc) =>
    sc == 1 ? "BULLISH ▲" : "BEARISH ▼"

// Price vs 200 label
p200Lbl(int sc) =>
    sc == 1 ? "ABOVE ▲" : "BELOW ▼"

// OBV flow label
obvFlowLbl(int abv, int slope) =>
    abv == 1 and slope == 1  ? "ACCUM ▲" :
     abv == 0 and slope == -1 ? "DISTRIB ▼" :
     abv == 1 and slope == 0  ? "ABOVE MA" :
     abv == 0 and slope == 0  ? "BELOW MA" :
     abv == 1 and slope == -1 ? "WEAKENING" :
     abv == 0 and slope == 1  ? "BUILDING" :
     "NEUTRAL"

obvFlowCol(int abv, int slope) =>
    abv == 1 and slope == 1  ? cBS :
     abv == 0 and slope == -1 ? cRS :
     abv == 1                 ? cBW :
     abv == 0 and slope == 1  ? cBW :
     abv == 0                 ? cRW :
     cN

// Regime label (max total score is now 6)
regLbl(int sc) =>
    sc >= 5 ? "STRONG BULL" : sc >= 1 ? "BULLISH" : sc == 0 ? "NEUTRAL" : sc >= -4 ? "BEARISH" : "STRONG BEAR"

// Volatility regime label (ATR percentile)
volLbl(int pct) =>
    pct >= 75 ? "EXTREME · " + str.tostring(pct) + "%" :
     pct >= 50 ? "ELEVATED · " + str.tostring(pct) + "%" :
     pct >= 25 ? "NORMAL · " + str.tostring(pct) + "%" :
     "LOW · " + str.tostring(pct) + "%"

// Net Score percentile label — where today's reading ranks vs. its own trailing history
netPctileLbl(int pct) =>
    pct >= 90 ? "EXTREME HIGH · " + str.tostring(pct) + "%" :
     pct >= 75 ? "HIGH · " + str.tostring(pct) + "%" :
     pct >= 25 ? "TYPICAL · " + str.tostring(pct) + "%" :
     pct >= 10 ? "LOW · " + str.tostring(pct) + "%" :
     "EXTREME LOW · " + str.tostring(pct) + "%"

// Strength bar (5 dots)
strBar(int sc) =>
    a = math.abs(sc)
    a >= 4 ? "● ● ● ● ●" : a >= 3 ? "● ● ● ● ○" : a >= 2 ? "● ● ● ○ ○" : a >= 1 ? "● ● ○ ○ ○" : "○ ○ ○ ○ ○"

// Score text with sign
scoreTxt(int sc) =>
    (sc > 0 ? "+" : "") + str.tostring(sc)

// Percentage text with sign
pctTxt(int pct) =>
    (pct > 0 ? "+" : "") + str.tostring(pct) + "%"

// TF display name
tfN(simple string tf) =>
    switch tf
        "1"   => "1m"
        "3"   => "3m"
        "5"   => "5m"
        "15"  => "15m"
        "30"  => "30m"
        "45"  => "45m"
        "60"  => "1H"
        "120" => "2H"
        "180" => "3H"
        "240" => "4H"
        "1D"  => "Daily"
        "1W"  => "Weekly"
        "1M"  => "Monthly"
        => tf

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// CHART OVERLAY
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

cEF = #42A5F5
cEM = #FFA726
cES = #EF5350

eFCol = bullStack ? cBS : bearStack ? cRS : cEF
eMCol = bullStack ? cBS : bearStack ? cRS : cEM
eSCol = bullStack ? color.new(cBS, 40) : bearStack ? color.new(cRS, 40) : color.new(cES, 40)

pF = plot(emaF, "EMA Fast", color=eFCol, linewidth=2)
pM = plot(emaM, "EMA Mid", color=eMCol, linewidth=2)
pS = plot(emaS, "EMA Slow", color=eSCol, linewidth=3)

ribC = bullStack ? color.new(cBS, 85) : bearStack ? color.new(cRS, 85) : color.new(cN, 93)
fill(pF, pM, color=i_emaFill ? ribC : na, title="EMA Ribbon")

stC = stBull ? cBS : cRS
plot(i_stShow ? stValue : na, "Supertrend", color=stC, linewidth=2, style=plot.style_linebr)
plotshape(i_stShow and stFlipBull, "ST↑", shape.triangleup, location.belowbar, cBS, size=size.tiny)
plotshape(i_stShow and stFlipBear, "ST↓", shape.triangledown, location.abovebar, cRS, size=size.tiny)

// Vol Stop — plotted as circles so it reads as a secondary/slower stop, distinct from the solid Supertrend line
plot(i_vsShow and vsDir == 1 ? vsLongStop : na, "Vol Stop (Long)", color=cBS, style=plot.style_circles, linewidth=2)
plot(i_vsShow and vsDir == -1 ? vsShortStop : na, "Vol Stop (Short)", color=cRS, style=plot.style_circles, linewidth=2)
plotshape(i_vsShow and vsFlipBull, "VS↑", shape.diamond, location.belowbar, cBS, size=size.tiny)
plotshape(i_vsShow and vsFlipBear, "VS↓", shape.diamond, location.abovebar, cRS, size=size.tiny)

// Heikin-Ashi last candle color — marker shown only on the current/last bar
plotshape(barstate.islast and haBull, "HA Bullish", shape.square, location.belowbar, cBS, size=size.small)
plotshape(barstate.islast and not haBull, "HA Bearish", shape.square, location.abovebar, cRS, size=size.small)

if i_showCross and goldenCross
    label.new(bar_index, emaS, "GC", color=color.new(cBS, 20), textcolor=color.white, style=label.style_label_up, size=size.small)
if i_showCross and deathCross
    label.new(bar_index, emaS, "DC", color=color.new(cRS, 20), textcolor=color.white, style=label.style_label_down, size=size.small)

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// MTF HEATMAP TABLE — Professional Layout
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

tPos = switch i_hmPos
    "Top Right"    => position.top_right
    "Top Left"     => position.top_left
    "Bottom Right" => position.bottom_right
    "Bottom Left"  => position.bottom_left
    "Middle Right" => position.middle_right
    "Middle Left"  => position.middle_left
    => position.middle_right

tSz = switch i_hmSize
    "Tiny"   => size.tiny
    "Small"  => size.small
    "Normal" => size.normal
    "Large"  => size.large
    "Huge"   => size.huge
    => size.normal

hSz = switch i_hmSize
    "Tiny"   => size.tiny
    "Small"  => size.tiny
    "Normal" => size.small
    "Large"  => size.normal
    "Huge"   => size.large
    => size.small

// Table colors
cDark  = color.new(#0d1117, 0)
cRow1  = color.new(#161b22, 0)
cRow2  = color.new(#0d1117, 0)
cBrd   = color.new(#21262d, 0)
cHead  = color.new(#1c2128, 0)
cDim   = color.new(#6e7681, 0)
cWht   = color.new(#e6edf3, 0)
cWhtD  = color.new(#8b949e, 0)

// Section header colors
cSecBlue   = color.new(#1f3a5f, 0)
cSecPurple = color.new(#3b1f5f, 0)
cSecTeal   = color.new(#1a3f3f, 0)
cSecGold   = color.new(#3f351a, 0)
cSecOrange = color.new(#4a2a10, 0)

if i_showHM and barstate.islast
    var tbl = table.new(tPos, 5, 21, bgcolor=cDark, border_width=1, border_color=cBrd, frame_width=2, frame_color=color.new(#30363d, 0))

    // ── ROW 0 — Title ──
    table.cell(tbl, 0, 0, "  T R E N D   E N G I N E  ", text_color=cWht, text_size=hSz, bgcolor=color.new(#010409, 0), text_halign=text.align_center)
    table.merge_cells(tbl, 0, 0, 4, 0)

    // ── ROW 1 — TF Headers ──
    table.cell(tbl, 0, 1, "",           text_color=cDim, text_size=hSz, bgcolor=cHead, text_halign=text.align_center)
    table.cell(tbl, 1, 1, tfN(i_tf1),   text_color=cWht, text_size=hSz, bgcolor=cHead, text_halign=text.align_center)
    table.cell(tbl, 2, 1, tfN(i_tf2),   text_color=cWht, text_size=hSz, bgcolor=cHead, text_halign=text.align_center)
    table.cell(tbl, 3, 1, tfN(i_tf3),   text_color=cWht, text_size=hSz, bgcolor=cHead, text_halign=text.align_center)
    table.cell(tbl, 4, 1, tfN(i_tf4),   text_color=cWht, text_size=hSz, bgcolor=cHead, text_halign=text.align_center)

    // ── ROW 2 — Section: STRUCTURE ──
    table.cell(tbl, 0, 2, "  S T R U C T U R E  ", text_color=color.new(cEF, 0), text_size=size.tiny, bgcolor=cSecBlue, text_halign=text.align_center)
    table.merge_cells(tbl, 0, 2, 4, 2)

    // ── ROW 3 — EMA Stack ──
    table.cell(tbl, 0, 3, " EMA Stack ", text_color=cEF, text_size=tSz, bgcolor=cRow1, text_halign=text.align_left)
    table.cell(tbl, 1, 3, emaLbl(int(e1)), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(int(e1), 2), 25), text_halign=text.align_center)
    table.cell(tbl, 2, 3, emaLbl(int(e2)), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(int(e2), 2), 25), text_halign=text.align_center)
    table.cell(tbl, 3, 3, emaLbl(int(e3)), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(int(e3), 2), 25), text_halign=text.align_center)
    table.cell(tbl, 4, 3, emaLbl(int(e4)), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(int(e4), 2), 25), text_halign=text.align_center)

    // ── ROW 4 — Price vs EMA 200 ──
    table.cell(tbl, 0, 4, " Price/200 ", text_color=cWhtD, text_size=tSz, bgcolor=cRow2, text_halign=text.align_left)
    table.cell(tbl, 1, 4, p200Lbl(int(p1)), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(int(p1), 1), 35), text_halign=text.align_center)
    table.cell(tbl, 2, 4, p200Lbl(int(p2)), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(int(p2), 1), 35), text_halign=text.align_center)
    table.cell(tbl, 3, 4, p200Lbl(int(p3)), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(int(p3), 1), 35), text_halign=text.align_center)
    table.cell(tbl, 4, 4, p200Lbl(int(p4)), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(int(p4), 1), 35), text_halign=text.align_center)

    // ── ROW 5 — Section: DIRECTION ──
    table.cell(tbl, 0, 5, "  D I R E C T I O N  ", text_color=color.new(#AB47BC, 0), text_size=size.tiny, bgcolor=cSecPurple, text_halign=text.align_center)
    table.merge_cells(tbl, 0, 5, 4, 5)

    // ── ROW 6 — Supertrend ──
    table.cell(tbl, 0, 6, " SuperTrend ", text_color=#AB47BC, text_size=tSz, bgcolor=cRow1, text_halign=text.align_left)
    table.cell(tbl, 1, 6, stLbl(int(s1)), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(int(s1), 1), 25), text_halign=text.align_center)
    table.cell(tbl, 2, 6, stLbl(int(s2)), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(int(s2), 1), 25), text_halign=text.align_center)
    table.cell(tbl, 3, 6, stLbl(int(s3)), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(int(s3), 1), 25), text_halign=text.align_center)
    table.cell(tbl, 4, 6, stLbl(int(s4)), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(int(s4), 1), 25), text_halign=text.align_center)

    // ── ROW 7 — Vol Stop ──
    table.cell(tbl, 0, 7, " Vol Stop ", text_color=#AB47BC, text_size=tSz, bgcolor=cRow2, text_halign=text.align_left)
    table.cell(tbl, 1, 7, stLbl(int(vs1)), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(int(vs1), 1), 25), text_halign=text.align_center)
    table.cell(tbl, 2, 7, stLbl(int(vs2)), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(int(vs2), 1), 25), text_halign=text.align_center)
    table.cell(tbl, 3, 7, stLbl(int(vs3)), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(int(vs3), 1), 25), text_halign=text.align_center)
    table.cell(tbl, 4, 7, stLbl(int(vs4)), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(int(vs4), 1), 25), text_halign=text.align_center)

    // ── ROW 8 — HA Candle ──
    table.cell(tbl, 0, 8, " HA Candle ", text_color=#AB47BC, text_size=tSz, bgcolor=cRow1, text_halign=text.align_left)
    table.cell(tbl, 1, 8, stLbl(int(ha1)), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(int(ha1), 1), 25), text_halign=text.align_center)
    table.cell(tbl, 2, 8, stLbl(int(ha2)), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(int(ha2), 1), 25), text_halign=text.align_center)
    table.cell(tbl, 3, 8, stLbl(int(ha3)), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(int(ha3), 1), 25), text_halign=text.align_center)
    table.cell(tbl, 4, 8, stLbl(int(ha4)), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(int(ha4), 1), 25), text_halign=text.align_center)

    // ── ROW 9 — Section: VOLUME ──
    table.cell(tbl, 0, 9, "  V O L U M E   F L O W  ", text_color=color.new(#26A69A, 0), text_size=size.tiny, bgcolor=cSecTeal, text_halign=text.align_center)
    table.merge_cells(tbl, 0, 9, 4, 9)

    // ── ROW 10 — OBV Flow ──
    table.cell(tbl, 0, 10, " OBV Flow ", text_color=#26A69A, text_size=tSz, bgcolor=cRow1, text_halign=text.align_left)
    table.cell(tbl, 1, 10, obvFlowLbl(int(oa1), int(os1)), text_color=cWht, text_size=tSz, bgcolor=color.new(obvFlowCol(int(oa1), int(os1)), 25), text_halign=text.align_center)
    table.cell(tbl, 2, 10, obvFlowLbl(int(oa2), int(os2)), text_color=cWht, text_size=tSz, bgcolor=color.new(obvFlowCol(int(oa2), int(os2)), 25), text_halign=text.align_center)
    table.cell(tbl, 3, 10, obvFlowLbl(int(oa3), int(os3)), text_color=cWht, text_size=tSz, bgcolor=color.new(obvFlowCol(int(oa3), int(os3)), 25), text_halign=text.align_center)
    table.cell(tbl, 4, 10, obvFlowLbl(int(oa4), int(os4)), text_color=cWht, text_size=tSz, bgcolor=color.new(obvFlowCol(int(oa4), int(os4)), 25), text_halign=text.align_center)

    // ── ROW 11 — Section: VOLATILITY ──
    table.cell(tbl, 0, 11, "  V O L A T I L I T Y  ", text_color=color.new(#FFAB40, 0), text_size=size.tiny, bgcolor=cSecOrange, text_halign=text.align_center)
    table.merge_cells(tbl, 0, 11, 4, 11)

    // ── ROW 12 — ATR Percentile Regime ──
    table.cell(tbl, 0, 12, " Volatility ", text_color=#FFAB40, text_size=tSz, bgcolor=cRow1, text_halign=text.align_left)
    table.cell(tbl, 1, 12, volLbl(ap1), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(v1, 2), 25), text_halign=text.align_center)
    table.cell(tbl, 2, 12, volLbl(ap2), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(v2, 2), 25), text_halign=text.align_center)
    table.cell(tbl, 3, 12, volLbl(ap3), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(v3, 2), 25), text_halign=text.align_center)
    table.cell(tbl, 4, 12, volLbl(ap4), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(v4, 2), 25), text_halign=text.align_center)

    // ── ROW 13 — Section: CONFLUENCE ──
    table.cell(tbl, 0, 13, "  C O N F L U E N C E  ", text_color=color.new(#FFB74D, 0), text_size=size.tiny, bgcolor=cSecGold, text_halign=text.align_center)
    table.merge_cells(tbl, 0, 13, 4, 13)

    // ── ROW 14 — Score ──
    table.cell(tbl, 0, 14, " Score ", text_color=cWht, text_size=tSz, bgcolor=cRow1, text_halign=text.align_left)
    table.cell(tbl, 1, 14, scoreTxt(t1), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(t1, 6), 15), text_halign=text.align_center)
    table.cell(tbl, 2, 14, scoreTxt(t2), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(t2, 6), 15), text_halign=text.align_center)
    table.cell(tbl, 3, 14, scoreTxt(t3), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(t3, 6), 15), text_halign=text.align_center)
    table.cell(tbl, 4, 14, scoreTxt(t4), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(t4, 6), 15), text_halign=text.align_center)

    // ── ROW 15 — Strength Bar ──
    table.cell(tbl, 0, 15, " Strength ", text_color=cWhtD, text_size=tSz, bgcolor=cRow2, text_halign=text.align_left)
    table.cell(tbl, 1, 15, strBar(t1), text_color=hmCol(t1, 6), text_size=tSz, bgcolor=cRow2, text_halign=text.align_center)
    table.cell(tbl, 2, 15, strBar(t2), text_color=hmCol(t2, 6), text_size=tSz, bgcolor=cRow2, text_halign=text.align_center)
    table.cell(tbl, 3, 15, strBar(t3), text_color=hmCol(t3, 6), text_size=tSz, bgcolor=cRow2, text_halign=text.align_center)
    table.cell(tbl, 4, 15, strBar(t4), text_color=hmCol(t4, 6), text_size=tSz, bgcolor=cRow2, text_halign=text.align_center)

    // ── ROW 16 — Regime (volatility-discounted) ──
    dT1r = int(math.round(dT1))
    dT2r = int(math.round(dT2))
    dT3r = int(math.round(dT3))
    dT4r = int(math.round(dT4))
    table.cell(tbl, 0, 16, " Regime ", text_color=cWht, text_size=tSz, bgcolor=cRow1, text_halign=text.align_left)
    table.cell(tbl, 1, 16, regLbl(dT1r), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(dT1r, 6), 10), text_halign=text.align_center)
    table.cell(tbl, 2, 16, regLbl(dT2r), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(dT2r, 6), 10), text_halign=text.align_center)
    table.cell(tbl, 3, 16, regLbl(dT3r), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(dT3r, 6), 10), text_halign=text.align_center)
    table.cell(tbl, 4, 16, regLbl(dT4r), text_color=cWht, text_size=tSz, bgcolor=color.new(hmCol(dT4r, 6), 10), text_halign=text.align_center)

    // ── ROW 17 — Net Score (weighted % of max, Daily & Weekly count 2x) ──
    netCol = color.new(hmCol(int(math.round(netScore)), netScoreMax), 10)
    table.cell(tbl, 0, 17, " Net Score ", text_color=cWht, text_size=tSz, bgcolor=cSecGold, text_halign=text.align_left)
    table.cell(tbl, 1, 17, pctTxt(netScorePct), text_color=cWht, text_size=tSz, bgcolor=netCol, text_halign=text.align_center)
    table.merge_cells(tbl, 1, 17, 4, 17)

    // ── ROW 18 — Net Score Percentile (vs. its own trailing history) ──
    netPctileSigned = int(math.round((netScorePctile - 50) * 2))   // rescale 0-100 to -100..100 for hmCol
    netPctileCol    = color.new(hmCol(netPctileSigned, 100), 10)
    table.cell(tbl, 0, 18, " Net %ile ", text_color=cWht, text_size=tSz, bgcolor=cRow2, text_halign=text.align_left)
    table.cell(tbl, 1, 18, netPctileLbl(netScorePctile), text_color=cWht, text_size=tSz, bgcolor=netPctileCol, text_halign=text.align_center)
    table.merge_cells(tbl, 1, 18, 4, 18)

    // ── ROW 19 — Divider ──
    for col = 0 to 4
        table.cell(tbl, col, 19, "", bgcolor=color.new(#30363d, 0), text_size=size.tiny)

    // ── ROW 20 — MTF Alignment Summary ──
    alignText = bullTFs == 4 ? "◆ 4/4 BULLISH — Full alignment" :
     bullTFs == 3 ? "▲ 3/4 BULLISH — Strong alignment" :
     bearTFs == 4 ? "◆ 4/4 BEARISH — Full alignment" :
     bearTFs == 3 ? "▼ 3/4 BEARISH — Strong alignment" :
     bullTFs == 2 and bearTFs == 2 ? "◆ SPLIT 2/2 — No clear bias" :
     bullTFs > bearTFs ? "▲ " + str.tostring(bullTFs) + "/4 Bullish — Partial" :
     bearTFs > bullTFs ? "▼ " + str.tostring(bearTFs) + "/4 Bearish — Partial" :
     "◆ MIXED — Wait for clarity"

    alignCol = bullTFs >= 3 ? cBS : bearTFs >= 3 ? cRS : cN
    table.cell(tbl, 0, 20, alignText, text_color=alignCol, text_size=hSz, bgcolor=color.new(#010409, 0), text_halign=text.align_center)
    table.merge_cells(tbl, 0, 20, 4, 20)

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// ALERTS
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

alertcondition(trendChanged and isStrongBull, "Strong bullish", "Trend Engine: STRONG BULLISH — All components aligned.")
alertcondition(trendChanged and isStrongBear, "Strong bearish", "Trend Engine: STRONG BEARISH — All components aligned.")
alertcondition(goldenCross, "Golden cross", "Trend Engine: GOLDEN CROSS detected.")
alertcondition(deathCross, "Death cross", "Trend Engine: DEATH CROSS detected.")
alertcondition(stFlipBull, "ST flip bull", "Trend Engine: Supertrend flipped BULLISH.")
alertcondition(stFlipBear, "ST flip bear", "Trend Engine: Supertrend flipped BEARISH.")
alertcondition(vsFlipBull, "Vol Stop flip bull", "Trend Engine: Vol Stop flipped BULLISH.")
alertcondition(vsFlipBear, "Vol Stop flip bear", "Trend Engine: Vol Stop flipped BEARISH.")
alertcondition(trendChanged, "Trend change", "Trend Engine: Classification changed — check heatmap.")

Overview

On-balance volume trend and a volatility-percentile regime feed a scoring step, and a multi-timeframe heatmap table shows the combined reading across four chosen timeframes. Golden-cross and death-cross labels can be shown. Settings cover EMA lengths, Supertrend factor, stop multiplier, OBV smoothing, volatility discounts, heatmap timeframes and table position.

Details

Published by

vedkanani123 on GitHub

Draws

On the price chart

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
Fast EMAint21i_emaFast
Mid EMAint50i_emaMid
Slow EMAint200i_emaSlow
Show ribbon fillbooltruei_emaFill
Factorfloat3.0i_stFactor
ATR Periodint10i_stAtr
Show Supertrend linebooltruei_stShow
ATR Periodint20i_vsAtrLen
ATR Multiplierfloat3.25i_vsMult
Show Vol Stop linebooltruei_vsShow
OBV MA Lengthint20i_obvMaLen
Slope lookbackint5i_obvLook
Show all 27 settings
SettingTypeDefaultVariable
ATR Lengthint14i_volAtrLen
Percentile Lookbackint100i_volLook
Discount — Low Volfloat1.00i_discLow
Discount — Normal Volfloat1.00i_discNormal
Discount — Elevated Volfloat0.75i_discElevated
Discount — Extreme Volfloat0.50i_discExtreme
Timeframe 1timeframe60i_tf1
Timeframe 2timeframe1Di_tf2
Timeframe 3timeframe1Wi_tf3
Timeframe 4timeframe1Mi_tf4
Show heatmapbooltruei_showHM
Net Score Percentile Lookbackint100i_netPctLook
PositionstringMiddle Righti_hmPos
Text sizestringNormali_hmSize
Show GC / DC labelsbooltruei_showCross
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

Snagprofit WMA MA

by dearvn
4 stars

Snagprofit WMA MA calculates and plots weighted moving averages across multiple timeframes (1-minute, 5-minute, 15-minute, and 1-hour) alongside a chart-period simple moving average. It evaluates directional alignment between these moving averages and checks f

Indicator v5 Moving averagesTrend Repaints
Updated 4 years ago · None stated GitHub repository of Snagprofit WMA MA

EMA-Volume

by engtuncay
1 stars

EMA-Volume calculates two Exponential Moving Averages alongside volume moving averages derived from scaled USD volume. It draws directly on the price chart, plotting both moving averages with bullish and bearish crossover markers and colored background highlig

Indicator v6 Moving averagesTrend
Updated 6 days ago · None stated GitHub repository of EMA-Volume
1 stars

This indicator plots a ribbon of seven exponential moving averages based on Fibonacci lengths (8, 13, 21, 34, 55, 89, and 144) directly on the price chart. It calculates volume-weighted distance gaps between consecutive moving averages normalized against a 50-

Indicator v5 Moving averagesTrend
Updated 7 weeks ago · None stated GitHub repository of Fibonacci Volumetric MA Ribbon
228 stars

TradersPost Trading Checklist is an overlay indicator that evaluates a suite of popular technical conditions for long and short trade setups. It checks session-anchored VWAP, fast and slow EMA alignments and crosses, 200 SMA, RSI overbought or oversold conditi

Indicator v6 Screeners & dashboardsTrend
Updated 3 months ago · None stated GitHub repository of TradersPost Trading Checklist

Adaptive MA Slope

by capissimo
114 stars

This indicator calculates Kaufman's Adaptive Moving Average (KAMA) on a chosen price source and determines trend direction based on the slope across a configurable lookback window. Signals can be filtered by short-term volatility expansion using ATR comparison

Indicator v4 Moving averagesTrend
Updated 1 year ago · None stated GitHub repository of Adaptive MA Slope
92 stars

This indicator plots five moving averages of a chosen source on the price chart, defaulting to EMA lengths 10, 20, 30, 40 and 50. The user can switch the average type to SMA, WMA or HMA and recolor each line. Wide translucent glows sit under the lines, and sof

Indicator v5 TrendMoving averages
Updated 2 months ago · Custom licence GitHub repository of Moon Dev Rainbow MA Ribbon 10-50

More Trend scripts

Related on ForexR

Trade Your Charts With a Regulated Broker

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

Compare brokers