Indicator · Pine Script v6 · On the chart

Volume & Key Levels

by MoDarK-MK· code credited to {{SHORTTITLE}}

This overlay indicator template plots previous-day and previous-week highs and lows and marks liquidity sweeps when price pierces a level on elevated volume and closes back inside.

View on GitHub

GitHub stars1on the repository
Pine versionv6current
Lines of code382
Settings19inputs
LicenceMPL-2.0
Last update8 weeks ago4 Sep 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

382 lines of Pine Script v6 from assets/templates/indicator_volume_keylevels_template.pine, published under MPL-2.0. Keep the author's credit and licence lines when you reuse it.

indicator_volume_keylevels_template.pine
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © {{SHORTTITLE}}

//@version=6
indicator(
     "{{TITLE}}", shorttitle="{{SHORTTITLE}}", overlay=true,
     max_boxes_count=500, max_lines_count=500, max_labels_count=500,
     max_bars_back=1000
     )

// Template for high-precision Volume & Key Levels indicators.
// Combines Auction Market Theory (Volume Profile & vPOCs), Multi-Timeframe Key
// Levels with Liquidity Sweeps, Anchored VWAP, and Order Flow Delta/Absorption.

// ————— Constants
string THEME_DARK   = "Dark"
string THEME_LIGHT  = "Light"
string THEME_AUTO   = "Auto"
string THEME_CUSTOM = "Custom"

color BULL_DARK     = #089981
color BEAR_DARK     = #f23645
color ACCENT_DARK   = #d98b1f
color NEUTRAL_DARK  = #b2b5be

color BULL_LIGHT    = #00796b
color BEAR_LIGHT    = #c62828
color ACCENT_LIGHT  = #b26a00

// ————— Inputs: Multi-Timeframe Key Levels
string G_HTF = "Key Levels & MTF"
bool   showPdhPdlInput   = input.bool(
     true, "Show Prev Day High/Low (PDH/PDL)", group=G_HTF,
     tooltip="Plots the Previous Day's High and Low levels without lookahead bias.")
bool   showPwhPwlInput   = input.bool(
     true, "Show Prev Week High/Low (PWH/PWL)", group=G_HTF,
     tooltip="Plots the Previous Week's High and Low macro liquidity extremes.")
bool   showSweepsInput   = input.bool(
     true, "Detect Liquidity Sweeps", group=G_HTF,
     tooltip="Highlights false breakouts where price pierces a key level with volume surge and closes back inside.")
float  sweepVolMultInput = input.float(
     1.8, "Sweep Volume Multiplier", minval=1.0, maxval=10.0, step=0.1, group=G_HTF,
     tooltip="Volume must exceed this multiple of the 20-bar average to qualify as an institutional sweep.")

// ————— Inputs: Volume Profile
string G_VP = "Volume Profile"
bool   showVpInput       = input.bool(
     true, "Enable Volume Profile", group=G_VP,
     tooltip="Computes horizontal volume distribution, POC, and Value Area (VAH/VAL).")
int    vpLookbackInput   = input.int(
     150, "Profile Lookback (Bars)", minval=20, maxval=800, group=G_VP,
     tooltip="Number of chart bars included in the rolling volume profile.")
int    vpRowsInput       = input.int(
     24, "Price Rows", minval=10, maxval=50, group=G_VP,
     tooltip="Number of horizontal price bins used for volume profile resolution.")
float  vaPercentInput    = input.float(
     70.0, "Value Area %", minval=50.0, maxval=90.0, step=1.0, group=G_VP,
     tooltip="Percentage of volume encompassed by Value Area (Standard Auction Theory uses 70%).")

// ————— Inputs: Anchored VWAP & Order Flow
string G_OF = "Order Flow & Anchored VWAP"
bool   showAvwapInput    = input.bool(
     true, "Show Anchored VWAP", group=G_OF,
     tooltip="Plots Volume-Weighted Average Price anchored to the chosen period.")
string avwapAnchorInput  = input.string(
     "Session", "VWAP Anchor Period", options=["Session", "Week", "Month"], group=G_OF,
     tooltip="Reset frequency for the Anchored VWAP accumulation.")
bool   showAvwapBands    = input.bool(
     true, "Show VWAP ±1σ Bands", group=G_OF,
     tooltip="Plots first standard deviation volume dispersion bands around VWAP.")
bool   detectAbsorbInput = input.bool(
     true, "Highlight Volume Absorption", group=G_OF,
     tooltip="Identifies bars with unusually high volume and narrow spread (Effort vs Result divergence).")

// ————— Inputs: Appearance & Dashboard
string G_APP = "Appearance & Dashboard"
string themeInput        = input.string(
     THEME_DARK, "Theme", options=[THEME_DARK, THEME_LIGHT, THEME_AUTO, THEME_CUSTOM], group=G_APP,
     tooltip="Color theme palette adaptation.")
color  customBullInput   = input.color(
     #089981, "Custom Bull", group=G_APP, inline="cust",
     tooltip="Bullish highlight color for Custom theme.")
color  customBearInput   = input.color(
     #f23645, "Custom Bear", group=G_APP, inline="cust",
     tooltip="Bearish highlight color for Custom theme.")
bool   showDashInput     = input.bool(
     true, "Show HUD Dashboard", group=G_APP,
     tooltip="Displays live on-chart heads-up summary table.")
string tablePosInput     = input.string(
     "Top Right", "Dashboard Position",
     options=["Top Right", "Top Left", "Bottom Right", "Bottom Left"], group=G_APP,
     tooltip="Corner placement for the HUD table.")
int    panelTranspInput  = input.int(
     15, "Dashboard Transparency", minval=0, maxval=90, group=G_APP,
     tooltip="Background opacity for the HUD table.")
bool   testModeInput     = input.bool(
     false, "Test Mode", group="Debug/Test",
     tooltip="Runs internal test assertions and displays validation counters.")

// ————— Theme Resolution Helpers
_isLightChart() =>
    r = color.r(chart.bg_color)
    g = color.g(chart.bg_color)
    b = color.b(chart.bg_color)
    r * 0.299 + g * 0.587 + b * 0.114 > 128.0

getBullColor() =>
    switch themeInput
        THEME_LIGHT  => BULL_LIGHT
        THEME_AUTO   => _isLightChart() ? BULL_LIGHT : BULL_DARK
        THEME_CUSTOM => customBullInput
        =>              BULL_DARK

getBearColor() =>
    switch themeInput
        THEME_LIGHT  => BEAR_LIGHT
        THEME_AUTO   => _isLightChart() ? BEAR_LIGHT : BEAR_DARK
        THEME_CUSTOM => customBearInput
        =>              BEAR_DARK

getAccentColor() =>
    switch themeInput
        THEME_LIGHT => ACCENT_LIGHT
        =>             ACCENT_DARK

// library-sync-exempt: this variant supports a third theme, THEME_AUTO, which
// follows the chart's own light/dark setting. The library has only two, because
// a published library cannot read the chart it is imported into.
getTextColor() =>
    themeInput == THEME_LIGHT or (themeInput == THEME_AUTO and _isLightChart()) ? #131722 : #d1d4dc

// library-sync-exempt: this variant supports a third theme, THEME_AUTO, which
// follows the chart's own light/dark setting. The library has only two, because
// a published library cannot read the chart it is imported into.
getMutedColor() =>
    themeInput == THEME_LIGHT or (themeInput == THEME_AUTO and _isLightChart()) ? #4a4e58 : #b2b5be

// library-sync-exempt: this variant supports a third theme, THEME_AUTO, which
// follows the chart's own light/dark setting. The library has only two, because
// a published library cannot read the chart it is imported into.
getPanelColor() =>
    color.new(
         themeInput == THEME_LIGHT or (themeInput == THEME_AUTO and _isLightChart()) ? #ffffff : #131722,
         panelTranspInput)

getTablePosition() =>
    switch tablePosInput
        "Top Left"     => position.top_left
        "Bottom Right" => position.bottom_right
        "Bottom Left"  => position.bottom_left
        =>                position.top_right

// ————— Safe Zero-Repaint HTF Data
[pdh, pdl] = request.security(
     syminfo.tickerid, "D", [high[1], low[1]],
     lookahead=barmerge.lookahead_off, gaps=barmerge.gaps_off)

[pwh, pwl] = request.security(
     syminfo.tickerid, "W", [high[1], low[1]],
     lookahead=barmerge.lookahead_off, gaps=barmerge.gaps_off)

// ————— Order Flow & Cumulative Volume Delta (CVD)
float barRange = high - low
float buyShare = barRange > 0 ? (close - low) / barRange : 0.5
float barBuyVol = nz(volume) * buyShare
float barSellVol = nz(volume) * (1.0 - buyShare)
float barDelta = barBuyVol - barSellVol

var float cvd = 0.0
bool isNewDay = timeframe.change("D")
if isNewDay
    cvd := barDelta
else
    cvd += barDelta

// ————— Effort vs Result / Absorption Detection
float atr14 = ta.atr(14)
float avgVol20 = ta.sma(nz(volume), 20)
float spreadRatio = atr14 > 0 ? math.max(0.1, barRange / atr14) : 1.0
float volRatio = avgVol20 > 0 ? nz(volume) / avgVol20 : 1.0
float evr = volRatio / spreadRatio

bool isAbsorption = detectAbsorbInput and evr > 2.2 and nz(volume) >= (avgVol20 * 1.5)

// ————— Liquidity Sweeps
bool pdhSweep = showSweepsInput and not na(pdh) and high > pdh and close < pdh and
     nz(volume) >= (avgVol20 * sweepVolMultInput)
bool pdlSweep = showSweepsInput and not na(pdl) and low < pdl and close > pdl and
     nz(volume) >= (avgVol20 * sweepVolMultInput)

// ————— Anchored VWAP Calculation
string anchorTf = avwapAnchorInput == "Week" ? "W" : (avwapAnchorInput == "Month" ? "M" : "D")
bool isAnchorReset = timeframe.change(anchorTf)

var float vwapSumSrcVol = 0.0
var float vwapSumVol    = 0.0
var float vwapSumSqVol  = 0.0

if isAnchorReset
    vwapSumSrcVol := 0.0
    vwapSumVol    := 0.0
    vwapSumSqVol  := 0.0

float curTypPrice = hlc3
float curVol      = nz(volume)
vwapSumSrcVol += curTypPrice * curVol
vwapSumVol    += curVol
vwapSumSqVol  += math.pow(curTypPrice, 2) * curVol

float avwap = vwapSumVol > 0 ? vwapSumSrcVol / vwapSumVol : curTypPrice
float vwapVar = vwapSumVol > 0 ? math.max(0.0, (vwapSumSqVol / vwapSumVol) - math.pow(avwap, 2)) : 0.0
float vwapDev = math.sqrt(vwapVar)
float avwapBand1Up = avwap + vwapDev
float avwapBand1Dn = avwap - vwapDev

// ————— Volume Profile & vPOC Arrays (Pre-allocated Pools)
var float[] vpPricesPool = array.new_float(50, 0.0)
var float[] vpVolsPool   = array.new_float(50, 0.0)

var float curPoc = na
var float curVah = na
var float curVal = na

if showVpInput and barstate.islast
    int lb = math.min(bar_index, vpLookbackInput)
    int nRows = math.min(50, vpRowsInput)
    float hiB = -1.0e10
    float loB = 1.0e10

    for i = 0 to lb - 1
        hiB := math.max(hiB, high[i])
        loB := math.min(loB, low[i])

    float rowStep = (hiB > loB and nRows > 0) ? (hiB - loB) / nRows : syminfo.mintick
    array.fill(vpVolsPool, 0.0)
    for r = 0 to nRows - 1
        array.set(vpPricesPool, r, loB + (r + 0.5) * rowStep)

    float totalVPVol = 0.0
    for i = 0 to lb - 1
        float v = nz(volume[i])
        int rLo = math.max(0, math.min(nRows - 1, int(math.floor((low[i] - loB) / rowStep))))
        int rHi = math.max(0, math.min(nRows - 1, int(math.floor((high[i] - loB) / rowStep))))
        int span = math.max(1, rHi - rLo + 1)
        float vSplit = v / span
        for r = rLo to rHi
            array.set(vpVolsPool, r, array.get(vpVolsPool, r) + vSplit)
        totalVPVol += v

    float maxV = 0.0
    int   pIdx = 0
    for r = 0 to nRows - 1
        float v = array.get(vpVolsPool, r)
        if v > maxV
            maxV := v
            pIdx := r

    curPoc := array.get(vpPricesPool, pIdx)
    float targetVa = totalVPVol * (vaPercentInput / 100.0)
    float vaAccum  = maxV
    int   uP = pIdx + 1
    int   dP = pIdx - 1

    while vaAccum < targetVa and (uP < nRows or dP >= 0)
        float uV = uP < nRows ? array.get(vpVolsPool, uP) : 0.0
        float dV = dP >= 0 ? array.get(vpVolsPool, dP) : 0.0
        if uV >= dV and uP < nRows
            vaAccum += uV
            uP += 1
        else if dP >= 0
            vaAccum += dV
            dP -= 1
        else if uP < nRows
            vaAccum += uV
            uP += 1

    curVah := array.get(vpPricesPool, math.min(nRows - 1, uP - 1))
    curVal := array.get(vpPricesPool, math.max(0, dP + 1))

// ————— Plots & Visuals
color bullC   = getBullColor()
color bearC   = getBearColor()
color accentC = getAccentColor()

// HTF Levels
plot(showPdhPdlInput ? pdh : na, "PDH", color=color.new(accentC, 20), linewidth=1, style=plot.style_linebr)
plot(showPdhPdlInput ? pdl : na, "PDL", color=color.new(accentC, 20), linewidth=1, style=plot.style_linebr)
plot(showPwhPwlInput ? pwh : na, "PWH", color=color.new(accentC, 0), linewidth=2, style=plot.style_linebr)
plot(showPwhPwlInput ? pwl : na, "PWL", color=color.new(accentC, 0), linewidth=2, style=plot.style_linebr)

// Anchored VWAP & Dispersion Bands
plot(showAvwapInput ? avwap : na, "AVWAP", color=color.new(#2962ff, 0), linewidth=2)
plot(showAvwapInput and showAvwapBands ? avwapBand1Up : na, "AVWAP +1σ",
     color=color.new(#2962ff, 50), linewidth=1, style=plot.style_circles)
plot(showAvwapInput and showAvwapBands ? avwapBand1Dn : na, "AVWAP -1σ",
     color=color.new(#2962ff, 50), linewidth=1, style=plot.style_circles)

// Signals & Markers
plotshape(pdhSweep, "PDH Sweep (Bearish)", shape.triangledown, location.abovebar,
     bearC, size=size.small, text="SWEEP")
plotshape(pdlSweep, "PDL Sweep (Bullish)", shape.triangleup, location.belowbar,
     bullC, size=size.small, text="SWEEP")
plotshape(isAbsorption, "Volume Absorption", shape.diamond, location.bottom, accentC, size=size.tiny)

// ————— HUD Dashboard Table
var table hudTable = table.new(getTablePosition(), 2, 7, border_width=1)

formatVolCompact(float v) =>
    float av = math.abs(nz(v))
    switch
        av >= 1000000000 => str.tostring(v / 1000000000, "#.##") + "B"
        av >= 1000000    => str.tostring(v / 1000000, "#.##") + "M"
        av >= 1000       => str.tostring(v / 1000, "#.#") + "K"
        =>                  str.tostring(nz(v), "#.#")

if showDashInput and barstate.islast
    color bgP = getPanelColor()
    color txtP = getTextColor()
    color mutP = getMutedColor()

    table.cell(hudTable, 0, 0, "VOL & KEY LEVELS", bgcolor=bgP, text_color=txtP, text_size=size.small)
    table.cell(hudTable, 1, 0, "HUD", bgcolor=bgP, text_color=accentC, text_size=size.small)

    string deltaStr = (barDelta >= 0 ? "+" : "") + formatVolCompact(barDelta)
    table.cell(hudTable, 0, 1, "Price / Delta", bgcolor=bgP, text_color=mutP, text_size=size.small)
    table.cell(hudTable, 1, 1, str.tostring(close, "#.##") + " (" + deltaStr + ")",
         bgcolor=bgP, text_color=barDelta >= 0 ? bullC : bearC, text_size=size.small)

    table.cell(hudTable, 0, 2, "Cumulative Delta (CVD)", bgcolor=bgP, text_color=mutP, text_size=size.small)
    table.cell(hudTable, 1, 2, formatVolCompact(cvd), bgcolor=bgP,
         text_color=cvd >= 0 ? bullC : bearC, text_size=size.small)

    table.cell(hudTable, 0, 3, "Volume Profile POC", bgcolor=bgP, text_color=mutP, text_size=size.small)
    table.cell(hudTable, 1, 3, na(curPoc) ? "--" : str.tostring(curPoc, "#.##"),
         bgcolor=bgP, text_color=accentC, text_size=size.small)

    string vaStr = (na(curVah) ? "--" : str.tostring(curVah, "#.##")) + " / " +
         (na(curVal) ? "--" : str.tostring(curVal, "#.##"))
    table.cell(hudTable, 0, 4, "Value Area (VAH/VAL)", bgcolor=bgP, text_color=mutP, text_size=size.small)
    table.cell(hudTable, 1, 4, vaStr, bgcolor=bgP, text_color=txtP, text_size=size.small)

    table.cell(hudTable, 0, 5, "Anchored VWAP", bgcolor=bgP, text_color=mutP, text_size=size.small)
    table.cell(hudTable, 1, 5, str.tostring(avwap, "#.##"), bgcolor=bgP, text_color=#2962ff, text_size=size.small)

    string evrSuffix = isAbsorption ? " (ABSORB)" : ""
    table.cell(hudTable, 0, 6, "Effort vs Result", bgcolor=bgP, text_color=mutP, text_size=size.small)
    table.cell(hudTable, 1, 6, str.tostring(evr, "#.##") + evrSuffix,
         bgcolor=bgP, text_color=isAbsorption ? accentC : txtP, text_size=size.small)

// ————— Alerts
alertcondition(pdhSweep, "PDH Liquidity Sweep", "Bearish liquidity sweep detected above Previous Day High.")
alertcondition(pdlSweep, "PDL Liquidity Sweep", "Bullish liquidity sweep detected below Previous Day Low.")
alertcondition(isAbsorption, "Volume Absorption Alert", "High volume absorption detected at current bar.")

// ————— Debug / Test Block
int TEST_COUNT = 3
var int passCount = 0
var int failCount = 0

assertFailed(bool condition, string description) =>
    if not condition
        label.new(
             bar_index, high, "FAIL: " + description, color=#f23645,
             textcolor=color.white, style=label.style_label_down, size=size.tiny)
    condition ? 0 : 1

if testModeInput
    int fails = 0
    fails += assertFailed(buyShare >= 0.0 and buyShare <= 1.0, "buyShare out of range")
    fails += assertFailed(not na(avwap), "avwap is na")
    fails += assertFailed(evr >= 0.0, "evr is negative")
    failCount += fails
    passCount += TEST_COUNT - fails

var table testTable = table.new(position.bottom_left, 2, 2, border_width=1)
if testModeInput and barstate.islast
    table.cell(testTable, 0, 0, "Passed", bgcolor=BULL_DARK, text_color=color.white)
    table.cell(testTable, 1, 0, str.tostring(passCount), bgcolor=BULL_DARK, text_color=color.white)
    table.cell(testTable, 0, 1, "Failed",
         bgcolor=failCount == 0 ? NEUTRAL_DARK : BEAR_DARK, text_color=color.white)
    table.cell(testTable, 1, 1, str.tostring(failCount),
         bgcolor=failCount == 0 ? NEUTRAL_DARK : BEAR_DARK, text_color=color.white)

Overview

Volume & Key Levels builds a rolling volume profile with point of control and value area, plus an anchored VWAP that can reset by session, week, or month and optional one-standard-deviation bands. High-volume narrow bars can be highlighted as absorption. Settings control lookback, row count, value-area percentage, sweep volume multiplier, theme, and a HUD table. It draws on the price chart and has no trade entries or exits.

Details

Published by

MoDarK-MK on GitHub

Code credit

{{SHORTTITLE}}, as written in the script's header

Draws

On the price chart

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Topics

ci-cdindicatorslinterpine-scriptpythonstrategiestradingview

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Show Prev Day High/Low (PDH/PDL)booltrueshowPdhPdlInput
Show Prev Week High/Low (PWH/PWL)booltrueshowPwhPwlInput
Detect Liquidity SweepsbooltrueshowSweepsInput
Sweep Volume Multiplierfloat1.8sweepVolMultInput
Enable Volume ProfilebooltrueshowVpInput
Profile Lookback (Bars)int150vpLookbackInput
Price Rowsint24vpRowsInput
Value Area %float70.0vaPercentInput
Show Anchored VWAPbooltrueshowAvwapInput
VWAP Anchor PeriodstringSessionavwapAnchorInput
Show VWAP ±1σ BandsbooltrueshowAvwapBands
Highlight Volume AbsorptionbooltruedetectAbsorbInput
Show all 19 settings
SettingTypeDefaultVariable
ThemestringTHEME_DARKthemeInput
Custom Bullcolor#089981customBullInput
Custom Bearcolor#f23645customBearInput
Show HUD DashboardbooltrueshowDashInput
Dashboard PositionstringTop RighttablePosInput
Dashboard Transparencyint15panelTranspInput
Test ModeboolfalsetestModeInput
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

This indicator overlays Wyckoff schematic analysis on the chart, identifying accumulation and distribution phases (A through E) alongside key events like Selling Climax, Automatic Rally, Spring, UTAD, and Sign of Strength. It calculates range quality scores, a

Indicator v6 SMC / ICT / price actionSupport & resistance
Updated 3 days ago · MIT GitHub repository of Wyckoff Schematics [WavesUnchained]

SMC+WWAP+FVG+TBT

by IAMATOMIC001
3 stars

This overlay indicator maps market structure and a volume-weighted average on the price chart. It plots bullish and bearish structure from a pivot period, with an optional response length for shorter or longer structure. Premium and discount areas can be shade

Indicator v6 SMC / ICT / price actionVolume Repaints
Updated 12 months ago · None stated GitHub repository of SMC+WWAP+FVG+TBT

OWS Context

by vishnu-vardhan-d
2 stars

This indicator evaluates institutional market structure by tracking five core behaviors: liquidity sweeps with reclaims, stopping volume, range compression and expansion, breaks of structure, and order block mitigations. When a user-defined minimum number of p

Indicator v6 SMC / ICT / price actionSupport & resistance
Updated 2 weeks ago · MIT GitHub repository of OWS Context

Draw on Liquidity

by Ahmed1926
1 stars

An overlay indicator that draws liquidity levels at pivot highs and lows, filtered by volume. A level appears when the pivot bar's volume exceeds a multiple of its moving average. High and low levels have separate colours, and a display mode shows either all h

Indicator v6 SMC / ICT / price actionSupport & resistance
Updated 9 months ago · None stated GitHub repository of Draw on Liquidity

More Volume scripts

Related on ForexR

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers