Isolated Scroll Container

1. Indicator Description – Structural Leg Profiler [LuxAlgo]

Detects structural swing legs, then builds a volume profile per leg using 1-minute data to reveal where the most volume was traded inside each price move

1.1 Indicator Concept

Most volume indicators (like the classic Volume Profile) show where volume was traded over the entire visible chart or session. The Structural Leg Profiler takes a different approach: it breaks the chart into individual structural legs — distinct price moves from one swing pivot to the next — and then builds a separate volume profile for each leg.

The idea is that each leg represents one "chapter" of market activity. By seeing the volume distribution within each chapter, a trader can answer questions like: "Was the majority of this rally driven by buyers at the bottom, or did most of the volume come in near the top?" The price level with the most volume inside a leg is called the Point of Control (POC) — the price level the market showed the most interest in during that move.

To make the volume data as precise as possible, the indicator pulls 1-minute bar data from TradingView's lower-timeframe feed (regardless of what chart timeframe you are on). Each 1-minute bar's volume is split into estimated buy volume and sell volume using the candle's close position within its high-low range. This gives a richer picture than just raw volume per bar.

On top of the profiles, the indicator also highlights volume anomaly candles (unusually high volume spikes) with colored circle bubbles, giving an instant visual cue for candles where smart money may be active.

1.2 Indicator Features

  • Volume Profile Boxes per Structural Leg: For every confirmed swing leg (up or down), a series of horizontal price boxes is drawn covering the leg's price range. Each box shows a mini ASCII bar chart (filled blocks vs empty blocks) representing relative volume at that price level, plus an optional numeric volume value.
  • Point of Control (POC) Line: A dashed horizontal line marks the price level with the highest volume within the leg. This is the most significant price level for that move.
  • Untested POC Extension: POC lines can optionally extend forward (to the right) until price actually comes back and tests that level. A maximum of 2 untested bull POCs and 2 untested bear POCs are kept active at any time to avoid clutter.
  • Summary Label per Leg: At the midpoint of each leg, a small label displays: total leg volume, delta (buy volume minus sell volume with a + or - sign), and the POC price.
  • Structural Leg Line: A dotted gray line connecting the start pivot to the end pivot of each leg, making the structure visually clear.
  • Two Box Color Modes: "Volume Gradient" colors boxes along a 3-stop color gradient (low-vol color → mid-vol color → high-vol color) based on position relative to the POC. "Delta (Buy vs Sell)" colors boxes green if buy volume dominated at that level and red if sell volume dominated.
  • Volume Anomaly Bubbles: On any bar where volume exceeds a set multiple of the 20-bar SMA, a colored circle is drawn at the midpoint (hl2) of the candle. The circle grows larger as the spike is bigger. If the spike is especially large (1.5× the threshold), the actual volume number is shown inside the bubble.

1.3 How to Use the Indicator

  • Identify high-volume price nodes within each leg: The tallest bars in a volume profile (most filled blocks) show where the market spent the most time and traded the most volume. These levels often act as support or resistance when price revisits them.
  • Trade POC retests: When price returns to a leg's POC (especially an extended untested POC), it is a high-probability area to watch for a reaction. If the POC was formed during a bull leg, expect potential support there on a pullback.
  • Read the Delta label to assess conviction: A large positive delta (e.g. "+2.5M") on a bull leg means buyers dominated strongly throughout — this leg was driven by aggressive buying. A near-zero or negative delta on an up leg suggests the rally was weak or sell-side absorption was high.
  • Use Delta box coloring to spot absorption or distribution: In a bull leg, if the boxes near the top of the move are colored red (sell-dominant delta), it signals that sellers were absorbing the buying at those levels — a potential reversal warning.
  • Volume bubble candles mark inflection points: A large bubble on a candle often coincides with a swing pivot, a breakout, or a reversal. Bullish bubbles (teal/cyan) in a downtrend or bearish bubbles (red) in an uptrend are particularly worth noting as potential turning points.
  • Adjust Swing Multiplier to match your trading style: Higher values create fewer, larger legs (better for swing traders). Lower values capture micro-swings (better for scalpers or intraday traders). Watch that too-low a value creates too many small legs and clutters the chart.

1.4 How the Indicator Works

Inputs & Their Roles
  • atrPeriod (Integer, default 5): The ATR lookback period used to measure recent volatility. A shorter period (e.g. 3) reacts faster to recent price swings; a longer period (e.g. 14) produces a smoother, less reactive baseline.
  • swingMult (Decimal, default 2.5): The key sensitivity control. The indicator triggers a new swing pivot when price reverses by ATR(atrPeriod) × swingMult. Higher values (e.g. 4.0) create bigger, fewer legs — only major structural moves. Lower values (e.g. 1.0) capture small intraday swings. If this is too low, you will see many tiny legs all overlapping.
  • maxBoxes (Integer, default 50, range 10–150): Maximum number of horizontal price boxes drawn per leg profile. If the leg's price range would require more boxes than this limit, the box height is automatically increased to fit. More boxes means finer resolution but more visual density.
  • alignMode (Options: Left / Right / Center): Controls whether the ASCII bar text inside each box is left-aligned, right-aligned, or centered.
  • showBoxVol (Checkbox, default on): When enabled, the actual volume number is printed after the ASCII bar inside each box. Turning off keeps the profile cleaner visually.
  • extendPoc (Checkbox, default on): When enabled, each leg's POC line is extended to the right until price comes back and crosses that level (a "test"). Only the 2 most recent untested bull POCs and 2 most recent untested bear POCs are kept active at once.
  • showBubbles (Checkbox, default on): Enables volume anomaly circle labels on candles with unusually high volume.
  • bubbleMult (Decimal, default 2.0): The volume spike threshold. A candle's volume must be at least this many times the 20-bar SMA to trigger a bubble. Setting to 3.0 only shows truly extreme spikes; setting to 1.5 shows more frequent anomalies.
  • colorMode (Options: Volume Gradient / Delta): "Volume Gradient" paints boxes along a color gradient based on their volume relative to the POC. "Delta (Buy vs Sell)" colors each box green or red based on whether buy or sell volume dominated at that price level.
  • upStartC / upMidC / upEndC: Three color stops for the gradient of bullish leg boxes — from low-volume color to mid-volume color to high-volume color. Default is dark blue → bright blue → cyan.
  • dnStartC / dnMidC / dnEndC: Same three-stop gradient for bearish leg boxes. Default is dark purple → magenta → red.
Main Logic Blocks

🔷 Flow 1 – Lower-Timeframe Data Collection (1-Minute Bars)

On every chart bar, the indicator fetches all 1-minute sub-bars that fall within that chart bar using request.security_lower_tf. For each 1-minute bar, it estimates buy and sell volume:

buyVol = totalVolume × (close − low) / (high − low)
sellVol = totalVolume × (high − close) / (high − low)
If close is near the high of the 1m bar → most volume is attributed to buyers. If close is near the low → most to sellers. This is a simplified estimate (no actual order flow data required).

All 1-minute bars are stored in a large running list called ltfHistory (capped at 90,000 entries). When the chart timeframe is too high for 1m data to be available, the indicator falls back to using the chart bar itself.

🔷 Flow 2 – Swing Detection (ATR-Based ZigZag)

The indicator tracks direction using a variable zzDir (1 = currently looking for a high, -1 = currently looking for a low). The reversal threshold is:

revAmount = ATR(atrPeriod) × swingMult
Current DirectionTrigger ConditionAction
Upswing (zzDir = 1) Price keeps making new highs → update zzHigh. Then if low drops more than revAmount below zzHigh → swing high confirmed. Mark isSwingHigh = true. Record zzHigh as the pivot. Flip zzDir to -1.
Downswing (zzDir = -1) Price keeps making new lows → update zzLow. Then if high rises more than revAmount above zzLow → swing low confirmed. Mark isSwingLow = true. Record zzLow as the pivot. Flip zzDir to 1.

Example: ATR = 10, swingMult = 2.5 → revAmount = 25. Price rallies from 1000 to 1080 (tracking zzHigh = 1080). Then price drops to 1054 (= 1080 − 26, which is more than 25) → swing high confirmed at 1080.

🔷 Flow 3 – Leg Processing (Profile Build Trigger)

When a swing pivot is confirmed, the indicator calls f_processLeg() for the completed leg — the stretch from the previous pivot to the new one. This function:

  • Draws a dotted gray structural line from lastPivotBar to the new pivot bar.
  • Scans through ltfHistory and collects only the 1-minute bars whose chartBar index falls within the leg's time range.
  • Accumulates total buy volume, total sell volume, the true high, and the true low of all those 1m bars.
  • Calculates a target box height: ATR(14) / 10. If the leg's full range requires more boxes than maxBoxes, the box height is increased to fit.
  • Calls f_createProfile() to build the distribution, then profile.draw() to render it.
  • Trims ltfHistory to keep only bars from the new pivot onwards (old data is discarded to save memory).

🔷 Flow 4 – Volume Profile Construction

Inside f_createProfile(), the leg's price range is divided into N horizontal boxes. For each 1-minute bar and each box, the overlap between the 1m bar's high-low range and the box's price range is calculated:

overlapRatio = overlapHeight / (1m bar high − 1m bar low)
volContrib = 1m bar volume × overlapRatio
deltaContrib = (buyVol − sellVol) × overlapRatio

Example: a 1m bar has a range of 10 points and total volume of 500. A price box overlaps 4 of those 10 points → overlapRatio = 0.4 → this box receives 200 units of volume from this bar. All 1m bars contribute their volume to all overlapping boxes.

After all bars are processed, the box with the highest total volume is identified as the POC (Point of Control), and its center price becomes pocPrice.

🔷 Flow 5 – Profile Rendering (Boxes, POC Line, Summary Label)

Inside profile.draw(), three types of chart objects are created:

  • Price boxes: One box.new() per price level. The text inside is an ASCII bar like ████████░░░░░ 1.23K — the number of filled blocks scales with how much volume that box holds relative to the POC box. Color depends on colorMode:
    • Volume Gradient mode: Boxes below the POC blend from upStartC → upMidC; boxes above blend from upMidC → upEndC. The POC box itself gets midC.
    • Delta mode: Green gradient if box delta > 0 (buyers dominated), red gradient if delta < 0 (sellers dominated), gray if neutral.
  • POC dashed line: A dashed horizontal line at pocPrice, drawn from the leg's start bar to end bar (and optionally extended further by the POC Extension system).
  • Summary label: A small label at the midpoint of the leg, positioned above (for bull legs) or below (for bear legs) the profile, showing total leg volume, delta with sign, and POC price.

🔷 Flow 6 – Untested POC Extension

When extendPoc is on, each new POC is added to a list called untestedPocs. On every bar, the indicator:

  • Checks if price has crossed each POC (bar's high >= poc price AND bar's low <= poc price). If so → the POC is "tested" → its line is stopped at the current bar and removed from the list.
  • If not tested → extends the POC line to the current bar.
  • Limits to a maximum of 2 untested bull POCs and 2 untested bear POCs. If the count exceeds 2, the oldest excess POC is cut off at its original end bar.

🔷 Flow 7 – Volume Anomaly Bubbles

On every bar (if showBubbles is on):

  • Calculate volSma = SMA(volume, 20) and volRatio = volume / volSma.
  • If volRatio >= bubbleMult → draw a circle label at hl2 (midpoint of the bar).
  • Circle color: teal/cyan for bull candles, red for bear candles (using the indicator's high-vol color stops).
  • Circle size: dynamically scaled as clamp(volRatio × 4, 6, 20). A 3× spike → size 12; a 5× spike → size 20 (max).
  • If volRatio >= bubbleMult × 1.5 → show the actual volume number as text inside the circle.
Outputs & Their Role in Trading
  • Volume profile box columns: The visual "histogram" per leg. Taller/more-filled boxes = more volume at that price level. Identifies the value area and the highest-volume node (POC) within each structural move.
  • POC dashed line: The single most important price level within each leg. Acts as a magnet — price tends to return and react at the POC. Extended untested POCs become forward-looking support/resistance levels.
  • Summary label (Leg Vol / Delta / POC): Instant snapshot of the leg's conviction. A large positive delta on a bull leg confirms buyer dominance. A negative delta on a bull leg signals potential weakness or distribution.
  • Dotted structural leg line: Shows the start and end pivot of each leg, making the ZigZag structure visually explicit.
  • Volume anomaly bubbles: Circle markers on extreme-volume candles. Often coincide with key decision points — reversals, breakouts, or absorption events. Larger circles = more extreme the spike.
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

VWAP Volume Profile Indicator – Strategy

Một hồ sơ khối lượng hai chiều dựng trên đường VWAP thay vì trên giá: khối lượng của mỗi nến được gắn dấu cộng hoặc trừ tuỳ VWAP đang lên hay xuống, rồi gom lại thành biểu đồ cột nằm ngang chìa ra cả hai phía ở mép phải chart.

Market Shift Levels Indicator – Strategy

Every time the HMA moving average flips its slope, the indicator locks in the high or the low of that exact candle as a “boundary level”, colors every candle relative to it, and flags the moments price pokes through the level and immediately fails.

Dynamic Swing Anchored VWAP Indicator – Strategy

Automatically anchors a VWAP line to the most recent swing reversal point, rebuilds the whole line from that anchor every time market structure flips, and tags each anchor with an HH / HL / LH / LL structure label.