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.
🔷 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 Direction | Trigger Condition | Action |
|---|---|---|
| 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 × overlapRatiodeltaContrib = (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.
- 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.
// 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 volumeDistribution
array deltaDistribution
float maxVolumeInProfile
int maxVolumeIndex
float pocPrice
type UntestedPOC
line pocLine
float price
bool isBull
int endBar
//---------------------------------------------------------------------------------------------------------------------}
// State Variables
//---------------------------------------------------------------------------------------------------------------------{
var array ltfHistory = array.new()
var array untestedPocs = array.new()
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 legBars) =>
float barRange = legHigh - legLow
int numBoxes = math.max(1, int(math.round(barRange / targetBoxHeight)))
float adjustedBoxHeight = barRange / numBoxes
array volDist = array.new_float(numBoxes, 0.0)
array 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 history, float baseBoxHeight) =>
line.new(startBar, startPrice, endBar, endPrice, color=color.new(color.gray, 50), width=2, style=line.style_dotted)
array legBars = array.new()
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 newHistory = array.new()
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.


