1. Volumetric Order Flow Structure Strategy Description
Detects market-structure breaks (BOS/CHoCH) via pivots, attaching a "delta" bar showing the conviction of the breakout candle, a synthetic 15-row Volume Profile built from the pivot candle itself, and manipulation bubbles that flag liquidity grabs against still-active structure zones.
1.1 Indicator Concept
This indicator belongs to the same Break of Structure (BOS) / Change of Character (CHoCH) family as many other Smart Money Concepts tools: when price closes past the nearest swing pivot, that's evidence market structure has just changed. What sets it apart is that it attaches a "volumetric signature" to every break:
- Delta / Conviction Bar: a 3-layer horizontal bar whose "filled" inner portion is longer or shorter depending on how close the BREAKOUT CANDLE's close settled to the edge favoring the break's direction - the closer to the favorable edge, the longer the fill (higher conviction behind the break).
- Synthetic 15-Row Volume Profile: NOT real volume-at-price (no lower-timeframe data involved) - a geometric approximation instead. It divides the range of the PIVOT CANDLE ITSELF (not the breakout candle) into 15 rows, each given a bell-shaped weight (highest near the middle, tapering toward both edges), plus a bonus for any row that overlaps the candle's real body. The highest-weighted row is labeled "POC" (Point of Control) in orange.
- Manipulation Bubbles: while a structure zone ("Order Block") is still active, if price wicks past its boundary and gets rejected (no close-through), the indicator draws a warning bubble sized proportionally to that candle's relative volume - a flag for "liquidity was just hunted" right at the zone's edge.
Every break becomes a continuously tracked "Order Block" object that lives until price closes back through it ("mitigation" - it's invalidated), or gets retired FIFO-style once the number of active blocks exceeds the allowed limit.
1.2 Indicator Features
- 3-Layer Volumetric Structure Bar + BOS/CHoCH Label: a horizontal bar made of a faint background layer, a "glow" layer, and a solid core layer, spanning from the pivot candle to the confirmation candle, with a "BOS" (continuation) or "CHoCH" (reversal) label - drawn PERMANENTLY, never deleted afterward, acting as a historical marker of the break event.
- 15-Row Volume Profile (over the Order Block's range): horizontal colored bands covering the zone's height, rows overlapping the real candle body drawn more opaque than rows only overlapping a wick. The bands' right edge keeps extending every bar while the block stays active.
- Mini Histogram (right side of chart): a horizontal-bar-chart rendering of the same 15 weights, bar length proportional to weight, POC row colored orange, the rest colored by the block's bull/bear color.
- Manipulation Bubble + Volume Label: a warning circle appears exactly where price pierced a block's boundary and got rejected, with a text label showing that candle's volume (shorthand format "1.5K", "2.3M"...), bubble size split into 5 tiers (tiny → huge) based on relative volume.
- Overlap filter (optional): when enabled, a new block is only drawn if its volume is GREATER than every active block it overlaps in price - weaker overlapping blocks get deleted to make room, keeping the chart cleaner where many pivots occur close together.
- Max active block cap (FIFO): once the number of blocks exceeds "Max Recent Blocks", the OLDEST one (by creation order, not price) is deleted immediately, regardless of whether it's still price-valid.
- No color inputs, no alerts: unlike several other BOS/CHoCH indicators in this series, the bull/bear/POC colors here are hardcoded constants with no color picker, and the indicator ships with zero alertcondition() calls.
1.3 How to Use the Indicator
- Distinguish BOS from CHoCH to read context correctly: "BOS" is a break in the SAME direction as the current trend (continuation), "CHoCH" is a break AGAINST the current trend (the first sign of a reversal) - these two signal types should be handled with different strategic weight.
- Use the Order Block's [low, high] range as a dynamic support/resistance zone: when price returns to it and bounces, the zone stays "alive" on the chart; the moment price closes fully through it, every live drawing tied to that block disappears - a signal the zone has been invalidated and is no longer trustworthy.
- Treat a manipulation bubble as a liquidity-trap warning: a large bubble (high relative volume) appearing exactly at a block's boundary without a close-through suggests the level was just defended by real participation - adding confidence if price then reverses back into the block.
- Read the delta bar's filled length as a proxy for breakout conviction: a longer fill (nearly spanning the whole bar) means the breakout candle closed very close to its favorable edge - a strong, decisive break; a short fill means it closed near the unfavorable edge - a weak signal, more prone to failing.
- Don't treat the orange POC row as an actual traded-volume level: it's an illustrative synthetic shape (bell curve + body bonus), not a real volume profile computed from tick/lower-timeframe data - read it only as "where the pivot candle's body was most concentrated within its own range".
- Tune "Max Recent Blocks" and "Hide Overlapping Blocks" to control chart clutter on lower timeframes where pivots occur frequently and back-to-back.
1.4 How the Indicator Works
Inputs & Roles
- pivotLenInput ("Pivot Length", Integer, default: 3): number of bars on each side used to confirm a pivot high/low. Example: pivotLenInput=3 means a swing high is only confirmed 3 bars after it forms - a minimum 3-bar lag. Increase → only catches major swing points, fewer but more reliable BOS/CHoCH events. Decrease → more events, less lag but noisier.
- volLookbackInput ("Volume Lookback", Integer, default: 20): number of bars summed into the totalVolume variable.
- maxObsInput ("Max Recent Blocks", Integer, default: 5): maximum number of Order Blocks allowed to be active simultaneously. Example: when a 6th block is created while 5 previous ones are still "alive" → the OLDEST one (created first) is deleted immediately to make room, regardless of whether it's still price-valid. Increase → keeps more structural history visible but the chart gets more cluttered. Decrease → cleaner chart but old blocks vanish sooner.
- boxTransparencyInput ("Base Transparency", Integer 0-100, default: 80): base transparency of the 15-row Volume Profile bands. Rows overlapping the real candle body are always drawn 10 points more opaque than this value (more visible), rows only overlapping a wick are 10 points more transparent.
- hideOverlappingInput ("Hide Overlapping Blocks", Boolean, default: false): when ON, a new block is only drawn if the pivot candle's volume that created it is GREATER than every active block whose price range it overlaps; if so, all weaker overlapping blocks are fully deleted before the new one is drawn.
- showManipulationInput ("Show Manipulation Bubbles", Boolean, default: true): toggles the liquidity-grab warning bubbles.
- manipSizeInput ("Bubble Sensitivity", Float, default: 1.0, min 0.1): multiplier applied to the relative-volume ratio before bucketing bubble size. Example: candle volume = 1500, highest volume over 200 bars = 5000, manipSizeInput=1.0 → ratio = (1500/5000)×1.0 = 0.30 → falls into the "small" tier. Increase → the same actual volume produces a bigger bubble (easier to reach "huge"). Decrease → smaller bubbles for the same volume.
Main Logic Blocks
🎯 Flow 1: Pivot Detection
- ta.pivothigh(pivotLenInput, pivotLenInput) and ta.pivotlow(...) confirm a swing high/low once enough bars exist on both sides. When a new pivot forms: save lastPh/lastPl = the pivot's price, lastPhIdx/lastPlIdx = the pivot's TRUE bar position (bar_index - pivotLenInput, stepping back exactly the confirmation lag).
- Example: pivotLenInput=3. A swing high forms at bar 500, confirms at bar 503 → lastPh := the high's price, lastPhIdx := 503 - 3 = 500 (correctly points back to the actual pivot bar, not the confirmation bar).
🎯 Flow 2: Breakout Detection & BOS/CHoCH Labeling
- isCrossover = ta.crossover(close, lastPh): when true and lastPh still exists → calls draw_structure() with label "CHoCH" if the current trend is -1 (bearish, i.e. this is a reversal), or "BOS" otherwise (already +1 or neutral, i.e. a continuation) → updates trend := 1 → clears lastPh (so this pivot can't retrigger a second time).
- isCrossunder is symmetric using lastPl, setting trend := -1.
- Example: lastPh=1.2700 (from bar 500), current trend = -1. At bar 530, close=1.2705 crosses above 1.2700 → calls draw_structure(500, 1.2700, "CHoCH", BULL_COLOR, true) (since trend==-1 → a reversal); trend := 1; lastPh is cleared.
🔍 Flow 3: Overlap Filtering (if enabled)
- Scans all of activeObs for blocks whose price range [low, high] overlaps the block about to be created. If ANY overlapping block has volume ≥ the new pivot candle's volume → skip drawing the new block entirely (shouldDraw := false). Otherwise, delete all the (weaker) overlapping blocks before proceeding to draw the new one.
🖊️ Flow 4: Drawing the Volumetric Structure Bar
- range_ = the high-low range of the BREAKOUT CONFIRMATION candle (the current bar). deltaPct = how close that candle's close settled to the edge favoring the break's direction (e.g. for a bullish break: (close-low)/range_).
- dist = the number of bars from the pivot to now. fillEnd = pivot + round(dist × max(0.1, deltaPct)) - this is where the "filled" portion (glow + core) of the bar ends; the remainder (faint background only) stretches on to the current bar.
- Draws 3 stacked boxes: a very faint background (92% transparent, full length), a glow (80% transparent, length up to fillEnd), and a solid core (20% transparent, same length as glow) - none of these 3 boxes are stored in any array, so they persist PERMANENTLY on the chart. The "BOS"/"CHoCH" label is the same - drawn once, never deleted.
- Example: pivot at bar 500, breakout confirms at bar 530 → dist=30. Bar 530 has high=1.2710, low=1.2695, close=1.2705, isBullish=true → range_=0.0015, deltaPct=(1.2705-1.2695)/0.0015=0.667 → fillEnd=500+round(30×0.667)=500+20=520. The filled portion spans bar 500 to 520 (~67% of the bar's length), the rest (520→530) shows only the faint background layer.
🧮 Flow 5: Building the Synthetic 15-Row Volume Profile
- Divides the PIVOT CANDLE's [pLow, pHigh] range into 15 equal rows (rowStep). For each row i: distFromMid = |i - 7.5|, a base weight w = max(2, 12 - distFromMid×1.5) (bell-shaped, highest at the middle, lowest at both edges); if that row overlaps the real candle body (between pOpen and pClose) → add 5.
- The highest-weighted row becomes pocIndex (POC, colored orange). Two box sets are then drawn per row: colored bands covering the Order Block's range (boxes, right edge keeps extending every bar while the block stays alive) and a bar in the mini histogram on the right side of the chart (histBoxes, length = weight).
- Example: pHigh=1.2720, pLow=1.2680 → rowStep=0.002667. Row i=7 (closest to middle): distFromMid=0.5 → w=max(2,12-0.5×1.5)=11; if it overlaps the body → w=16 → usually becomes the POC. Row i=0 (top edge): distFromMid=7.5 → w=max(2,12-7.5×1.5)=max(2,0.75)=2 (minimum floor), unless it also overlaps the body (then +5=7).
📦 Flow 6: Registering the New Order Block + FIFO Cap
- The new block (with all its boxes and weights just built) is pushed into activeObs. If the array's size exceeds maxObsInput → array.shift() pulls out and deletes the FRONT element (oldest by creation order) - deleting every box/label it owns.
🗑️ Flow 7: Per-Bar Update - Mitigation Check
- Every bar, iterates backward through every block in activeObs: mitigated = true if a bullish block's close drops below ob.low, or a bearish block's close rises above ob.high. If true: delete ALL of that block's profile boxes, histogram boxes, manipulation bubbles, and accumulated volume labels, then remove it from the array.
- Example: a bullish block with ob.low=1.2680. Price later closes at 1.2675 (<1.2680) → mitigated=true → every live drawing tied to that block is deleted. The original 3-layer delta bar + BOS/CHoCH label (not tracked in any array) remain untouched on the chart forever as a historical marker.
🔄 Flow 8: Per-Bar Update - Extending Live Drawings
- For blocks NOT yet mitigated: the right edge of every profile box is extended to bar_index + 10; the histogram boxes' coordinates are reassigned (using the same stored weights and bounds - values don't actually change).
🫧 Flow 9: Manipulation Detection
- For still-active blocks: raidHigh = the block is bearish AND the current high > ob.high AND the current close ≤ ob.high (price wicked above the boundary then got rejected). raidLow is symmetric for a bullish block.
- When true: manipVolScale = (current bar's volume / highest volume over 200 bars) × manipSizeInput, bucketed into 5 size tiers (tiny through huge). Draws one circle bubble (colored BEAR_COLOR if raidHigh, BULL_COLOR if raidLow) + one text label showing the shorthand volume, both stored into that block's arrays to be deleted together later when the block is mitigated or FIFO-retired.
- Example: a bearish block with ob.high=1.2650. Current bar: high=1.2658 (>1.2650), close=1.2645 (≤1.2650) → raidHigh=true. Candle volume=1500, highest volume over 200 bars=5000, manipSizeInput=1.0 → ratio=(1500/5000)×1.0=0.30 → falls into the "small" tier. A red bubble (BEAR_COLOR) appears at price 1.2658, the text label shows "1.5K".
Outputs & Usage Roles
- Delta bar + BOS/CHoCH label: a permanent historical marker pinpointing exactly when, at what price, and with how much conviction each structure break occurred.
- 15-row Volume Profile bands + histogram + POC row: a visual read of "where the pivot candle's body was concentrated within its own range" - a reference for a likely reaction zone when price revisits the block.
- Manipulation bubbles + labels: a live warning that an active block's boundary was just tested and defended, sized by relative volume.
- A block's disappearance: signals price has decisively closed through it (mitigated) - that structural reference is no longer valid.


