Isolated Scroll Container

1. Cup & Handle Indicator Description (Zeiierman)

An indicator that automatically detects the Cup & Handle pattern - one of the most classic chart patterns in technical analysis

1.1 Indicator Concept

The Cup & Handle indicator is based on the theory of market psychology patterns discovered by William O'Neil. This pattern believes that:

  • Cup Phase: Represents the process where price gradually declines, forms a bottom, then recovers back to the initial level. This is the market "consolidation" phase after a previous uptrend, where weak sellers exit and strong buyers accumulate.
  • Handle Phase: After the cup forms, price has a small pullback creating the handle. This is the final "test" before the breakout.
  • Breakout: When price breaks above the cup's rim, this signals a strong uptrend is about to occur, with a price target equal to the cup's depth.

This indicator automatically detects both bullish patterns (Cup & Handle) and bearish patterns (Inverted Cup & Handle) based on price pivot points (swing highs/lows).

1.2 Indicator Features

  • Display Cup & Handle Pattern:
    • Cup Curve: Drawn with curved polyline connecting 3 points: left rim → cup bottom → right rim. Green for bullish pattern, red for bearish pattern.
    • Handle Curve: Drawn from right rim → handle low → projected breakout point. Same color as cup.
    • Filled Area: Light color fill inside cup and handle for easy identification.
    • Pattern Label: Displays "Cup+Handle" or "Inv Cup+Handle" text at cup center.
    • Target Line: Horizontal line showing price target after breakout, calculated as: Rim Price ± (Cup Depth × Target Multiplier)
  • Alerts:
    • "Cup & Handle (Brewed)": Triggers when valid bullish pattern is detected.
    • "Inverted Cup & Handle (Brewed)": Triggers when valid bearish pattern is detected.

1.3 How to Use the Indicator

  • Identify Entry Opportunities: When the indicator draws a Cup & Handle pattern and price breaks out from the rim (if "Require breakout confirmation" is enabled), this is a signal to enter BUY (bullish pattern) or SELL (bearish pattern).
  • Set Take Profit Target: Use the Target Line as the profit-taking level. Default is 0.5× cup depth, adjustable via "Target multiplier".
  • Set Stop Loss: Place SL below the "Invalidation" level (default 61.8% of handle depth from rim). If price touches this level, the pattern is invalidated.
  • Filter Quality Signals: Adjust parameters like "Rim similarity tolerance", "Handle retrace min/max" to filter more accurate patterns and reduce noise.
  • Combine with Larger Timeframes: Cup & Handle pattern works best on H4, Daily, Weekly timeframes. Avoid using on very small timeframes (M1, M5) due to noise.

1.4 How the Indicator Works

Inputs & Roles

  • pivotSpan (Integer, default: 10): Number of bars needed to confirm a swing high/low (pivot). For example, pivotSpan=10 means 10 bars on the left and 10 bars on the right must all be lower (for high) or higher (for low) to confirm a pivot. Increase pivotSpan → fewer but stronger pivots, fewer patterns but higher quality. Decrease pivotSpan → more pivots, more signals but more noise.
  • rimTolPct (Integer %, default: 18%): Allowed deviation between left rim and right rim of the cup. For example, if left rim is at $100, right rim at $110, deviation = 10%. If rimTolPct=18%, it's accepted; if rimTolPct=5%, it's rejected. Decrease rimTolPct → cup must be more balanced, fewer patterns but more accurate. Increase rimTolPct → accept more unbalanced cups, more patterns.
  • hMin (Float, default: 0.12): Minimum depth of handle relative to cup depth. For example, if cup is $100 deep, handle must be at least $12 deep (0.12×100). Too small → handle too shallow, insufficient "test", weak signal.
  • hMax (Float, default: 0.55): Maximum depth of handle. For example, if cup is $100 deep, handle cannot be deeper than $55. Too large → handle too deep, messy pattern, no longer a standard Cup & Handle.
  • killAtFib (Float, default: 61.8%): Pattern "invalidation" level. If price drops below 61.8% of handle depth (from rim), pattern is broken. This is the safe Stop Loss level. Decrease → tighter SL, less risk but easier to stop out early. Increase → looser SL, accept larger swings.
  • needConfirm (Boolean, default: false): Whether to require price breakout past rim. false → early detection as soon as pattern forms. true → only triggers when price has broken past rim, higher quality signal but later.
  • targetMult (Float, default: 0.5): Multiplier to calculate price target. For example, cup depth $100, rim at $200, target = 200 + (100×0.5) = $250. Increase → farther target, larger profit but harder to reach. Decrease → closer target, easier to reach but smaller profit.
  • showName, bgBull, lnBull, bgBear, lnBear, wOk, stOk, showTarget, targetWidth, targetStyle: Display options (show/hide label, colors, line width, line style). Don't affect detection logic, only visual appearance.

Main Logic Blocks

🎯 Flow 1: Cup & Handle Pattern Detection

  • Step 1 - Collect Pivots (Swing Highs/Lows):
    • The indicator uses ta.pivothigh() and ta.pivotlow() functions to find swing highs and lows based on pivotSpan.
    • Each time a pivot is found, it's saved to a "pivot list" (array) with 3 pieces of information: price (p), bar position (i), direction (d) (+1 = high, -1 = low).
    • This list only keeps the most recent 12 pivots (if more than 12, the oldest pivot is deleted).
    • Example: If pivotSpan=10, price makes a high at bar 100 with price $50, and 10 bars before + 10 bars after are all below $50, then this pivot is saved: {p: 50, i: 100, d: +1}.
  • Step 2 - Identify Valid 4-Pivot Sequence:
    • The indicator takes the 4 most recent pivots from the list: s0, s1, s2, s3.
    • Bullish pattern (Cup & Handle): Sequence must be: High → Low → High → Low (s0.d=+1, s1.d=-1, s2.d=+1, s3.d=-1).
    • Bearish pattern (Inverted Cup & Handle): Sequence must be: Low → High → Low → High (s0.d=-1, s1.d=+1, s2.d=-1, s3.d=+1).
    • Bullish pattern example: s0 = high $100 (left rim), s1 = low $80 (cup bottom), s2 = high $98 (right rim), s3 = low $92 (handle low).
  • Step 3 - Validate Cup Conditions:
    • Rim similarity: Compare prices of s0 (left rim) and s2 (right rim). If deviation ≤ rimTolPct%, it's valid.
    • Example: s0=$100, s2=$110, deviation = |100-110|/100 = 10%. If rimTolPct=18% → valid. If rimTolPct=5% → rejected.
    • Calculate cup depth: depth = |rimPrice - Bp|, where rimPrice = min(s0, s2) for bullish pattern, or max(s0, s2) for bearish pattern.
    • Bullish pattern example: s0=$100, s2=$98, s1=$80 → rimPrice=$98 (take lower), depth=|98-80|=$18.
  • Step 4 - Validate Handle Conditions:
    • Calculate handle depth (hRet): hRet = |rimPrice - Hp| / depth, where Hp is the price of s3 (handle low).
    • Example: rimPrice=$98, Hp=$92, depth=$18 → hRet = |98-92|/18 = 6/18 = 0.33 (33%).
    • Check hRet is within [hMin, hMax]: If hMin=0.12, hMax=0.55, then 0.33 is within range → valid.
    • Check handle position: For bullish pattern, Hp must be < rimPrice (handle must be below cup rim). For bearish pattern, Hp must be> rimPrice.
  • Step 5 - Check Breakout (if needConfirm enabled):
    • If needConfirm=true, indicator only triggers when closing price (close) breaks past rimPrice.
    • Bullish pattern: close > rimPrice.
    • Bearish pattern: close < rimPrice.
    • If needConfirm=false, skip this step, trigger as soon as pattern forms.
  • Step 6 - Remove Duplicates:
    • Check if new pattern duplicates a previous pattern (based on rim position and rim price).
    • If duplicate (deviation < 0.15%), skip to avoid drawing multiple times.

🎨 Flow 2: Draw Pattern on Chart

  • Draw Cup Curve:
    • Create 3 points: point 1 (Li, rimPrice), point 2 (midBar, Bp), point 3 (Ri, rimPrice).
    • Use polyline.new() function with curved=true parameter to draw curved line connecting these 3 points.
    • Line color and fill color chosen based on bullish/bearish pattern (bgBull/lnBull or bgBear/lnBear).
  • Draw Handle Curve:
    • Create 3 points: point 1 (Ri, rimPrice), point 2 (Hi, Hp), point 3 (projBar, rimPrice).
    • projBar = Hi + (Hi - Ri), meaning extend handle forward to create complete handle shape.
    • Draw similar to cup, using curved polyline.
  • Draw Target Line:
    • If showTarget=true, draw horizontal line from Ri to Hi+25 bars, at price level tgtPrice.
    • tgtPrice = Rp + (depth × targetMult) for bullish pattern, or Rp - (depth × targetMult) for bearish pattern.
    • Example: Rp=$98, depth=$18, targetMult=0.5 → tgtPrice = 98 + (18×0.5) = $107.
  • Draw Pattern Label:
    • If showName=true, draw label "Cup+Handle" or "Inv Cup+Handle" at cup center (midBar, rimPrice).

🔔 Flow 3: Trigger Alerts

  • When a valid pattern is detected, variable newSignal = true and newSide = +1 (bullish) or -1 (bearish).
  • Function alertcondition() checks this condition and triggers corresponding alert.
  • Alert "Cup & Handle (Brewed)": Triggers when newSignal=true and newSide=+1.
  • Alert "Inverted Cup & Handle (Brewed)": Triggers when newSignal=true and newSide=-1.

Outputs & Usage Roles

  • Cup & Handle Curves: Help traders visually identify the pattern on chart, determine accumulation zone and potential breakout point.
  • Target Line: Shows price target for profit-taking, based on cup depth theory.
  • Invalidation Level (invPrice): Price level where if touched, pattern is broken. Used to set Stop Loss. Example: invPrice = Rp - (depth × 0.618) for bullish pattern.
  • Alerts: Timely notifications when pattern appears, helping traders not miss opportunities.
💡 Note: This indicator works best on larger timeframes (H4, Daily, Weekly) and on assets with good liquidity. Should be combined with other indicators (volume, RSI, MACD) to confirm signals.
Zoom/Pan Layered Image
Background Overlay
+
				
					// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © LuxAlgo

//@version=6
indicator("Structural Leg Profiler [LuxAlgo]", "LuxAlgo - Leg Profiler", overlay=true, max_boxes_count=500, max_lines_count=500, max_labels_count=500)

//---------------------------------------------------------------------------------------------------------------------}
// Inputs
//---------------------------------------------------------------------------------------------------------------------{
string GRP_SWING   = "Swing Detection"
int    atrPeriod   = input.int(5, "ATR Period", group=GRP_SWING)
float  swingMult   = input.float(2.5, "Swing Multiplier (ATR)", step=0.1, group=GRP_SWING, tooltip="Higher values create larger structural legs. Lower values capture micro-swings.")

string GRP_PROFILE = "Profile Settings"
int    maxBoxes    = input.int(50, "Max Profile Boxes", minval=10, maxval=150, group=GRP_PROFILE)
string alignMode   = input.string("Left", "Profile Alignment", options=["Left", "Right", "Center"], group=GRP_PROFILE)
bool   showBoxVol  = input.bool(true, "Show Volume Value Inside Boxes", group=GRP_PROFILE)
bool   extendPoc   = input.bool(true, "Extend Untested POCs", group=GRP_PROFILE, tooltip="Extends the Point of Control line forward until price touches and tests it.")

string GRP_BUBBLES = "Volume Anomalies"
bool   showBubbles = input.bool(true, "Show Volume Bubbles", group=GRP_BUBBLES)
float  bubbleMult  = input.float(2.0, "Spike Threshold (x SMA)", step=0.1, group=GRP_BUBBLES, tooltip="Highlights candles where volume is X times greater than the 20-period average.")

string GRP_COLORS  = "Style & Colors"
string colorMode   = input.string("Volume Gradient", "Box Color Mode", options=["Volume Gradient", "Delta (Buy vs Sell)"], group=GRP_COLORS)

color  upStartC    = input.color(color.new(#01579B, 0), "Up Leg (Low Vol)", group=GRP_COLORS, inline="up")
color  upMidC      = input.color(color.new(#2962FF, 0), "Up Leg (Mid Vol)", group=GRP_COLORS, inline="up")
color  upEndC      = input.color(color.new(#00E5FF, 0), "Up Leg (High Vol)", group=GRP_COLORS, inline="up")

color  dnStartC    = input.color(color.new(#311B92, 0), "Down Leg (Low Vol)", group=GRP_COLORS, inline="dn")
color  dnMidC      = input.color(color.new(#C51162, 0), "Down Leg (Mid Vol)", group=GRP_COLORS, inline="dn")
color  dnEndC      = input.color(color.new(#FF5252, 0), "Down Leg (High Vol)", group=GRP_COLORS, inline="dn")

//---------------------------------------------------------------------------------------------------------------------}
// Types
//---------------------------------------------------------------------------------------------------------------------{
type LTFBar
    int chartBar
    float h
    float l
    float v
    float buyV
    float sellV

type CandleProfile
    float profileHigh
    float profileLow
    int   numBoxes
    float boxHeight
    array<float> volumeDistribution
    array<float> deltaDistribution
    float maxVolumeInProfile
    int   maxVolumeIndex
    float pocPrice

type UntestedPOC
    line  pocLine
    float price
    bool  isBull
    int   endBar

//---------------------------------------------------------------------------------------------------------------------}
// State Variables
//---------------------------------------------------------------------------------------------------------------------{
var array<LTFBar>      ltfHistory   = array.new<LTFBar>()
var array<UntestedPOC> untestedPocs = array.new<UntestedPOC>()

var int   zzDir          = 1
var float zzHigh         = high
var int   zzHighBar      = bar_index
var float zzLow          = low
var int   zzLowBar       = bar_index
var int   lastPivotBar   = bar_index
var float lastPivotPrice = close

//---------------------------------------------------------------------------------------------------------------------}
// Methods / Functions
//---------------------------------------------------------------------------------------------------------------------{
f_buildVolumeBar(int filledBlocks, int totalBlocks) =>
    string result = ""
    for i = 1 to totalBlocks
        result += i <= filledBlocks ? "█" : "░"
    result

f_createProfile(float legHigh, float legLow, float targetBoxHeight, array<LTFBar> legBars) =>
    float barRange = legHigh - legLow
    int numBoxes = math.max(1, int(math.round(barRange / targetBoxHeight)))
    float adjustedBoxHeight = barRange / numBoxes
    array<float> volDist = array.new_float(numBoxes, 0.0)
    array<float> deltaDist = array.new_float(numBoxes, 0.0)
    
    for i = 0 to legBars.size() - 1
        LTFBar b = legBars.get(i)
        float ltfBarRange = math.max(b.h - b.l, syminfo.mintick)
        
        for boxIndex = 0 to numBoxes - 1
            float boxBottom = legLow + (boxIndex * adjustedBoxHeight)
            float boxTop = boxBottom + adjustedBoxHeight
            float overlapHeight = math.max(0, math.min(boxTop, b.h) - math.max(boxBottom, b.l))
            
            if overlapHeight > 0
                float overlapRatio = overlapHeight / ltfBarRange
                float volContrib = b.v * overlapRatio
                float buyContrib = b.buyV * overlapRatio
                float sellContrib = b.sellV * overlapRatio
                
                volDist.set(boxIndex, volDist.get(boxIndex) + volContrib)
                deltaDist.set(boxIndex, deltaDist.get(boxIndex) + (buyContrib - sellContrib))
                
    float maxVolume = volDist.max()
    int maxVolIdx = volDist.indexof(maxVolume)
    float pocPrice = legLow + (maxVolIdx * adjustedBoxHeight) + (adjustedBoxHeight / 2)
    
    CandleProfile.new(legHigh, legLow, numBoxes, adjustedBoxHeight, volDist, deltaDist, maxVolume, maxVolIdx, pocPrice)

method draw(CandleProfile this, int startBar, int endBar, bool isUpLeg, float totalBuyVol, float totalSellVol) =>
    int bLeft = startBar
    int bRight = math.max(startBar + 1, endBar)
    int totalBlocks = math.max(5, math.min(30, int(15 * ((bRight - bLeft) / 50.0))))

    color startC = isUpLeg ? upStartC : dnStartC
    color midC   = isUpLeg ? upMidC : dnMidC
    color endC   = isUpLeg ? upEndC : dnEndC
    
    string parsedAlign = alignMode == "Left" ? text.align_left : alignMode == "Right" ? text.align_right : text.align_center
    
    for i = 0 to this.numBoxes - 1
        float boxBottom = this.profileLow + (i * this.boxHeight)
        float boxTop = boxBottom + this.boxHeight
        float currentBoxVolume = this.volumeDistribution.get(i)
        float currentBoxDelta = this.deltaDistribution.get(i)
        
        if currentBoxVolume > 0
            int filledBlocks = this.maxVolumeInProfile > 0 ? int(math.round((currentBoxVolume / this.maxVolumeInProfile) * totalBlocks)) : 0
            string boxText = f_buildVolumeBar(filledBlocks, totalBlocks)
            if showBoxVol
                boxText += " " + str.tostring(currentBoxVolume, format.volume)
            
            color textColor = na
            
            if colorMode == "Delta (Buy vs Sell)"
                if currentBoxDelta > 0
                    textColor := color.from_gradient(currentBoxDelta, 0, this.maxVolumeInProfile, color.new(color.green, 60), color.new(color.green, 0))
                else if currentBoxDelta < 0
                    textColor := color.from_gradient(math.abs(currentBoxDelta), 0, this.maxVolumeInProfile, color.new(color.red, 60), color.new(color.red, 0))
                else
                    textColor := color.gray
            else
                if i < this.maxVolumeIndex
                    textColor := color.from_gradient(i, 0, this.maxVolumeIndex, startC, midC)
                else if i > this.maxVolumeIndex
                    textColor := color.from_gradient(i, this.maxVolumeIndex, this.numBoxes - 1, midC, endC)
                else
                    textColor := midC
                
            color bgC = color.new(textColor, 90)
            box.new(left=bLeft, top=boxTop, right=bRight, bottom=boxBottom, border_color=color(na), bgcolor=bgC, text=boxText, text_size=size.small, text_color=textColor, text_halign=parsedAlign, text_valign=text.align_center, text_wrap=text.wrap_none, text_font_family=font.family_monospace)
            
    line pocL = line.new(startBar, this.pocPrice, endBar, this.pocPrice, color=color.new(endC, 0), style=line.style_dashed, width=2)
    if extendPoc
        untestedPocs.push(UntestedPOC.new(pocL, this.pocPrice, isUpLeg, endBar))
        
    float delta = totalBuyVol - totalSellVol
    color deltaColor = delta > 0 ? color.green : color.red
    string deltaSign = delta > 0 ? "+" : ""
    
    string summaryText = "Leg Vol: " + str.tostring(totalBuyVol + totalSellVol, format.volume) + "\n" +
                         "Delta: " + deltaSign + str.tostring(delta, format.volume) + "\n" +
                         "POC: " + str.tostring(this.pocPrice, format.mintick)
                         
    int midBar = int(math.round((startBar + endBar) / 2))
    float summaryY = isUpLeg ? this.profileHigh : this.profileLow
    label.new(midBar, summaryY, text=summaryText, color=color.new(chart.bg_color, 20), style=isUpLeg ? label.style_label_down : label.style_label_up, textcolor=deltaColor, size=size.tiny)

f_processLeg(int startBar, int endBar, float startPrice, float endPrice, bool isUpLeg, array<LTFBar> history, float baseBoxHeight) =>
    line.new(startBar, startPrice, endBar, endPrice, color=color.new(color.gray, 50), width=2, style=line.style_dotted)
    
    array<LTFBar> legBars = array.new<LTFBar>()
    float totalBuy = 0.0
    float totalSell = 0.0
    float maxH = -1.0
    float minL = 99999999.0
    
    for i = 0 to history.size() - 1
        LTFBar b = history.get(i)
        if b.chartBar >= startBar and b.chartBar <= endBar
            legBars.push(b)
            totalBuy += b.buyV
            totalSell += b.sellV
            maxH := math.max(maxH, b.h)
            minL := math.min(minL, b.l)
            
    if legBars.size() > 0
        float groupRange = maxH - minL
        float targetBoxHeight = (groupRange / baseBoxHeight) > maxBoxes ? groupRange / maxBoxes : baseBoxHeight
        
        CandleProfile profile = f_createProfile(maxH, minL, targetBoxHeight, legBars)
        profile.draw(startBar, endBar, isUpLeg, totalBuy, totalSell)
        
    array<LTFBar> newHistory = array.new<LTFBar>()
    for i = 0 to history.size() - 1
        if history.get(i).chartBar >= endBar
            newHistory.push(history.get(i))
    newHistory

//---------------------------------------------------------------------------------------------------------------------}
// Data Retrieval & Accumulation
//---------------------------------------------------------------------------------------------------------------------{
[ltfOpens, ltfHighs, ltfLows, ltfCloses, ltfVolumes] = request.security_lower_tf(syminfo.tickerid, "1", [open, high, low, close, volume])

if ltfHighs.size() > 0
    for i = 0 to ltfHighs.size() - 1
        float h = ltfHighs.get(i)
        float l = ltfLows.get(i)
        float c = ltfCloses.get(i)
        float v = ltfVolumes.get(i)
        
        float rng = math.max(h - l, syminfo.mintick)
        float buyVol = v * (c - l) / rng
        float sellVol = v * (h - c) / rng
        
        ltfHistory.push(LTFBar.new(bar_index, h, l, v, buyVol, sellVol))
else
    float rng = math.max(high - low, syminfo.mintick)
    float buyVol = volume * (close - low) / rng
    float sellVol = volume * (high - close) / rng
    ltfHistory.push(LTFBar.new(bar_index, high, low, volume, buyVol, sellVol))

if ltfHistory.size() > 90000
    ltfHistory.shift()

//---------------------------------------------------------------------------------------------------------------------}
// Swing Logic & Profiling
//---------------------------------------------------------------------------------------------------------------------{
float globalAtr = ta.atr(atrPeriod)
float globalAtr14 = ta.atr(14)
float revAmount = globalAtr * swingMult

bool isSwingHigh = false
bool isSwingLow = false

if zzDir == 1
    if high > zzHigh
        zzHigh := high
        zzHighBar := bar_index
    if low < zzHigh - revAmount
        zzDir := -1
        zzLow := low
        zzLowBar := bar_index
        isSwingHigh := true
else
    if low < zzLow
        zzLow := low
        zzLowBar := bar_index
    if high > zzLow + revAmount
        zzDir := 1
        zzHigh := high
        zzHighBar := bar_index
        isSwingLow := true

if isSwingHigh
    float boxHeightLimit = globalAtr14 / 10
    ltfHistory := f_processLeg(lastPivotBar, zzHighBar, lastPivotPrice, zzHigh, true, ltfHistory, boxHeightLimit)
    lastPivotBar := zzHighBar
    lastPivotPrice := zzHigh

if isSwingLow
    float boxHeightLimit = globalAtr14 / 10
    ltfHistory := f_processLeg(lastPivotBar, zzLowBar, lastPivotPrice, zzLow, false, ltfHistory, boxHeightLimit)
    lastPivotBar := zzLowBar
    lastPivotPrice := zzLow

//---------------------------------------------------------------------------------------------------------------------}
// Untested POC Extensions
//---------------------------------------------------------------------------------------------------------------------{
if untestedPocs.size() > 0
    for i = untestedPocs.size() - 1 to 0
        UntestedPOC p = untestedPocs.get(i)
        bool isTested = high >= p.price and low <= p.price
        
        if isTested
            p.pocLine.set_x2(bar_index)
            untestedPocs.remove(i)
        else
            p.pocLine.set_x2(bar_index)
            
    if untestedPocs.size() > 0
        int bullCount = 0
        int bearCount = 0
        for i = untestedPocs.size() - 1 to 0
            UntestedPOC p = untestedPocs.get(i)
            if p.isBull
                bullCount += 1
                if bullCount > 2
                    p.pocLine.set_x2(p.endBar)
                    untestedPocs.remove(i)
            else
                bearCount += 1
                if bearCount > 2
                    p.pocLine.set_x2(p.endBar)
                    untestedPocs.remove(i)

//---------------------------------------------------------------------------------------------------------------------}
// Volume Anomalies
//---------------------------------------------------------------------------------------------------------------------{
if showBubbles
    float volSma = ta.sma(volume, 20)
    if volSma > 0
        float volRatio = volume / volSma
        if volRatio >= bubbleMult
            bool isBull = close >= open
            color bubColor = isBull ? color.new(upEndC, 40) : color.new(dnEndC, 40)
            int dynSize = int(math.max(6, math.min(volRatio * 4, 20)))
            string bubText = volRatio >= (bubbleMult * 1.5) ? str.tostring(volume, format.volume) : ""
            label.new(bar_index, hl2, text=bubText, color=bubColor, style=label.style_circle, textcolor=color.white, size=dynSize, tooltip="Volume: " + str.tostring(volume, format.volume) + "\nSpike: " + str.tostring(volRatio, "#.##") + "x Average")

//---------------------------------------------------------------------------------------------------------------------}

				
			

Indicator Insider

Elliot Wave Pattern Indicator Analysis

This indicator is based on Elliott Wave Theory—one of the most well-known principles in technical analysis—which posits that markets move in repeatable, predictable wave patterns.

Volume Profile, Pivot Anchored by DGT Analysis

This indicator is based on the principle that “Trading volume clusters at key prices” combined with “Pivot Point theory”.

Working hypothesis: When price returns to zones that historically carried large volume (especially the PoC), the market tends to react strongly — either bouncing (support/resistance) or breaking through to continue the

PRO Scalper – A Russian Strategy

PRO Scalper believes price doesn’t move purely by technicals; it also reflects where real order flow and liquidity concentrate.

Instead of relying only on moving averages or candlestick patterns, this indicator combines five core building blocks:

Session VWAP
Opening Range
Trend Filter
Two independent Supply/Demand Zone pairs<br