Indicator · Pine Script v6 · On the chart

Wirezard Wave Rider

by udhansingh· code credited to wirezard

An overlay that combines ADX, RSI, an impulse MACD, VIDYA and volume to draw buy and sell markers, swing pivot labels, divergence markers and Fibonacci levels.

View on GitHub

GitHub stars1on the repository
Pine versionv6current
Lines of code808
Settings40inputs
LicenceMIT
Last update7 months ago16 Mar 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

808 lines of Pine Script v6 from WirezardWaveRider.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

WirezardWaveRider.pine
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © wirezard

//@version=6
indicator("Wirezard Wave Rider", overlay=true, max_bars_back=500, max_labels_count=500, max_lines_count=500)

// ============================================================================
// V14 CHANGELOG (from V13):
// 1. EXHSELL FALSE SIGNAL FIX — trendExhaustionSell was firing at correction
//      bottoms (buy zones). Two guards added:
//      • not bullishDivergence — mirrors the guard already in strongSell; blocks
//        EXH SELL when price is printing a lower low + higher RSI/MACD (buy setup).
//      • rsi < rsi[3] — RSI must be DECLINING to confirm true exhaustion; prevents
//        firing when RSI is recovering from oversold (rising through the ceiling).
// 2. All V13 signal shapes, inputs, tolerance bands unchanged.
//
// V13 CHANGELOG (from V12):
// 1. DIVERGENCE SIGNALS PROMOTED — bearishDivergence-based sells (divergenceSell,
//      waveTopSell) now show as red "SELL" (same visual as strongSell).
//      correctionBuy with strongBullDiv now shows as large green "BUY" (same as
//      strongBuy). Eliminates confusing purple DIV↓ / teal DIV↑ trigger shapes.
// 2. SIGNAL SHAPES SIMPLIFIED — 6 plotshape calls reduced to 4:
//      • Strong BUY  (size.normal) — strongBuy OR correctionBuy + strongBullDiv
//      • Moderate BUY (size.small) — correctionBuy without strong divergence
//      • Strong SELL (size.normal) — strongSell OR divergenceSell OR waveTopSell
//      • Moderate SELL (size.small) — trendExhaustionSell only
// 3. All V12 inputs, tolerance bands, swing labels, and signal logic unchanged.
//
// V12 CHANGELOG (from V11):
// 1. INPUT SIMPLIFICATION — 41 params reorganised into 3 tiers:
//      ⚙️ Simple        (7 params)  — display & early-detection toggles
//      📊 Intermediate  (7 params)  — key ADX / RSI / Volume / Cooldown thresholds
//      🔬 Advanced      (31 params) — VIDYA, MTF weights, Fib, IMACD fine-tuning
// 2. SIGNAL TOLERANCE BANDS — ±sigTolPct% price zone drawn after every trigger.
// 3. SWING LABELS CONVERTED — SH/SL → "Sell"/"Buy" toggle in ⚙️ Simple.
// 4. LAG REDUCTION — pivotRight default 5→3; dashboard LAG row; EXH text bug fix.
// ============================================================================

// ─────────────────────────────────────────────────────────────────────────────
// ⚙️ SIMPLE  — 7 inputs (beginners start here)
// ─────────────────────────────────────────────────────────────────────────────

bool  autoMTF            = input.bool(true,  "Auto-detect MTF Timeframes",
     group="⚙️ Simple",
     tooltip="ON: uses 2×, 4×, 8× chart timeframe automatically.\nOFF: set timeframes manually in 🔬 Advanced → MTF.")

bool  showFibs           = input.bool(true,  "Show Fibonacci Levels",
     group="⚙️ Simple")

bool  showSwings         = input.bool(true,  "Show Swing Signals",
     group="⚙️ Simple",
     tooltip="Draws a label at every confirmed pivot high/low.")

bool  swingAsBuySell     = input.bool(true,  "Swing Labels: Buy / Sell  (OFF = SH / SL)",
     group="⚙️ Simple",
     tooltip="ON: swing high → 'Sell', swing low → 'Buy'.\nOFF: classic SH / SL labels.\nNote: these are structural signals, not the same as BUY/SELL trigger shapes.")

bool  showDiverg         = input.bool(true,  "Show Divergence Markers",
     group="⚙️ Simple")

bool  enableEarlyBottomBuy  = input.bool(true, "Early Bottom Detection",
     group="⚙️ Simple",
     tooltip="Relaxes Correction Buy conditions — catches wave 2/4/C bottoms 1-3 bars earlier by allowing VIDYA flattening and RSI crossover instead of full VIDYA reversal.")

bool  enableEarlyWaveTopSell = input.bool(true, "Early Top Detection",
     group="⚙️ Simple",
     tooltip="Relaxes Wave Top / Divergence Sell — fires at wave 5 and wave B peaks before VIDYA fully reverses. Pairs with the ±% Tolerance Band below.")

// ─────────────────────────────────────────────────────────────────────────────
// 📊 INTERMEDIATE  — 7 inputs (key signal thresholds)
// ─────────────────────────────────────────────────────────────────────────────

int   adxThreshold   = input.int(18,    "ADX Threshold — BUY / EXH signals",
     group="📊 Intermediate", minval=5, maxval=60,
     tooltip="Minimum ADX strength required for BUY and EXH sells. Below this ADX the market is ranging — signals are filtered out.")

int   strongAdxInp   = input.int(25,    "ADX Threshold — SELL reversal",
     group="📊 Intermediate", minval=10, maxval=60,
     tooltip="Minimum ADX for the strong SELL (tier 1 reversal). Higher = more selective, fewer but cleaner reversal signals.")

float volMult        = input.float(1.2, "Volume Multiplier",
     group="📊 Intermediate", minval=0.5, maxval=5.0, step=0.1,
     tooltip="Volume must exceed this multiple of its moving average to confirm a signal. 1.2 = 20% above average.")

float rsiOverbought  = input.float(75.0,"RSI Overbought Guard  (BUY block)",
     group="📊 Intermediate", minval=60, maxval=95, step=1,
     tooltip="BUY signals are suppressed when RSI is above this level (price already extended up — risk of buying a wave 5 top).")

float rsiOversold    = input.float(35.0,"RSI Oversold Guard  (SELL block)",
     group="📊 Intermediate", minval=5, maxval=45, step=1,
     tooltip="SELL signals are suppressed when RSI is below this level (prevents selling into a wave C capitulation bottom).")

int   sellCooldown   = input.int(15,    "Sell Cooldown Bars",
     group="📊 Intermediate", minval=1, maxval=50,
     tooltip="Minimum bars between consecutive SELL triggers. Prevents EXH / DIV / TOP signals clustering when conditions flicker.")

float sigTolPct      = input.float(5.0, "Signal Tolerance ± %",
     group="📊 Intermediate", minval=1.0, maxval=15.0, step=0.5,
     tooltip="After a BUY or SELL triggers, a ±% price band is drawn. Entry/exit is considered valid while price stays inside the band.\n\nWhy 5%? Pivot confirmation (pivotRight bars) creates 1-3 bar lag. On typical crypto, that equals 2-6% price movement. The band makes the valid entry zone visible and accounts for bar-close execution delay.\n\nBand expires when the next opposite signal fires.")

// ─────────────────────────────────────────────────────────────────────────────
// 🔬 ADVANCED  — fine-tuning for experienced users (27 inputs)
// ─────────────────────────────────────────────────────────────────────────────

// ── Indicator Internals ──────────────────────────────────────────────────────
int   adxLen       = input.int(14,    "ADX Length",
     group="🔬 Advanced: Indicator", minval=5, maxval=30)
int   volLen       = input.int(20,    "Volume MA Length",
     group="🔬 Advanced: Indicator")
int   imacdLen     = input.int(34,    "Impulse MACD Length",
     group="🔬 Advanced: Indicator")
int   imacdSmth    = input.int(9,     "Impulse MACD Smooth",
     group="🔬 Advanced: Indicator")
int   imacdSig     = input.int(9,     "Impulse MACD Signal",
     group="🔬 Advanced: Indicator")
int   vidyaSmooth  = input.int(12,    "VIDYA Smoothing",
     group="🔬 Advanced: Indicator")
int   pivotLeft    = input.int(10,    "Pivot Lookback Left",
     group="🔬 Advanced: Indicator", minval=3,
     tooltip="Bars to the left of a pivot to confirm it is a local high/low.")
int   pivotRight   = input.int(3,     "Pivot Lookback Right  ← lag control",
     group="🔬 Advanced: Indicator", minval=1, maxval=10,
     tooltip="Bars to the right of a pivot before it is confirmed.\n\nLower = earlier swing labels, less lag — but more false pivots.\nHigher = cleaner pivots, more lag.\n\nDefault changed 5 → 3 in V10 to reduce typical 5-bar swing-label delay.\nThe ±% Tolerance Band in 📊 Intermediate absorbs the remaining lag.\n\nSet to 1 for maximum speed; set to 5-7 for maximum confidence.")

// ── MTF Timeframes (manual override when autoMTF = OFF) ─────────────────────
string manualTf1   = input.timeframe("120", "Short TF  (manual override)",
     group="🔬 Advanced: MTF",
     tooltip="Active only when 'Auto-detect MTF' is OFF in ⚙️ Simple.")
string manualTf2   = input.timeframe("240", "Medium TF (manual override)",
     group="🔬 Advanced: MTF")
string manualTf3   = input.timeframe("480", "Long TF   (manual override)",
     group="🔬 Advanced: MTF")

// ── MTF Weights ──────────────────────────────────────────────────────────────
float w2h = input.float(3.0, "Short TF Weight",
     group="🔬 Advanced: MTF", minval=0.5, maxval=5.0, step=0.5,
     tooltip="Composite score = score2h×w2h + score4h×w4h + score8h×w8h. Range ±30 with default weights 3/2/1.")
float w4h = input.float(2.0, "Medium TF Weight",
     group="🔬 Advanced: MTF", minval=0.5, maxval=5.0, step=0.5)
float w8h = input.float(1.0, "Long TF Weight",
     group="🔬 Advanced: MTF", minval=0.5, maxval=5.0, step=0.5)

// ── MTF Score Thresholds ─────────────────────────────────────────────────────
float mtfBullStrongThr   = input.float(16.0, "Bull Confirmed Score",
     group="🔬 Advanced: MTF", minval=0, maxval=30, step=0.5,
     tooltip="Composite MTF score needed for STRONG BUY (range ±30 with default weights).")
float mtfBullModerateThr = input.float( 8.0, "Bull Moderate Score",
     group="🔬 Advanced: MTF", minval=0, maxval=30, step=0.5,
     tooltip="Composite score for CORRECTION BUY.")
float mtfBearStrongThr   = input.float(16.0, "Bear Confirmed Score",
     group="🔬 Advanced: MTF", minval=0, maxval=30, step=0.5,
     tooltip="Score needed for SELL reversal (applied as negative).")
float mtfBearModerateThr = input.float( 8.0, "Bear Moderate Score",
     group="🔬 Advanced: MTF", minval=0, maxval=30, step=0.5,
     tooltip="Score for EXH and DIV signals (applied as negative).")
float mtfBearLocalThr    = input.float( 3.0, "Bear Local 2H Score",
     group="🔬 Advanced: MTF", minval=0, maxval=5, step=0.5,
     tooltip="2H individual score threshold for mtfBearLocal (range ±5).")

// ── VIDYA Thresholds ─────────────────────────────────────────────────────────
int   vidyaTrendLB  = input.int(3,    "Trend Lookback Bars",
     group="🔬 Advanced: VIDYA", minval=1, maxval=10,
     tooltip="vidya > vidya[N] — bars back used to determine rising/falling trend.")
int   vidyaSlopeLB  = input.int(5,    "Slope Lookback Bars",
     group="🔬 Advanced: VIDYA", minval=2, maxval=20,
     tooltip="Bars used to compute slope percentage.")
float vidyaSteepPct = input.float(0.5,"Steep Slope Threshold %",
     group="🔬 Advanced: VIDYA", minval=0.1, maxval=3.0, step=0.1,
     tooltip="Minimum slope % to qualify as a steep trend.")
float vidyaFlatPct  = input.float(0.2,"Flat Threshold %",
     group="🔬 Advanced: VIDYA", minval=0.0, maxval=1.0, step=0.05,
     tooltip="Max slope % for VIDYA to be considered flattening (used in divergence confirmation).")

// ── Signal Fine-Tuning ────────────────────────────────────────────────────────
float corrBuyRsiMin = input.float(30.0,"COR Buy RSI Min",
     group="🔬 Advanced: Signals", minval=10, maxval=50, step=1,
     tooltip="Correction Buy: RSI must be above this (not in freefall).")
float corrBuyRsiMax = input.float(55.0,"COR Buy RSI Max",
     group="🔬 Advanced: Signals", minval=40, maxval=70, step=1,
     tooltip="Correction Buy: RSI must be below this (coming from oversold).")
float exhRsiCeil    = input.float(45.0,"EXH Sell RSI Ceiling",
     group="🔬 Advanced: Signals", minval=30, maxval=65, step=1,
     tooltip="EXH signal: RSI must be below this value (mid-trend exhaustion, not at a top).")
float divRsiFloor   = input.float(55.0,"DIV Sell RSI Floor",
     group="🔬 Advanced: Signals", minval=40, maxval=70, step=1,
     tooltip="DIV signal: RSI must be above this (selling near a top, not mid-range).")
float divRsiCeil    = input.float(75.0,"DIV Sell RSI Ceiling",
     group="🔬 Advanced: Signals", minval=60, maxval=90, step=1,
     tooltip="DIV signal: RSI must be below this (not in a blowoff spike — wait for rollover).")
float fibProxPct    = input.float(1.0, "Fib Proximity %",
     group="🔬 Advanced: Signals", minval=0.1, maxval=5.0, step=0.1,
     tooltip="Price must be within this % of a Fibonacci level to qualify as 'at fib zone'.")
int   localHighBars = input.int(10,   "Local High Lookback",
     group="🔬 Advanced: Signals", minval=5, maxval=30,
     tooltip="Bars for 'not at local high' check — blocks correction buy when near recent high.")
float localHighThr  = input.float(0.99,"Local High Threshold",
     group="🔬 Advanced: Signals", minval=0.95, maxval=1.01, step=0.01,
     tooltip="Block when close >= highest×this. 0.99 = within 1% of high. Set 1.01 to disable.")

// =============================================================================
// 2. CUSTOM FUNCTIONS  (unchanged from V9)
// =============================================================================

zlema(src, len) =>
    ema1 = ta.ema(src, len)
    ema2 = ta.ema(ema1, len)
    d    = ema1 - ema2
    ta.ema(ema1 + d, len)

calc_smma(src, len) =>
    var float smma = na
    sma_val        = ta.sma(src, len)
    smma := na(smma[1]) ? sma_val : (nz(smma[1]) * (len - 1) + src) / len
    smma

get_full_alert_msg(action, tier, price, adx_val, rsi_val, imacd_val, vol_ratio, divInfo) =>
    '{"ticker": "' + syminfo.tickerid +
     '", "action": "' + action +
     '", "tier": "'   + tier +
     '", "price": '   + str.tostring(price,     "#.##") +
     ', "adx": '      + str.tostring(adx_val,   "#.#")  +
     ', "rsi": '      + str.tostring(rsi_val,   "#.#")  +
     ', "imacd": '    + str.tostring(imacd_val, "#.##") +
     ', "vol_ratio": ' + str.tostring(vol_ratio, "#.##") +
     ', "divergence": "' + divInfo + '"}'

// =============================================================================
// 3. HTF FUNCTIONS  (unchanged from V9)
// =============================================================================

calc_vidya() =>
    m    = ta.change(close)
    sp   = math.sum(math.max(m,  0), 9)
    sn   = math.sum(math.max(-m, 0), 9)
    cmo_ = math.abs((sp - sn) / math.max(sp + sn, 1e-6))
    a    = 2.0 / (12.0 + 1.0)
    var float v = na
    v := na(v[1]) ? close : (a * cmo_ * close) + (1.0 - a * cmo_) * nz(v[1])
    v

calc_md() =>
    var float smhi  = na
    var float smlo  = na
    sma_hi_init     = ta.sma(high, 34)
    sma_lo_init     = ta.sma(low,  34)
    smhi := na(smhi[1]) ? sma_hi_init : (nz(smhi[1]) * 33.0 + high) / 34.0
    smlo := na(smlo[1]) ? sma_lo_init : (nz(smlo[1]) * 33.0 + low)  / 34.0
    zl   = ta.ema(ta.ema(close, 9) + (ta.ema(close, 9) - ta.ema(ta.ema(close, 9), 9)), 9)
    zl > smhi ? zl - smhi : zl < smlo ? zl - smlo : 0.0

calc_bias_score() =>
    vidya_       = calc_vidya()
    vidyaRising_ = vidya_ > vidya_[vidyaTrendLB]
    rsi_         = ta.rsi(close, 14)
    md_          = calc_md()
    volSma_      = ta.sma(volume, 20)
    volBull_     = (close > open) and (volume > volSma_)
    volBear_     = (close < open) and (volume > volSma_)
    float score  = 0.0
    score += vidyaRising_   ? 1.0 : -1.0
    score += close > vidya_ ? 1.0 : -1.0
    score += rsi_ > 50.0    ? 1.0 : -1.0
    score += md_ > 0.0      ? 1.0 : -1.0
    score += volBull_       ? 1.0 : volBear_ ? -1.0 : 0.0
    score

calc_htf_vidya_rising() =>
    v = calc_vidya()
    v > v[vidyaTrendLB]

calc_htf_vidya_above() =>
    v = calc_vidya()
    close > v

// =============================================================================
// 4. MTF BIAS — WEIGHTED SCORING  (unchanged from V9)
// =============================================================================

// Auto-compute 2×, 4×, 8× the current chart bar duration
int    chartSecs = timeframe.in_seconds(timeframe.period)
string autoTf1   = timeframe.from_seconds(chartSecs * 2)
string autoTf2   = timeframe.from_seconds(chartSecs * 4)
string autoTf3   = timeframe.from_seconds(chartSecs * 8)

string tf2h = autoMTF ? autoTf1 : manualTf1
string tf4h = autoMTF ? autoTf2 : manualTf2
string tf8h = autoMTF ? autoTf3 : manualTf3

float score2h = request.security(syminfo.tickerid, tf2h, calc_bias_score(), lookahead=barmerge.lookahead_off)
float score4h = request.security(syminfo.tickerid, tf4h, calc_bias_score(), lookahead=barmerge.lookahead_off)
float score8h = request.security(syminfo.tickerid, tf8h, calc_bias_score(), lookahead=barmerge.lookahead_off)

bool vidya2hRising = request.security(syminfo.tickerid, tf2h, calc_htf_vidya_rising(), lookahead=barmerge.lookahead_off)
bool vidya4hRising = request.security(syminfo.tickerid, tf4h, calc_htf_vidya_rising(), lookahead=barmerge.lookahead_off)
bool vidya8hRising = request.security(syminfo.tickerid, tf8h, calc_htf_vidya_rising(), lookahead=barmerge.lookahead_off)
bool vidya2hAbove  = request.security(syminfo.tickerid, tf2h, calc_htf_vidya_above(), lookahead=barmerge.lookahead_off)
bool vidya4hAbove  = request.security(syminfo.tickerid, tf4h, calc_htf_vidya_above(), lookahead=barmerge.lookahead_off)
bool vidya8hAbove  = request.security(syminfo.tickerid, tf8h, calc_htf_vidya_above(), lookahead=barmerge.lookahead_off)

int bias2h = score2h >= 4.0 ? 1 : score2h <= -4.0 ? -1 : 0
int bias4h = score4h >= 4.0 ? 1 : score4h <= -4.0 ? -1 : 0
int bias8h = score8h >= 4.0 ? 1 : score8h <= -4.0 ? -1 : 0

float mtfWeighted = score2h * w2h + score4h * w4h + score8h * w8h

int vidyaHTFBullCount = (vidya2hRising and vidya2hAbove ? 1 : 0) + (vidya4hRising and vidya4hAbove ? 1 : 0) + (vidya8hRising and vidya8hAbove ? 1 : 0)
int vidyaHTFBearCount = (not vidya2hRising and not vidya2hAbove ? 1 : 0) + (not vidya4hRising and not vidya4hAbove ? 1 : 0) + (not vidya8hRising and not vidya8hAbove ? 1 : 0)

bool mtfBullConfirmed = mtfWeighted >= mtfBullStrongThr   and vidyaHTFBullCount >= 2
bool mtfBullModerate  = mtfWeighted >= mtfBullModerateThr and vidyaHTFBullCount >= 1
bool mtfBearStrong    = mtfWeighted <= -mtfBearStrongThr  and vidyaHTFBearCount >= 1
bool mtfBearModerate  = mtfWeighted <= -mtfBearModerateThr and vidyaHTFBearCount >= 1
bool mtfBearLocal     = score2h <= -mtfBearLocalThr and not vidya2hRising

// =============================================================================
// 5. BASE TIMEFRAME CALCULATIONS  (unchanged from V9)
// =============================================================================

float mom    = ta.change(close)
float sumPos = math.sum(math.max(mom,  0), 9)
float sumNeg = math.sum(math.max(-mom, 0), 9)
float cmo    = math.abs((sumPos - sumNeg) / math.max(sumPos + sumNeg, 0.000001))
float alpha  = 2.0 / (vidyaSmooth + 1.0)
var float vidya = na
vidya := na(vidya[1]) ? close : (alpha * cmo * close) + (1.0 - alpha * cmo) * nz(vidya[1])

bool vidyaRising        = vidya > vidya[vidyaTrendLB]
bool vidyaFalling       = vidya < vidya[vidyaTrendLB]
bool priceAboveVidya    = close > vidya
bool priceBelowVidya    = close < vidya

float vidyaSlope        = (vidya - vidya[vidyaSlopeLB]) / math.max(vidya[vidyaSlopeLB], 1e-6) * 100.0
bool vidyaSteepRise     = vidyaSlope >  vidyaSteepPct
bool vidyaSteepFall     = vidyaSlope < -vidyaSteepPct
bool vidyaLostMomentum  = vidyaSlope > -vidyaSteepPct and vidyaSlope < vidyaSteepPct
bool vidyaFlattening    = vidyaLostMomentum
bool priceNearVidya     = math.abs(close - vidya) < vidya * (fibProxPct / 100.0)
bool priceCrossAboveVidya = close > vidya and close[1] <= vidya[1]

float smma_hi = calc_smma(high, imacdLen)
float smma_lo = calc_smma(low,  imacdLen)
float mi      = zlema(close, imacdSmth)
float md      = (mi > smma_hi) ? (mi - smma_hi) : (mi < smma_lo) ? (mi - smma_lo) : 0.0
float sb      = ta.sma(md, imacdSig)
float sh      = md - sb

[diplus, diminus, adx] = ta.dmi(adxLen, adxLen)
float rsi    = ta.rsi(close, 14)

// =============================================================================
// 6. VOLUME CONDITIONS  (unchanged from V9)
// =============================================================================

float volSma      = ta.sma(volume, volLen)
float volRatio    = volume / math.max(volSma, 1)
bool  volBuyConf  = (close > open) and (volRatio >= volMult)
bool  volSellConf = (close < open) and (volRatio >= volMult)
bool  volDivBear  = (high > high[1]) and (volume < volume[1]) and (volume < volSma)
bool  volDivBull  = (low < low[1])   and (volume < volume[1]) and (volume < volSma)
bool  volExpanding = volRatio >= volMult

// =============================================================================
// 7. SWING STRUCTURE  (unchanged from V9 except pivotRight default is now 3)
// =============================================================================

// LAG NOTE: pivotRight bars must pass after a swing high/low before it is confirmed.
// With pivotRight=3 (V10 default), labels appear 3 bars after the actual pivot —
// roughly 2 bars earlier than the V9 default of 5. The ±sigTolPct% band compensates
// for the remaining entry timing gap.

float pivHi = ta.pivothigh(high, pivotLeft, pivotRight)
float pivLo = ta.pivotlow(low,   pivotLeft, pivotRight)

var float swingHi1 = na
var float swingHi2 = na
var int   swingHi1Bar = na
var int   swingHi2Bar = na
var float swingLo1 = na
var float swingLo2 = na
var int   swingLo1Bar = na
var int   swingLo2Bar = na

if not na(pivHi)
    swingHi2    := swingHi1
    swingHi2Bar := swingHi1Bar
    swingHi1    := pivHi
    swingHi1Bar := bar_index - pivotRight

if not na(pivLo)
    swingLo2    := swingLo1
    swingLo2Bar := swingLo1Bar
    swingLo1    := pivLo
    swingLo1Bar := bar_index - pivotRight

bool higherHighs = not na(swingHi1) and not na(swingHi2) and (swingHi1 > swingHi2)
bool lowerHighs  = not na(swingHi1) and not na(swingHi2) and (swingHi1 < swingHi2)
bool higherLows  = not na(swingLo1) and not na(swingLo2) and (swingLo1 > swingLo2)
bool lowerLows   = not na(swingLo1) and not na(swingLo2) and (swingLo1 < swingLo2)

bool bullishStructure = higherHighs and higherLows
bool bearishStructure = lowerHighs  and lowerLows

// =============================================================================
// 8. FIBONACCI RETRACEMENT LEVELS  (unchanged from V9)
// =============================================================================

float fibRange   = nz(swingHi1) - nz(swingLo1)
bool  fibBullish = not na(swingLo1Bar) and not na(swingHi1Bar) and (swingLo1Bar > swingHi1Bar)
bool  fibBearish = not na(swingHi1Bar) and not na(swingLo1Bar) and (swingHi1Bar > swingLo1Bar)

float fib236 = fibBearish ? swingHi1 - fibRange * 0.236 : fibBullish ? swingLo1 + fibRange * 0.236 : na
float fib382 = fibBearish ? swingHi1 - fibRange * 0.382 : fibBullish ? swingLo1 + fibRange * 0.382 : na
float fib500 = fibBearish ? swingHi1 - fibRange * 0.500 : fibBullish ? swingLo1 + fibRange * 0.500 : na
float fib618 = fibBearish ? swingHi1 - fibRange * 0.618 : fibBullish ? swingLo1 + fibRange * 0.618 : na
float fib786 = fibBearish ? swingHi1 - fibRange * 0.786 : fibBullish ? swingLo1 + fibRange * 0.786 : na

float fibProximity = close * (fibProxPct / 100.0)
bool  nearFib382   = not na(fib382) and math.abs(close - fib382) < fibProximity
bool  nearFib500   = not na(fib500) and math.abs(close - fib500) < fibProximity
bool  nearFib618   = not na(fib618) and math.abs(close - fib618) < fibProximity
bool  atFibZone    = nearFib382 or nearFib500 or nearFib618

// =============================================================================
// 9. DIVERGENCE DETECTION  (unchanged from V9)
// =============================================================================

var float rsiAtSwingHi1 = na
var float rsiAtSwingHi2 = na
var float rsiAtSwingLo1 = na
var float rsiAtSwingLo2 = na
var float mdAtSwingHi1  = na
var float mdAtSwingHi2  = na
var float mdAtSwingLo1  = na
var float mdAtSwingLo2  = na

if not na(pivHi)
    rsiAtSwingHi2 := rsiAtSwingHi1
    mdAtSwingHi2  := mdAtSwingHi1
    rsiAtSwingHi1 := rsi[pivotRight]
    mdAtSwingHi1  := md[pivotRight]

if not na(pivLo)
    rsiAtSwingLo2 := rsiAtSwingLo1
    mdAtSwingLo2  := mdAtSwingLo1
    rsiAtSwingLo1 := rsi[pivotRight]
    mdAtSwingLo1  := md[pivotRight]

bool rsiBearDiv       = higherHighs and not na(rsiAtSwingHi1) and not na(rsiAtSwingHi2) and (rsiAtSwingHi1 < rsiAtSwingHi2)
bool mdBearDiv        = higherHighs and not na(mdAtSwingHi1)  and not na(mdAtSwingHi2)  and (mdAtSwingHi1  < mdAtSwingHi2)
bool bearishDivergence = rsiBearDiv or mdBearDiv

bool rsiBullDiv       = lowerLows and not na(rsiAtSwingLo1) and not na(rsiAtSwingLo2) and (rsiAtSwingLo1 > rsiAtSwingLo2)
bool mdBullDiv        = lowerLows and not na(mdAtSwingLo1)  and not na(mdAtSwingLo2)  and (mdAtSwingLo1  > mdAtSwingLo2)
bool bullishDivergence = rsiBullDiv or mdBullDiv

bool vidyaConfirmsBearDiv = bearishDivergence and (vidyaFalling or vidyaSlope <  vidyaFlatPct)
bool vidyaConfirmsBullDiv = bullishDivergence and (vidyaRising  or vidyaSlope > -vidyaFlatPct)

bool strongBullDiv = rsiBullDiv and mdBullDiv
bool strongBearDiv = rsiBearDiv and mdBearDiv

// =============================================================================
// 10. SIGNAL LOGIC  (unchanged from V9)
// =============================================================================

bool rsiNotOverbought = rsi < rsiOverbought
bool rsiNotOversold   = rsi > rsiOversold

// ── BUY TIER 1: Strong Trend Buy ──────────────────────────────────────────────
bool strongBuy =
     (adx > adxThreshold)      and
     vidyaRising                and
     priceAboveVidya            and
     md > 0.0                   and
     rsiNotOverbought           and
     volBuyConf                 and
     not volDivBear             and
     not bearishDivergence      and
     not vidyaLostMomentum      and
     mtfBullConfirmed

// ── BUY TIER 2: Correction Buy  (wave 2/4/B bottoms) ─────────────────────────
bool corrBuyVidyaOk    = vidyaRising or (enableEarlyBottomBuy and vidyaFlattening and rsi < 50.0)
bool corrBuyPriceOk    = (close > vidya or priceNearVidya) or (enableEarlyBottomBuy and priceCrossAboveVidya)
bool corrBuyRsiOk      = (rsi > corrBuyRsiMin and rsi < corrBuyRsiMax) or (enableEarlyBottomBuy and strongBullDiv and rsi > 20 and rsi < corrBuyRsiMax)
bool corrBuyMtfOk      = mtfBullModerate or (strongBullDiv and not mtfBearStrong) or (enableEarlyBottomBuy and strongBullDiv and mtfWeighted > -20.0)
bool corrBuyNotAtTop   = not (bearishDivergence and rsi > 52.0)
bool corrBuyNotAtLocalHigh = localHighThr >= 1.0 or close < ta.highest(high, localHighBars) * localHighThr
bool correctionBuy =
     corrBuyVidyaOk            and
     corrBuyPriceOk            and
     corrBuyRsiOk              and
     bullishDivergence         and
     (atFibZone or higherLows or lowerLows) and
     corrBuyMtfOk              and
     corrBuyNotAtTop           and
     corrBuyNotAtLocalHigh     and
     (volBuyConf or volDivBull)

// ── SELL TIER 1: Strong Reversal ──────────────────────────────────────────────
bool strongSell =
     (adx > strongAdxInp)  and
     vidyaFalling           and
     priceBelowVidya        and
     md < 0.0               and
     rsiNotOversold         and
     volSellConf            and
     not bullishDivergence  and
     mtfBearStrong

// ── SELL TIER 2: Exhaustion / Wave B Top ─────────────────────────────────────
// V14 FIX — two guards added to prevent firing in buy zones:
//
// 1. not bullishDivergence
//    SELL Tier 1 (strongSell) already has this guard; Tier 2 was missing it.
//    When price makes a lower low while RSI/MACD makes a higher low, the market
//    is setting up a BUY (wave C bottom / correction buy) — EXH SELL must not fire.
//    Root cause of the orange SELL appearing at AAPL correction bottoms.
//
// 2. rsi < rsi[3]  (RSI must be DECLINING, not just low)
//    rsi < exhRsiCeil (45) alone is satisfied during a recovery bounce from
//    oversold (e.g. RSI rising 28 → 40 → 44). True mid-trend exhaustion has
//    RSI falling toward that ceiling, not climbing up through it from below.
//    This distinguishes "exhaustion at a lower high" from "recovery from a bottom".
bool trendExhaustionSell =
     (adx > adxThreshold)               and
     (priceBelowVidya or priceNearVidya) and
     vidyaFalling                        and
     rsi < exhRsiCeil                    and   // RSI below exhaustion ceiling
     rsi < rsi[3]                        and   // V14: RSI must be FALLING — not recovering from a low
     not bullishDivergence               and   // V14: block when market is printing a buy setup
     sh < 0.0                            and
     volSellConf                         and
     (bearishStructure or lowerHighs)    and
     mtfBearModerate

// ── SELL TIER 3: Early Divergence Sell ───────────────────────────────────────
bool divSellMtfOk    = mtfBearModerate or (enableEarlyWaveTopSell and strongBearDiv and mtfWeighted <= 0.0)
bool divSellStructOk = (atFibZone or lowerHighs) or (enableEarlyWaveTopSell and higherHighs)
bool divergenceSell =
     rsiBearDiv and mdBearDiv    and
     vidyaConfirmsBearDiv        and
     rsi > divRsiFloor           and
     rsi < divRsiCeil            and
     sh < 0.0 and md < sb        and
     divSellStructOk             and
     divSellMtfOk

// ── SELL TIER 4: Wave Top (Elliott Wave 5 / Wave B peak) ─────────────────────
bool waveTopVidyaOk  = vidyaLostMomentum or (enableEarlyWaveTopSell and vidyaSlope < vidyaSteepPct and vidyaSlope >= 0.0)
bool waveTopMomOk    = (sh < 0.0 or md < sb) or (enableEarlyWaveTopSell and (md < md[1] or sh < sh[1]))
bool waveTopDivOk    = rsiBearDiv or (enableEarlyWaveTopSell and mdBearDiv)
bool waveTopSell =
     waveTopDivOk           and
     waveTopVidyaOk         and
     not vidyaFalling       and
     priceAboveVidya        and
     higherHighs            and
     rsi > divRsiFloor      and
     rsi < rsiOverbought    and
     waveTopMomOk           and
     not bearishStructure

// ── Composite + edge detection ────────────────────────────────────────────────
bool buyCondition  = strongBuy or correctionBuy
bool sellCondition = strongSell or trendExhaustionSell or divergenceSell or waveTopSell
bool confirmedBuy  = buyCondition
bool confirmedSell = sellCondition

bool triggerBuy     = confirmedBuy  and not confirmedBuy[1]
bool rawTriggerSell = confirmedSell and not confirmedSell[1]

var int lastSellBar = na
bool triggerSell    = rawTriggerSell and (na(lastSellBar) or (bar_index - lastSellBar) >= sellCooldown)
if triggerSell
    lastSellBar := bar_index

// Tier labels
string buyTier  = strongBuy ? "STRONG_TREND" : "CORRECTION_BUY"
string sellTier = strongSell ? "SELL" : trendExhaustionSell ? "EXHAUSTION" : divergenceSell ? "DIVERGENCE" : "WAVE_TOP"
string divInfo  = bearishDivergence ? (rsiBearDiv and mdBearDiv ? "RSI+MACD" : rsiBearDiv ? "RSI" : "MACD") :
                  bullishDivergence ? (rsiBullDiv and mdBullDiv ? "RSI+MACD" : rsiBullDiv ? "RSI" : "MACD") : "NONE"

// =============================================================================
// 11. ALERTS  (unchanged from V9)
// =============================================================================

if triggerBuy
    alert(get_full_alert_msg("BUY",  buyTier,  close, adx, rsi, md, volRatio, divInfo), alert.freq_once_per_bar_close)
if triggerSell
    alert(get_full_alert_msg("SELL", sellTier, close, adx, rsi, md, volRatio, divInfo), alert.freq_once_per_bar_close)

// =============================================================================
// 12. SIGNAL TOLERANCE BANDS  (V10 NEW)
//
// PURPOSE: Compensate for inherent lag — signals fire at bar CLOSE, and
// pivotRight confirmation adds additional delay. The ±sigTolPct% band shows
// traders the valid execution window around each signal price.
//
// MECHANICS:
//   • A band is drawn from signal_price × (1 − pct) to signal_price × (1 + pct).
//   • BUY band (green dashed) expires when the next SELL triggers.
//   • SELL band (red dashed) expires when the next BUY triggers.
//   • This handles ≈1-5 bar lag at default sigTolPct=5 % on 1D BTC charts.
// =============================================================================

var float buyTolLow   = na
var float buyTolHigh  = na
var float sellTolLow  = na
var float sellTolHigh = na
var int   buyTrigBar  = na
var int   sellTrigBar = na

if triggerBuy
    buyTolLow   := close * (1.0 - sigTolPct / 100.0)
    buyTolHigh  := close * (1.0 + sigTolPct / 100.0)
    buyTrigBar  := bar_index
    // Expire any open sell band — opposite signal invalidates it
    sellTolLow  := na
    sellTolHigh := na

if triggerSell
    sellTolLow  := close * (1.0 - sigTolPct / 100.0)
    sellTolHigh := close * (1.0 + sigTolPct / 100.0)
    sellTrigBar := bar_index
    // Expire any open buy band
    buyTolLow   := na
    buyTolHigh  := na

// Draw tolerance bands (linebr = broken line — gaps on na, continuous when active)
plot(buyTolLow,   title="Buy Zone Low",   color=color.new(color.green, 40), linewidth=1, style=plot.style_linebr)
plot(buyTolHigh,  title="Buy Zone High",  color=color.new(color.green, 40), linewidth=1, style=plot.style_linebr)
plot(sellTolLow,  title="Sell Zone Low",  color=color.new(color.red,   40), linewidth=1, style=plot.style_linebr)
plot(sellTolHigh, title="Sell Zone High", color=color.new(color.red,   40), linewidth=1, style=plot.style_linebr)

// Shade the active tolerance zone
bgcolor(not na(buyTolLow)  and close >= buyTolLow  and close <= buyTolHigh  ? color.new(color.green, 92) : na, title="Buy Tolerance Zone")
bgcolor(not na(sellTolLow) and close >= sellTolLow and close <= sellTolHigh ? color.new(color.red,   92) : na, title="Sell Tolerance Zone")

// =============================================================================
// 13. VISUALS  (V13: signal shapes simplified + divergence promoted to SELL/BUY)
// =============================================================================

// VIDYA line + slope background
color vidyaLineColor = vidyaRising ? color.new(#00C853, 0) : vidyaFalling ? color.new(#FF1744, 0) : color.new(#2962FF, 0)
plot(vidya, color=vidyaLineColor, linewidth=2, title="VIDYA Trend")
bgcolor(vidyaRising ? color.new(color.green, 93) : vidyaFalling ? color.new(color.red, 93) : na, title="VIDYA Slope BG")

// Volume candle backgrounds
bgcolor(volRatio >= volMult and close > open ? color.new(color.green, 92) : na, title="High Bull Vol")
bgcolor(volRatio >= volMult and close < open ? color.new(color.red,   92) : na, title="High Bear Vol")

// Fibonacci levels
plot(showFibs ? fib236 : na, color=color.new(color.gray,   60), linewidth=1, style=plot.style_circles, title="Fib 23.6%")
plot(showFibs ? fib382 : na, color=color.new(color.blue,   50), linewidth=1, style=plot.style_circles, title="Fib 38.2%")
plot(showFibs ? fib500 : na, color=color.new(color.purple, 40), linewidth=1, style=plot.style_circles, title="Fib 50.0%")
plot(showFibs ? fib618 : na, color=color.new(color.orange, 40), linewidth=1, style=plot.style_circles, title="Fib 61.8%")
plot(showFibs ? fib786 : na, color=color.new(color.gray,   60), linewidth=1, style=plot.style_circles, title="Fib 78.6%")

// ── Swing Labels — V10: SH/SL converted to Sell/Buy when swingAsBuySell=true ──
// WHY: Structural pivot highs are natural sell zones; pivot lows are natural buy zones.
// These labels appear pivotRight bars AFTER the actual swing, so they are historically
// accurate but slightly lagged from the real-time perspective.
if showSwings and not na(pivHi)
    string shText  = swingAsBuySell ? "Sell" : "SH"
    color  shColor = swingAsBuySell ? color.new(color.red, 50) : color.new(color.red, 70)
    label.new(bar_index - pivotRight, pivHi, shText,
              style=label.style_label_down, color=shColor, textcolor=color.white, size=size.tiny)

if showSwings and not na(pivLo)
    string slText  = swingAsBuySell ? "Buy" : "SL"
    color  slColor = swingAsBuySell ? color.new(color.green, 50) : color.new(color.green, 70)
    label.new(bar_index - pivotRight, pivLo, slText,
              style=label.style_label_up, color=slColor, textcolor=color.white, size=size.tiny)

// Divergence markers
if showDiverg and bearishDivergence and not bearishDivergence[1]
    label.new(bar_index, high + (high * 0.005), vidyaConfirmsBearDiv ? "DIV↓✓" : "DIV↓",
              style=label.style_label_down, color=color.new(color.purple, 20), textcolor=color.white, size=size.tiny)
if showDiverg and bullishDivergence and not bullishDivergence[1]
    label.new(bar_index, low - (low * 0.005), vidyaConfirmsBullDiv ? "DIV↑✓" : "DIV↑",
              style=label.style_label_up, color=color.new(color.teal, 20), textcolor=color.white, size=size.tiny)

// ── Signal Shapes (V13 — 4 plotshapes, divergence promoted to SELL / BUY) ─────
//
// Two visual tiers based on conviction:
//
//   STRONG  (size.normal, fully opaque)
//     BUY  — strongBuy  OR  correctionBuy backed by strongBullDiv
//     SELL — strongSell OR  divergenceSell OR waveTopSell
//            (bearishDivergence-based signals are now shown as SELL — not DIV↓)
//
//   MODERATE (size.small, semi-transparent)
//     BUY  — correctionBuy without strong divergence (structural wave 2/4 entries)
//     SELL — trendExhaustionSell only (mid-trend exhaustion, lower conviction)
//
// This collapses 6 plotshape calls into 4, eliminates the purple DIV↓ label noise,
// and makes all divergence-confirmed signals indistinguishable visually from the
// primary SELL / BUY triggers — matching user intent.

bool strongBuyShape    = triggerBuy  and (strongBuy or (correctionBuy and strongBullDiv))
bool moderateBuyShape  = triggerBuy  and not strongBuyShape
bool strongSellShape   = triggerSell and (strongSell or divergenceSell or waveTopSell)
bool moderateSellShape = triggerSell and not strongSellShape   // only trendExhaustionSell reaches here

plotshape(strongBuyShape,
     title="BUY (Strong)",   style=shape.labelup,   location=location.belowbar,
     color=color.green,      size=size.normal, text="BUY",  textcolor=color.white)
plotshape(moderateBuyShape,
     title="BUY",            style=shape.labelup,   location=location.belowbar,
     color=color.new(color.green, 25), size=size.small, text="BUY", textcolor=color.white)

plotshape(strongSellShape,
     title="SELL (Strong)",  style=shape.labeldown, location=location.abovebar,
     color=color.red,        size=size.normal, text="SELL", textcolor=color.white)
plotshape(moderateSellShape,
     title="SELL (EXH)",     style=shape.labeldown, location=location.abovebar,
     color=color.orange,     size=size.small,  text="SELL", textcolor=color.white)

// =============================================================================
// 14. DASHBOARD  (V10: added SIG AGE row for lag awareness)
// =============================================================================

var table mtfTable = table.new(position.top_right, 5, 7, bgcolor=color.new(color.black, 70), border_width=1)
if barstate.islast
    // Row 0: Headers
    table.cell(mtfTable, 0, 0, "WWR",  text_color=color.white,  text_size=size.tiny)
    table.cell(mtfTable, 1, 0, tf2h,   text_color=autoMTF ? color.yellow : color.gray, text_size=size.tiny)
    table.cell(mtfTable, 2, 0, tf4h,   text_color=autoMTF ? color.yellow : color.gray, text_size=size.tiny)
    table.cell(mtfTable, 3, 0, tf8h,   text_color=autoMTF ? color.yellow : color.gray, text_size=size.tiny)
    table.cell(mtfTable, 4, 0, "BASE", text_color=color.gray,   text_size=size.tiny)

    // Row 1: Bias scores
    table.cell(mtfTable, 0, 1, "Bias", text_color=color.gray, text_size=size.tiny)
    table.cell(mtfTable, 1, 1, str.tostring(score2h, "#.#"),
               text_color=score2h > 0 ? color.green : score2h < 0 ? color.red : color.gray, text_size=size.tiny)
    table.cell(mtfTable, 2, 1, str.tostring(score4h, "#.#"),
               text_color=score4h > 0 ? color.green : score4h < 0 ? color.red : color.gray, text_size=size.tiny)
    table.cell(mtfTable, 3, 1, str.tostring(score8h, "#.#"),
               text_color=score8h > 0 ? color.green : score8h < 0 ? color.red : color.gray, text_size=size.tiny)
    table.cell(mtfTable, 4, 1, str.tostring(mtfWeighted, "#.#"),
               text_color=mtfWeighted > 0 ? color.green : mtfWeighted < 0 ? color.red : color.gray, text_size=size.tiny)

    // Row 2: VIDYA HTF status
    table.cell(mtfTable, 0, 2, "VIDYA", text_color=color.gray, text_size=size.tiny)
    table.cell(mtfTable, 1, 2, vidya2hRising ? "↑" : "↓",
               text_color=vidya2hRising ? color.green : color.red, text_size=size.tiny)
    table.cell(mtfTable, 2, 2, vidya4hRising ? "↑" : "↓",
               text_color=vidya4hRising ? color.green : color.red, text_size=size.tiny)
    table.cell(mtfTable, 3, 2, vidya8hRising ? "↑" : "↓",
               text_color=vidya8hRising ? color.green : color.red, text_size=size.tiny)
    table.cell(mtfTable, 4, 2,
               vidyaRising ? "↑" + str.tostring(vidyaSlope, "#.#") + "%" : "↓" + str.tostring(vidyaSlope, "#.#") + "%",
               text_color=vidyaRising ? color.green : color.red, text_size=size.tiny)

    // Row 3: Volume + Divergence
    table.cell(mtfTable, 0, 3, "Vol",  text_color=color.gray, text_size=size.tiny)
    table.cell(mtfTable, 1, 3, str.tostring(volRatio, "#.#") + "x",
               text_color=volRatio >= volMult ? color.yellow : color.gray, text_size=size.tiny)
    table.cell(mtfTable, 2, 3, volDivBear ? "DIV↓" : volDivBull ? "DIV↑" : "—",
               text_color=volDivBear ? color.orange : volDivBull ? color.teal : color.gray, text_size=size.tiny)
    table.cell(mtfTable, 3, 3, bearishDivergence ? "BEAR" : bullishDivergence ? "BULL" : "—",
               text_color=bearishDivergence ? color.red : bullishDivergence ? color.green : color.gray, text_size=size.tiny)
    table.cell(mtfTable, 4, 3, divInfo,
               text_color=bearishDivergence ? color.red : bullishDivergence ? color.green : color.gray, text_size=size.tiny)

    // Row 4: Structure
    table.cell(mtfTable, 0, 4, "Struct", text_color=color.gray, text_size=size.tiny)
    table.cell(mtfTable, 1, 4, bullishStructure ? "HH/HL" : bearishStructure ? "LH/LL" : "MIXED",
               text_color=bullishStructure ? color.green : bearishStructure ? color.red : color.gray, text_size=size.tiny)
    table.cell(mtfTable, 2, 4, atFibZone ? "FIB" : "—",
               text_color=atFibZone ? color.yellow : color.gray, text_size=size.tiny)
    table.cell(mtfTable, 3, 4, fibBearish ? "RET↓" : fibBullish ? "RET↑" : "—",
               text_color=fibBearish ? color.red : fibBullish ? color.green : color.gray, text_size=size.tiny)
    table.cell(mtfTable, 4, 4, "ADX:" + str.tostring(adx, "#.#"),
               text_color=adx > strongAdxInp ? color.yellow : adx > adxThreshold ? color.white : color.gray, text_size=size.tiny)

    // Row 5: Active signal
    table.cell(mtfTable, 0, 5, "SIG",  text_color=color.gray, text_size=size.tiny)
    string sigText = confirmedBuy  ? (strongBuy ? "BUY▲" : "COR▲") :
                     confirmedSell ? (strongSell ? "SELL▼" : trendExhaustionSell ? "EXH▼" : divergenceSell ? "DIV▼" : "TOP▼") : "—"
    color  sigColor = confirmedBuy  ? color.green :
                      confirmedSell ? (strongSell ? color.red : trendExhaustionSell ? color.orange : divergenceSell ? color.purple : color.new(#FF6D00, 0)) : color.gray
    table.cell(mtfTable, 1, 5, sigText, text_color=sigColor, text_size=size.tiny)
    table.cell(mtfTable, 2, 5, "RSI:" + str.tostring(rsi, "#.#"),
               text_color=rsi > 70 ? color.red : rsi < 30 ? color.green : color.white, text_size=size.tiny)
    table.cell(mtfTable, 3, 5, "MD:" + str.tostring(md, "#.#"),
               text_color=md > 0 ? color.green : md < 0 ? color.red : color.gray, text_size=size.tiny)
    table.cell(mtfTable, 4, 5, "SH:" + str.tostring(sh, "#.#"),
               text_color=sh > 0 ? color.green : sh < 0 ? color.red : color.gray, text_size=size.tiny)

    // Row 6: Signal Age — V10 NEW (lag awareness)
    // Shows how many bars have passed since the last BUY or SELL trigger.
    // A large age means you are mid-swing, not at a fresh signal entry.
    int buyAge  = na(buyTrigBar)  ? -1 : bar_index - buyTrigBar
    int sellAge = na(sellTrigBar) ? -1 : bar_index - sellTrigBar
    string buyAgeStr  = buyAge  < 0 ? "—" : str.tostring(buyAge)  + "b"
    string sellAgeStr = sellAge < 0 ? "—" : str.tostring(sellAge) + "b"
    string tolStr     = str.tostring(sigTolPct, "#.#") + "%"
    table.cell(mtfTable, 0, 6, "LAG",  text_color=color.gray, text_size=size.tiny)
    table.cell(mtfTable, 1, 6, "BUY:"  + buyAgeStr,
               text_color=not na(buyTolLow) ? color.green : color.gray, text_size=size.tiny)
    table.cell(mtfTable, 2, 6, "SELL:" + sellAgeStr,
               text_color=not na(sellTolLow) ? color.red : color.gray, text_size=size.tiny)
    table.cell(mtfTable, 3, 6, "±" + tolStr,
               text_color=color.yellow, text_size=size.tiny)
    table.cell(mtfTable, 4, 6, "pR:" + str.tostring(pivotRight),
               text_color=pivotRight <= 3 ? color.yellow : color.gray, text_size=size.tiny)

Overview

A multi-timeframe score uses three higher timeframes, automatic at two, four and eight times the chart, with adjustable weights and thresholds. Cooldowns, tolerance bands around each signal and early bottom or top detection are optional. Settings are grouped by simple, intermediate and advanced tiers. Pivot labels confirm only after the right-hand lookback bars, so they lag.

Details

Published by

udhansingh on GitHub

Code credit

wirezard, as written in the script's header

Type

Indicator, Pine Script v6

Draws

On the price chart

Category

Trend, Oscillators & momentum, Divergence

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
Auto-detect MTF TimeframesbooltrueautoMTF
Show Fibonacci LevelsbooltrueshowFibs
Show Swing SignalsbooltrueshowSwings
Swing Labels: Buy / Sell (OFF = SH / SL)booltrueswingAsBuySell
Show Divergence MarkersbooltrueshowDiverg
Early Bottom DetectionbooltrueenableEarlyBottomBuy
Early Top DetectionbooltrueenableEarlyWaveTopSell
ADX Threshold — BUY / EXH signalsint18adxThreshold
ADX Threshold — SELL reversalint25strongAdxInp
Volume Multiplierfloat1.2volMult
RSI Overbought Guard (BUY block)float75.0rsiOverbought
RSI Oversold Guard (SELL block)float35.0rsiOversold
Show all 40 settings
SettingTypeDefaultVariable
Sell Cooldown Barsint15sellCooldown
Signal Tolerance ± %float5.0sigTolPct
ADX Lengthint14adxLen
Volume MA Lengthint20volLen
Impulse MACD Lengthint34imacdLen
Impulse MACD Smoothint9imacdSmth
Impulse MACD Signalint9imacdSig
VIDYA Smoothingint12vidyaSmooth
Pivot Lookback Leftint10pivotLeft
Pivot Lookback Right ← lag controlint3pivotRight
Short TF (manual override)timeframe120manualTf1
Medium TF (manual override)timeframe240manualTf2
Long TF (manual override)timeframe480manualTf3
Short TF Weightfloat3.0w2h
Medium TF Weightfloat2.0w4h
Long TF Weightfloat1.0w8h
Bull Confirmed Scorefloat16.0mtfBullStrongThr
Bull Moderate Scorefloat8.0mtfBullModerateThr
Bear Confirmed Scorefloat16.0mtfBearStrongThr
Bear Moderate Scorefloat8.0mtfBearModerateThr
Bear Local 2H Scorefloat3.0mtfBearLocalThr
Trend Lookback Barsint3vidyaTrendLB
Slope Lookback Barsint5vidyaSlopeLB
Steep Slope Threshold %float0.5vidyaSteepPct
Flat Threshold %float0.2vidyaFlatPct
COR Buy RSI Minfloat30.0corrBuyRsiMin
COR Buy RSI Maxfloat55.0corrBuyRsiMax
EXH Sell RSI Ceilingfloat45.0exhRsiCeil
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

This indicator plots calendar-spread context for commodity futures on the price chart. It maps the chart symbol to front and next month contracts automatically, or uses manual symbols, then calculates the spread as a difference or ratio. Fast and slow EMAs, a

Indicator v6 TrendOscillators & momentum
Updated 2 days ago · MIT GitHub repository of Vein: Spread Context [WavesUnchained]
5 stars

This indicator overlays multiple technical analysis tools onto the price chart to evaluate trend direction and trade setups. It computes an exponential moving average, a smoothed Stochastic RSI, a custom Williams Alligator using smoothed moving averages with o

Indicator v4 TrendMoving averages
Updated 3 years ago · Apache-2.0 GitHub repository of 200 EMA + Alligator + Stochastic

Fractals with Divergence Scanner is an overlay indicator that combines Exponential Moving Averages, an eight-line EMA ribbon cloud, and WaveTrend divergence analysis. It calculates baseline EMA trends alongside WaveTrend oscillators to detect regular and hidde

Indicator v5 TrendMoving averages
Updated 5 months ago · None stated GitHub repository of Fractals with Divergence Scanner
2 stars

ARPS Ultimate MultiStrategy Trading combines multiple technical indicators into a single chart overlay. It calculates and plots trend lines, moving averages, Ichimoku cloud components, Williams Alligator lines, and Fibonacci support and resistance levels direc

Indicator v4 TrendOscillators & momentum
Updated 6 months ago · None stated GitHub repository of ARPS Ultimate MultiStrategy Trading

Complexity Trender

by panzmoravylab
2 stars

Complexity Trender is an indicator that combines EMA crossovers, RSI momentum, Stochastic signals, Bollinger Bands, ADX trend strength, volume analysis, and divergence detection to identify trends. It plots labels, trend lines, and a summary table directly on

Indicator v6 TrendOscillators & momentum
Updated 1 year ago · None stated GitHub repository of Complexity Trender

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