Indicator · Pine Script v6 · On the chart

Money Flow Delta Profile [WavesUnchained]

by casoon

This indicator plots a directional volume and money flow profile directly on the price chart over a configurable lookback period.

View on GitHub

GitHub stars9on the repository
Pine versionv6current
Lines of code559
Settings39inputs
LicenceMIT
Last updateyesterday27 Oct 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

559 lines of Pine Script v6 from indicators/money_flow/money_flow_delta_profile/money_flow_delta_profile.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

money_flow_delta_profile.pine
//@version=6
// ============================================================================
// Money Flow Delta Profile [WavesUnchained]
// Version: 2.1.0
// Author: WavesUnchained
// Build: 2026-10-12
// ============================================================================
// Directional volume/money flow profile: a gray reference bar (total flow)
// and a colored delta bar share a left anchor and both extend right — green
// when buyers dominated a price level, red when sellers dominated.
//
// Features:
//   ✓ Proportional or Binary flow split per bar
//   ✓ Total flow reference bars as background context
//   ✓ Point of Control (POC) — price level with highest total flow
//   ✓ Value Area High / Low (configurable %)
//   ✓ Delta POC — most decisively directional level
//   ✓ Optional recency weighting (exponential decay)
//   ✓ Volume or Money Flow (volume × price) source — Row Mid / HL2 / Typical / Close
//   ✓ Level labels (POC / VAH / VAL / ΔPOC)
//   ✓ Dashboard with bias summary
//   ✓ HVN / LVN / AVN node classification — reference bars colored by relative flow density
//   ✓ LVN Supply/Demand zone overlay — adjacent thin-area rows projected as S/D boxes on chart
//   ✓ LVN zone min-width filter + optional forward projection (extend right)
//   ✓ Optional intrabar delta — price-direction-signed volume proxy from lower-TF
//     bars, not real trade-classified delta (no aggressor-side data in OHLCV)
//   ✓ Absorption profile — wick volume (visited but rejected) per price row
//   ✓ Absorption peak zones — local rejection maxima projected as S/R
//   ✓ Source note — feed, volume origin (exchange / broker proxy / index feed)
//     and the calendar span the bar lookback actually covers
//
// Data Contract:
//   Price:     REQUIRED   chart symbol
//   Volume:    REQUIRED   real trade volume — feed must deliver volume and
//                         syminfo.volumetype must not be "tick"; otherwise not available
//   OI:        NO
//   Reference: NO
//   Verdict:   Exchange-only
//
// ============================================================================

indicator("Money Flow Delta Profile [WavesUnchained]", "MF Delta [WU]", overlay = true,
     max_bars_back = 1500, max_boxes_count = 500, max_lines_count = 500)

// ─── Inputs ───────────────────────────────────────────────────────────────────

grP = "Profile"
rpLN  = input.int(200,               "Lookback",     minval = 10, maxval = 1500, step = 10, group = grP)
rpNR  = input.int(25,                "Rows",         minval = 10, maxval = 100,  step = 5,  group = grP)
rpSRC = input.string("Money Flow",   "Source",       options = ["Money Flow", "Volume"],    group = grP)
rpMFP = input.string("Row Mid",      "  MF Price",   options = ["Row Mid", "HL2", "Typical", "Close"], group = grP,
     tooltip = "Price multiplier for Money Flow mode. Row Mid = price midpoint of the row bucket. HL2/Typical/Close use the bar's own price — typically more accurate for narrow rows.")
rpDM  = input.string("Proportional", "Delta Mode",
     options = ["Proportional", "Binary"],
     tooltip = "Proportional: each bar contributes fractionally based on close location in its range. Binary: whole bar counts as bull or bear.",
     group = grP)
rpPTY = input.string("Bar Polarity", "Polarity (Binary only)",
     options = ["Bar Polarity", "Close Location"],
     tooltip = "Only used in Binary mode. Bar Polarity: close > open. Close Location: close nearer to high = bull, nearer to low = bear.",
     group = grP)

grW = "Weighting"
useDecay    = input.bool(false,   "Recency Weighting",
     tooltip = "Exponential decay: recent bars count more. Higher factor = faster fade of older bars.",
     group = grW)
decayFactor = input.float(0.015, "Decay Factor", minval = 0.001, maxval = 0.10, step = 0.005, group = grW)

grV = "Visualization"
showRef      = input.bool(true,   "Total Flow Reference",  group = grV)
showPOC      = input.bool(true,   "POC Line",              group = grV)
showVA       = input.bool(true,   "Value Area",            group = grV)
vaPct        = input.int(70,      "Value Area %",    minval = 10, maxval = 95, step = 5, group = grV) / 100
showDeltaPOC = input.bool(false,  "Delta POC Line",        group = grV)
showLabels   = input.bool(true,   "Level Labels",          group = grV)
showDash     = input.bool(false,  "Dashboard",             group = grV)
showRange    = input.bool(false,  "Show Lookback Range",   group = grV)
profileWInp  = input.int(60,      "Profile Width (bars)",  minval = 10, maxval = 200, group = grV)
vpHO         = input.int(40,      "Bar Offset",            group = grV)

bullC = input.color(color.new(#26a69a, 20), "Bull",          inline = "c1", group = grV)
bearC = input.color(color.new(#ef5350, 20), "Bear",          inline = "c1", group = grV)
avnC  = input.color(color.new(color.gray, 80), "AVN / POC",  inline = "c2", group = grV)
pocC  = input.color(#ffd600,                   "",            inline = "c2", group = grV)
vaC   = input.color(color.new(#2962ff, 85),    "VA / ΔPOC",  inline = "c3", group = grV)
dpC   = input.color(color.new(#ff6f00, 0),     "",            inline = "c3", group = grV)

grN = "Node Classification"
hvnThresh    = input.float(0.80, "HVN Threshold", minval = 0.50, maxval = 0.99, step = 0.05, group = grN,
     tooltip = "Rows where flow exceeds this fraction of the row maximum are High Volume Nodes (potential S/R).")
lvnThresh    = input.float(0.20, "LVN Threshold", minval = 0.01, maxval = 0.50, step = 0.05, group = grN,
     tooltip = "Rows where flow falls below this fraction are Low Volume Nodes — thin areas price moved through quickly.")
hvnC         = input.color(color.new(#ff6f00, 65), "HVN", inline = "ncol", group = grN)
lvnC         = input.color(color.new(color.gray, 92), "LVN", inline = "ncol", group = grN)
showLVNZones = input.bool(true, "LVN Zone Overlay", group = grN,
     tooltip = "Project LVN rows as Supply/Demand zone boxes across the lookback window. Adjacent LVN rows are merged into a single zone.")
lvnSupC      = input.color(color.new(#ef5350, 88), "  Supply (above POC)", group = grN)
lvnDemC      = input.color(color.new(#26a69a, 88), "  Demand (below POC)", group = grN)
lvnMinRows   = input.int(1, "  Min Zone Rows", minval = 1, maxval = 20, group = grN,
     tooltip = "Minimum number of adjacent LVN rows required to draw a zone. 1 = no filter (every LVN row qualifies).")
lvnExtendR   = input.bool(false, "  Extend Zones Right", group = grN,
     tooltip = "Project LVN zones forward to the right edge of the chart instead of ending them at the current bar.")

grI = "Intrabar Delta"
useIntrabar = input.bool(false, "Intrabar Delta (LTF)", group = grI,
     tooltip = "Compute the bull/bear split per bar from lower-timeframe volume direction instead of the close-location approximation. The lower timeframe is the chart timeframe divided by Granularity, clamped to 1 minute — on 1-minute or seconds charts this falls back to the approximation automatically.")
intraGran   = input.int(10, "  Granularity", minval = 2, maxval = 60, group = grI,
     tooltip = "Chart timeframe ÷ this value = requested lower timeframe. Higher = finer sampling, more data load.")

grA = "Absorption"
showAbsorption = input.bool(false, "Absorption Profile", group = grA,
     tooltip = "Wick-volume profile drawn left of the anchor line: flow at prices the bar visited but closed away from (rejection). Tall rows mark absorption levels where resting liquidity soaked up the move.")
absC           = input.color(color.new(#7e57c2, 45), "  Color", group = grA)
showAbsZones   = input.bool(false, "Absorption Peak Zones", group = grA,
     tooltip = "Rows whose absorption exceeds both neighbors and at least half of the absorption maximum are projected as S/R zones across the lookback window.")
absZoneC       = input.color(color.new(#7e57c2, 90), "  Zone Color", group = grA)

// ─── Data validity ────────────────────────────────────────────────────────────
// Echtes Handelsvolumen? Nur "tick" schließt es ausdrücklich aus (Anzahl
// Transaktionen, keine Menge). "n/a" heißt laut Referenz "kein Volumen ODER Art
// nicht angegeben" — die meisten Feeds außer Krypto melden das, auch Futures mit
// echten Kontrakten. Dort entscheidet, ob der Feed überhaupt Volumen liefert.
var bool feedHasVolume = false
if nz(volume) > 0
    feedHasVolume := true
bool volumeIsReal = syminfo.volumetype != "tick" and feedHasVolume

// Whose volume? Label only, never a computation path (syminfo.type is not a
// stable enum). The volumetype guard says a quantity exists, not whose it is:
// a CFD feed reports the broker's own count, an index feed no traded quantity
// of the index itself.
string volOrigin = switch syminfo.type
    "cfd"     => "broker proxy, not exchange volume"
    "index"   => "index feed volume, not traded volume"
    "futures" => "exchange volume"
    "stock"   => "exchange volume"
    "fund"    => "exchange volume"
    "dr"      => "exchange volume"
    "crypto"  => "exchange volume (this venue only)"
    => "volume origin unknown"
bool volIsExchange = str.startswith(volOrigin, "exchange")

// ─── State ────────────────────────────────────────────────────────────────────

var array<box>   drwBoxes  = array.new<box>()
var array<line>  drwLines  = array.new<line>()
var array<label> drwLabels = array.new<label>()
var table        dash      = na

// ─── Intrabar delta collection (per chart bar, from lower-TF volume) ─────────
// Price-direction-signed volume proxy from LTF bars: positive = up-bar volume,
// negative = down-bar volume. This is NOT real trade-classified delta — OHLCV
// carries no aggressor-side data, so "up-bar volume" is a heuristic, not a
// buy/sell classification. Per confirmed chart bar the sums are stored so the
// profile loop can replace the close-location approximation with this proxy.

int    chartSec = timeframe.in_seconds()
int    ltfSec   = math.max(60, int(chartSec / intraGran))
bool   ibActive = useIntrabar and ltfSec < chartSec and volumeIsReal

var array<float> ibBull = array.new_float()
var array<float> ibBear = array.new_float()
float ibBullCur = na
float ibBearCur = na

if ibActive
    string ltfTf = timeframe.from_seconds(ltfSec)
    float signedVolumeProxy = close > open ? nz(volume) : close < open ? -nz(volume) : 0.0
    arr = request.security_lower_tf(syminfo.tickerid, ltfTf, signedVolumeProxy)
    float bSum = 0.0
    float sSum = 0.0
    if arr.size() > 0
        for v in arr
            if v > 0
                bSum += v
            else
                sSum -= v
    ibBullCur := bSum
    ibBearCur := sSum
    if barstate.isconfirmed
        ibBull.push(bSum)
        ibBear.push(sSum)
        while ibBull.size() > 1500
            ibBull.shift()
            ibBear.shift()

// ─── Price range — computed on every bar so Pine maintains proper series history
float pLo = ta.lowest(low,   rpLN)
float pHi = ta.highest(high, rpLN)

// ─── Compute and draw (last bar only) ────────────────────────────────────────

// Kurzer Hinweis unten rechts; was fehlt, steht im Data Contract oben.
var table volWarn = table.new(position.bottom_right, 1, 1)
if barstate.islast and not volumeIsReal
    table.cell(volWarn, 0, 0, "MF Delta · not available",
         bgcolor = color.new(color.orange, 20), text_color = color.white, text_size = size.small)

if barstate.islast and volumeIsReal

    rpLN_adj = math.min(rpLN - 1, last_bar_index)

    if not na(pLo) and pHi > pLo

        // Clear previous drawings
        for b in drwBoxes
            box.delete(b)
        for l in drwLines
            line.delete(l)
        for lb in drwLabels
            label.delete(lb)
        drwBoxes.clear()
        drwLines.clear()
        drwLabels.clear()

        pSTP = (pHi - pLo) / rpNR

        // Accumulate flow per price row
        totFlow  = array.new_float(rpNR, 0.)
        bullFlow = array.new_float(rpNR, 0.)
        absFlow  = array.new_float(rpNR, 0.)

        for bI = rpLN_adj to 0
            h_ = high[bI]
            l_ = low[bI]
            c_ = close[bI]
            o_ = open[bI]
            v_   = nz(volume[bI])
            if v_ > 0 and h_ > l_
                // Buy ratio: fraction of flow attributed to buying pressure
                // Proportional: continuous (c-l)/(h-l) ratio — smoothest signal
                // Binary Bar Polarity: whole bar to bull/bear based on close vs open (doji = 50%)
                // Binary Close Location: continuous (c-l)/(h-l) ratio, but applied as a binary
                //   threshold in the original sense — now made proportional for less noise
                clRatio  = math.max(0.0, math.min(1.0, (c_ - l_) / (h_ - l_)))
                float buyRatio = clRatio
                if rpDM != "Proportional" and rpPTY == "Bar Polarity"
                    buyRatio := c_ > o_ ? 1.0 : c_ < o_ ? 0.0 : 0.5

                // Intrabar delta: replace the close-location approximation with
                // the signed-volume-proxy split from the lower timeframe when
                // stored — still a price-direction proxy, not real trade delta
                if ibActive
                    float ibB = na
                    float ibS = na
                    if bI == 0
                        ibB := ibBullCur
                        ibS := ibBearCur
                    else
                        // if the last bar is already confirmed it has been
                        // pushed too — shift the offset base accordingly
                        int ibBase = barstate.isconfirmed ? ibBull.size() - 1 : ibBull.size()
                        int ibIdx  = ibBase - bI
                        if ibIdx >= 0 and ibIdx < ibBull.size()
                            ibB := ibBull.get(ibIdx)
                            ibS := ibBear.get(ibIdx)
                    if not na(ibB) and ibB + ibS > 0
                        buyRatio := ibB / (ibB + ibS)

                // Wick segments of this bar (for the absorption profile)
                float bodyHi = math.max(o_, c_)
                float bodyLo = math.min(o_, c_)

                wt = useDecay ? math.exp(-decayFactor * bI) : 1.0

                // MF price per bar (used for all rows of this bar when not Row Mid)
                float barMFPrice = 0.0
                if rpMFP == "Close"
                    barMFPrice := c_
                else if rpMFP == "HL2"
                    barMFPrice := (h_ + l_) / 2.0
                else if rpMFP == "Typical"
                    barMFPrice := (h_ + l_ + c_) / 3.0

                for r = 0 to rpNR - 1
                    pLL = pLo + r * pSTP
                    if h_ >= pLL and l_ < pLL + pSTP
                        vPOR = if l_ >= pLL and h_ > pLL + pSTP
                            (pLL + pSTP - l_) / (h_ - l_)
                        else if h_ <= pLL + pSTP and l_ < pLL
                            (h_ - pLL) / (h_ - l_)
                        else if l_ >= pLL and h_ <= pLL + pSTP
                            1.0
                        else
                            pSTP / (h_ - l_)

                        mfPrice = rpMFP == "Row Mid" ? pLo + (r + 0.5) * pSTP : barMFPrice
                        flow = rpSRC == "Money Flow" ? v_ * vPOR * mfPrice * wt : v_ * vPOR * wt

                        totFlow.set(r,  totFlow.get(r)  + flow)
                        bullFlow.set(r, bullFlow.get(r) + flow * buyRatio)

                        // Absorption: the share of this row covered by the
                        // bar's wicks — price traded there but closed away
                        if showAbsorption or showAbsZones
                            upWickOv = math.max(0.0, math.min(h_, pLL + pSTP) - math.max(bodyHi, pLL))
                            loWickOv = math.max(0.0, math.min(bodyLo, pLL + pSTP) - math.max(l_, pLL))
                            wickPOR  = (upWickOv + loWickOv) / (h_ - l_)
                            if wickPOR > 0
                                absRow = rpSRC == "Money Flow" ? v_ * wickPOR * mfPrice * wt : v_ * wickPOR * wt
                                absFlow.set(r, absFlow.get(r) + absRow)

        totMax = totFlow.max()

        if totMax > 0
            totSum   = totFlow.sum()
            pocIdx   = totFlow.indexof(totMax)
            pocPrice = pLo + (pocIdx + 0.5) * pSTP

            // Delta per row
            deltaArr = array.new_float(rpNR, 0.)
            deltaMax = 0.0
            for r = 0 to rpNR - 1
                d = 2.0 * bullFlow.get(r) - totFlow.get(r)
                deltaArr.set(r, d)
                if math.abs(d) > deltaMax
                    deltaMax := math.abs(d)
            if deltaMax == 0.0
                deltaMax := 1.0

            absMax = absFlow.max()

            // Value Area: expand from POC toward highest adjacent row
            vaLo  = pocIdx
            vaHi  = pocIdx
            vaAcc = totFlow.get(pocIdx)
            vaTgt = totSum * vaPct

            while vaAcc < vaTgt
                addLo = vaLo > 0        ? totFlow.get(vaLo - 1) : -1.0
                addHi = vaHi < rpNR - 1 ? totFlow.get(vaHi + 1) : -1.0
                if addLo < 0 and addHi < 0
                    break
                if addLo >= addHi
                    vaLo  -= 1
                    vaAcc += addLo
                else
                    vaHi  += 1
                    vaAcc += addHi

            vahPrice = pLo + (vaHi + 1) * pSTP
            valPrice = pLo + vaLo * pSTP

            // Delta POC: row with highest absolute delta
            dPocIdx    = 0
            dPocAbsMax = 0.0
            for r = 0 to rpNR - 1
                ad = math.abs(deltaArr.get(r))
                if ad > dPocAbsMax
                    dPocAbsMax := ad
                    dPocIdx    := r
            dPocPrice = pLo + (dPocIdx + 0.5) * pSTP

            // Layout
            // anchorBI = left edge of profile
            // Gray reference extends RIGHT (total flow)
            // Bull and bear bars both extend RIGHT from anchor, overlaid on gray
            profileW = profileWInp
            maxOH    = math.max(int(profileW / 2), 1)  // max delta bar width
            anchorBI = bar_index + vpHO + 1
            rightBI  = anchorBI + profileW

            // Lookback range overlay
            if showRange
                drwBoxes.push(box.new(bar_index - rpLN_adj, pHi, bar_index, pLo,
                     border_color = color.new(color.orange, 40),
                     bgcolor      = color.new(color.orange, 92)))

            // Value Area drawn first so profile bars render on top
            if showVA
                drwBoxes.push(box.new(anchorBI, vahPrice, rightBI, valPrice,
                     vaC, bgcolor = color.new(vaC, 92)))

            // ── Profile rows ─────────────────────────────────────────────

            for r = 0 to rpNR - 1
                // Row bounds with gap for visual spacing
                yBot = pLo + r * pSTP
                yTop = pLo + (r + 1) * pSTP
                if yTop <= yBot + syminfo.mintick
                    yTop := yBot + syminfo.mintick
                gap  = pSTP * 0.08
                yLo  = yBot + gap
                yHi  = yTop - gap
                if yHi <= yLo + syminfo.mintick
                    yLo := yBot
                    yHi := yTop

                rowTot   = totFlow.get(r)
                rowShare = totMax > 0 ? rowTot / totMax : 0.0

                // Total flow reference bar — colored by HVN/AVN/LVN classification
                nodeColor = rowShare > hvnThresh ? hvnC : rowShare < lvnThresh ? lvnC : avnC
                if showRef
                    refEnd = anchorBI + math.max(int(rowShare * profileW), 1)
                    drwBoxes.push(box.new(anchorBI, yHi, refEnd, yLo,
                         border_color = color.new(color.gray, 60),
                         bgcolor = nodeColor))

                // Delta bar — 2-stop gradient, fading from anchor outward
                delta      = deltaArr.get(r)
                deltaRatio = math.abs(delta) / deltaMax
                dW         = math.max(int(deltaRatio * maxOH), 0)
                if dW > 0
                    barColor = delta >= 0.0 ? bullC : bearC
                    split    = anchorBI + math.max(dW * 2 / 3, 1)
                    tip      = anchorBI + dW
                    drwBoxes.push(box.new(anchorBI, yHi, split, yLo, color(na), bgcolor = color.new(barColor, 10)))
                    if split < tip
                        drwBoxes.push(box.new(split, yHi, tip, yLo, color(na), bgcolor = color.new(barColor, 55)))

                // Absorption bar — extends LEFT of the anchor (mirror side)
                if showAbsorption and absMax > 0
                    aW = int(absFlow.get(r) / absMax * maxOH)
                    if aW > 0
                        drwBoxes.push(box.new(anchorBI - aW, yHi, anchorBI, yLo,
                             border_color = color(na), bgcolor = absC))

                // Bull% label: buying share at this price level (independent of bar width)
                if rowShare > 0.04
                    bullPct_r = rowTot > 0 ? bullFlow.get(r) / rowTot * 100 : 50.0
                    midY      = (yLo + yHi) / 2
                    color lCol = if bullPct_r > 55.0
                        color.new(#00c853, 0)
                    else if bullPct_r < 45.0
                        color.new(#ef5350, 0)
                    else
                        color.new(color.gray, 20)
                    drwLabels.push(label.new(anchorBI + 1, midY,
                         str.tostring(math.round(bullPct_r)) + "%",
                         xloc      = xloc.bar_index, yloc = yloc.price,
                         color     = color(na),      style = label.style_none,
                         textcolor = lCol,           size  = size.tiny,
                         textalign = text.align_left))

            // ── LVN Supply/Demand Zone Overlay (#17) ────────────────────
            if showLVNZones
                int zStart = -1
                for r = 0 to rpNR
                    isLVN = r < rpNR and totFlow.get(r) / totMax < lvnThresh
                    if isLVN and zStart < 0
                        zStart := r
                    if not isLVN and zStart >= 0
                        if r - zStart >= lvnMinRows
                            zLo    = pLo + zStart * pSTP
                            zHi    = pLo + r * pSTP
                            midRow = (zStart + r - 1) / 2.0
                            drwBoxes.push(box.new(bar_index - rpLN_adj, zHi, bar_index, zLo,
                                 border_color = color.new(color.gray, 70),
                                 bgcolor      = midRow > pocIdx ? lvnSupC : lvnDemC,
                                 extend       = lvnExtendR ? extend.right : extend.none))
                        zStart := -1

            // ── Absorption Peak Zones — local rejection maxima as S/R ────
            if showAbsZones and absMax > 0
                for r = 1 to rpNR - 2
                    aV = absFlow.get(r)
                    if aV > absFlow.get(r - 1) and aV > absFlow.get(r + 1) and aV >= absMax * 0.5
                        drwBoxes.push(box.new(bar_index - rpLN_adj, pLo + (r + 1) * pSTP,
                             bar_index, pLo + r * pSTP,
                             border_color = color.new(color.gray, 70),
                             bgcolor      = absZoneC,
                             extend       = lvnExtendR ? extend.right : extend.none))

            // Anchor (zero) line
            drwLines.push(line.new(anchorBI, pHi, anchorBI, pLo,
                 xloc = xloc.bar_index, color = color.new(color.gray, 40),
                 style = line.style_solid, width = 2))

            // Source note: feed, volume origin and the time span the bar lookback
            // actually covers — 200 bars are ~6 weeks on a 23h CFD but ~3 months
            // on an 8.5h exchange session, so profiles across feeds differ.
            winStart = time[rpLN_adj]
            winDays  = math.round((time - winStart) / 86400000.0)
            drwLabels.push(label.new(anchorBI, pLo,
                 syminfo.prefix + " · " + syminfo.type + " · " + syminfo.volumetype + " → " + volOrigin
                 + "\n" + str.tostring(rpLN_adj + 1) + " bars · since "
                 + str.format_time(winStart, "yyyy-MM-dd", syminfo.timezone)
                 + " (" + str.tostring(winDays) + " calendar days)",
                 xloc = xloc.bar_index, yloc = yloc.price,
                 color = color(na), style = label.style_label_upper_left,
                 textcolor = volIsExchange ? color.new(color.gray, 20) : color.new(color.orange, 10),
                 size = size.small, textalign = text.align_left))

            // POC
            if showPOC
                drwLines.push(line.new(anchorBI, pocPrice, rightBI, pocPrice,
                     xloc = xloc.bar_index, color = pocC,
                     style = line.style_dashed, width = 2))
                if showLabels
                    drwLabels.push(label.new(rightBI + 1, pocPrice, "POC",
                         xloc = xloc.bar_index, yloc = yloc.price,
                         color = color(na), style = label.style_none,
                         textcolor = pocC, size = size.small,
                         textalign = text.align_left))

            // Delta POC
            if showDeltaPOC
                drwLines.push(line.new(anchorBI, dPocPrice, rightBI, dPocPrice,
                     xloc = xloc.bar_index, color = dpC,
                     style = line.style_dotted, width = 2))
                if showLabels
                    drwLabels.push(label.new(rightBI + 1, dPocPrice, "ΔPOC",
                         xloc = xloc.bar_index, yloc = yloc.price,
                         color = color(na), style = label.style_none,
                         textcolor = dpC, size = size.small,
                         textalign = text.align_left))

            // Value Area labels (box already drawn before profile rows)
            if showVA
                if showLabels
                    drwLabels.push(label.new(rightBI + 1, vahPrice, "VAH",
                         xloc = xloc.bar_index, yloc = yloc.price,
                         color = color(na), style = label.style_none,
                         textcolor = vaC, size = size.small,
                         textalign = text.align_left))
                    drwLabels.push(label.new(rightBI + 1, valPrice, "VAL",
                         xloc = xloc.bar_index, yloc = yloc.price,
                         color = color(na), style = label.style_none,
                         textcolor = vaC, size = size.small,
                         textalign = text.align_left))

            // ── Dashboard ────────────────────────────────────────────────

            if showDash
                bullPct = bullFlow.sum() / totSum * 100
                biasC   = bullPct > 52.0 ? #00c853 : bullPct < 48.0 ? #d50000 : color.new(color.gray, 20)
                color tc = color.new(color.gray, 20)
                color hd = color.new(color.gray, 90)

                if na(dash)
                    dash := table.new(position.top_right, 2, 6,
                         bgcolor      = color.new(color.white, 5),
                         border_color = color.new(color.gray, 60), border_width = 1,
                         frame_color  = color.new(color.gray, 40), frame_width  = 1)

                table.cell(dash, 0, 0, "MF Delta Profile",
                     text_color = tc, bgcolor = hd, text_size = size.small)
                table.cell(dash, 1, 0, str.tostring(rpLN_adj + 1) + "b · " + rpSRC,
                     text_color = tc, bgcolor = hd, text_size = size.small)
                table.cell(dash, 0, 1, "POC",
                     text_color = tc, text_size = size.small)
                table.cell(dash, 1, 1, str.tostring(pocPrice, format.mintick),
                     text_color = tc, text_size = size.small)
                table.cell(dash, 0, 2, "VAH",
                     text_color = tc, text_size = size.small)
                table.cell(dash, 1, 2, str.tostring(vahPrice, format.mintick),
                     text_color = tc, text_size = size.small)
                table.cell(dash, 0, 3, "VAL",
                     text_color = tc, text_size = size.small)
                table.cell(dash, 1, 3, str.tostring(valPrice, format.mintick),
                     text_color = tc, text_size = size.small)
                table.cell(dash, 0, 4, "Bull%",
                     text_color = tc, text_size = size.small)
                table.cell(dash, 1, 4, str.tostring(bullPct, "#.#") + "%",
                     text_color = biasC, text_size = size.small)
                table.cell(dash, 0, 5, "VA",
                     text_color = tc, text_size = size.small)
                table.cell(dash, 1, 5, str.tostring(int(vaPct * 100)) + "%",
                     text_color = tc, text_size = size.small)

Overview

Money Flow Delta Profile [WavesUnchained] displays total flow reference bars alongside directional delta bars to highlight buyer versus seller dominance at each price tier. The script identifies key structural levels including the Point of Control, Value Area High and Low, Delta Point of Control, and low-volume supply or demand zones. Settings customize row resolution, proportional or binary delta calculations, exponential recency weighting, and dashboard metrics.

Details

Published by

casoon on GitHub

Type

Indicator, Pine Script v6

Draws

On the price chart

Category

Volume, Support & resistance

Markets

Crypto, Stocks, Indices

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

pine-scriptpinescripttechnical-analysistrading-indicatorstrading-strategiestradingview

Settings

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

SettingTypeDefaultVariable
Lookbackint200rpLN
Rowsint25rpNR
SourcestringMoney FlowrpSRC
MF PricestringRow MidrpMFP
Delta ModestringProportionalrpDM
Polarity (Binary only)stringBar PolarityrpPTY
Recency WeightingboolfalseuseDecay
Decay Factorfloat0.015decayFactor
Total Flow ReferencebooltrueshowRef
POC LinebooltrueshowPOC
Value AreabooltrueshowVA
Value Area %int70vaPct
Show all 39 settings
SettingTypeDefaultVariable
Delta POC LineboolfalseshowDeltaPOC
Level LabelsbooltrueshowLabels
DashboardboolfalseshowDash
Show Lookback RangeboolfalseshowRange
Profile Width (bars)int60profileWInp
Bar Offsetint40vpHO
Bullcolorcolor.new(#26a69a, 20)bullC
Bearcolorcolor.new(#ef5350, 20)bearC
AVN / POCcolorcolor.new(color.gray, 80)avnC
pocCcolor#ffd600pocC
VA / ΔPOCcolorcolor.new(#2962ff, 85)vaC
dpCcolorcolor.new(#ff6f00, 0)dpC
HVN Thresholdfloat0.80hvnThresh
LVN Thresholdfloat0.20lvnThresh
HVNcolorcolor.new(#ff6f00, 65)hvnC
LVNcolorcolor.new(color.gray, 92)lvnC
LVN Zone OverlaybooltrueshowLVNZones
Supply (above POC)colorcolor.new(#ef5350, 88)lvnSupC
Demand (below POC)colorcolor.new(#26a69a, 88)lvnDemC
Min Zone Rowsint1lvnMinRows
Extend Zones RightboolfalselvnExtendR
Intrabar Delta (LTF)boolfalseuseIntrabar
Granularityint10intraGran
Absorption ProfileboolfalseshowAbsorption
Colorcolorcolor.new(#7e57c2, 45)absC
Absorption Peak ZonesboolfalseshowAbsZones
Zone Colorcolorcolor.new(#7e57c2, 90)absZoneC
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 overlay indicator draws a fixed-range volume profile on the price chart, splitting traded activity into up and down volume at each price level. It also plots a sentiment profile, a developing point of control, and value-area high and low around a configur

Indicator v5 VolumeSupport & resistance
Updated 2 months ago · MIT GitHub repository of Volume Profile and Indicator by DGT

MGIC-tracker

by Allen1212
303 stars

The MGIC-tracker is a TradingView indicator that overlays ARK Invest trade records onto stock price charts. It plots buy and sell labels at the exact timestamp of each transaction, showing share volume and ETF weight. Users select a specific ETF type via setti

Indicator v4 Support & resistanceVolume
Updated 2 years ago · None stated GitHub repository of MGIC-tracker
218 stars

Comprehensive Volume Profile is an overlay indicator that calculates and plots volume distribution across specified time ranges such as daily sessions, weekly, monthly, or custom bar lengths. It identifies key structural price levels including the Point of Con

Indicator v6 VolumeSupport & resistance
Updated 3 months ago · None stated GitHub repository of Comprehensive Volume Profile

Moon Dev GEX Arrows

by moondevonyt
92 stars

This overlay indicator plots option strike walls and an optional session VWAP on the price chart for SPY or ES. It spaces major strikes by the selected instrument, draws a set number of strikes on each side, and marks wall-trap and sweep events after a cooldow

Indicator v5 Support & resistanceSessions & time
Updated 8 weeks ago · Custom licence GitHub repository of Moon Dev GEX Arrows

More indicators

Trade Your Charts With a Regulated Broker

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

Compare brokers