Indicator · Pine Script v5 · On the chart

Volume Profile and Indicator by DGT

by namuan

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.

View on GitHub

GitHub stars318on the repository
Pine versionv5runs as is
Lines of code580
Settings40inputs
LicenceMIT
Last update2 months ago18 Aug 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

580 lines of Pine Script v5 from tv-scripts/tvt-volume-profile.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

tvt-volume-profile.pine
//@version=5
// Credit: https://www.tradingview.com/script/Qwj6TO5I-Volume-Profile-and-Volume-Indicator-by-DGT/
// ══════════════════════════════════════════════════════════════════════════════════════════════════ //
//# * ══════════════════════════════════════════════════════════════════════════════════════════════
//# *
//# * Study       : Volume Profile / Price by Volume - Fixed Ragne
//# * Author      : © dgtrd
//# *
//# * Revision History
//# *  Release    : Feb 23, 2022
//# *  Update     : Feb 27, 2022 : added volume indicator (histogram)
//# *  Update     : Feb 28, 2022 : volume indicator now has a moving average option
//# *  Update     : Mar 10, 2022 : horizontal offset option added, applicable for volume profile placed on right side
//# *  Update     : Mar 15, 2022 : added bull/bear volume dominace histogram
//# *  Update     : Apr 09, 2022 : aesthetic tweaks
//# *  Update     : Apr 25, 2022 : value area addition
//# *  Update     : Jul 13, 2022 : visable range optin added, thnaks to pine latest update
//# *  Update     : Jan 05, 2024 : core functionality enhancements and new features addition
//# *  Update     : Jan 13, 2024 : stats addition
//# *
//# * ══════════════════════════════════════════════════════════════════════════════════════════════
// ══════════════════════════════════════════════════════════════════════════════════════════════════ //

indicator("Volume Profile and Indicator by DGT", "VP ʙʏ DGT ☼☾", overlay = true, max_boxes_count = 500, max_lines_count = 500, max_bars_back = 5000)

//------------------------------------------------------------------------------
// Inputs
//-----------------------------------------------------------------------------{

disp = display.all - display.status_line

vpGR = 'Volume & Sentiment Profile'

vpTP   = 'displays total trading activity (both buying and selling trading activity) over a specified time period at specific price levels\n\n' +
          'row lengths, indicates the amount of the traded activity at specific price levels\n\n' +
          ' - high traded zones - usually represents consolidation zones (value areas)\n' +
          ' - low traded zones - usually represents supply & demand or liquidity zones'

vpSH = input.bool(true, 'Volume Profile', group = vpGR, tooltip = vpTP)

vpUC = input.color(color.new(#5d606b, 50), '  Up Volume ', inline = 'VP', group = vpGR)
vpDC = input.color(color.new(#d1d4dc, 50), 'Down Volume ', inline = 'VP', group = vpGR)

vaUC = input.color(color.new(#2962ff, 30), '  Value Area Up', inline = 'VA', group = vpGR)
vaDC = input.color(color.new(#fbc02d, 30), 'Value Area Down', inline = 'VA', group = vpGR)

spTP   = 'displays the sentiment, the dominat party over a specified time period at the specific price levels\n\n' +
          ' - bullish node rows : buying trading activity is higher\n'  +
          ' - barish node rows : selling trading activity is higher\n\n' +
          'row lengths, indicates the strength of the buyers/sellers at the specific price levels'

spSH = input.bool(true, 'Sentiment Profile', group = vpGR, tooltip = spTP)
spUC = input.color(color.new(#26a69a, 30), '  Bullish', inline = 'BB', group = vpGR)
spDC = input.color(color.new(#ef5350, 30), 'Bearish', inline = 'BB', group = vpGR)

sdTT = 'Defines the relationship between the price of a given asset and the willingness of traders to either buy or sell it'
sdSH = input.bool(true, 'Supply & Demand Zones', group = vpGR, tooltip = sdTT)
sdTH = input.int(15, '  Supply & Demand Threshold %', minval = 0, maxval = 41, group = vpGR, display = disp) / 100
sdSC = input.color(color.new(#ec1313, 80), '  Supply Zones', inline = 'SD', group = vpGR)
sdDC = input.color(color.new(#0094FF, 80), 'Demand Zones', inline = 'SD', group = vpGR)

pcSH = input.string('Developing POC', 'Point of Control', options = ['Developing POC', 'Last (Line)', 'None'], inline = 'POC', group = vpGR, display = disp)
pocC = input.color(#f44336, '', inline = 'POC', group = vpGR)
pocW = input.int(2, '', minval = 1, inline = 'POC', group = vpGR, display = disp)

vpVA = input.float(68, 'Value Area (%)', minval = 0, maxval = 100, group = vpGR, display = disp) / 100

vahS = input.bool(true, 'Value Area High (VAH)', inline = 'VAH', group = vpGR)
vahC = input.color(#2962ff, '', inline = 'VAH', group = vpGR)
vahW = input.int(1, '', minval = 1, inline = 'VAH', group = vpGR, display = disp)

vlSH = input.bool(true, 'Value Area Low (VAL)', inline = 'VAL', group = vpGR)
valC = input.color(#2962ff, '', inline = 'VAL', group = vpGR)
valW = input.int(1, '', minval = 1, inline = 'VAL', group = vpGR, display = disp)

spPT = 'polarity methods is a measure used to divide the total volume into either up volume (trades that moved the price up) or ' +
         'down volume (trades that moved the price down), simply said conditions used to calculate up/down volume\n\n' +
         '* bar polarity\n   up     => if close > open\n   down => if close <= open\n\n' +
         '* bar buying/selling pressure\n   up     => if (close - low) > (high - close)\n   down => if (close - low) <= (high - close)'
spP1 = 'Bar Polarity'
spP2 = 'Bar Buying/Selling Pressure'
vpPT = input.string(spP1, 'Profile Polarity Method', options = [spP1, spP2], group = vpGR, tooltip = spPT, display = disp)
vsPT = vpPT == spP1

vpLR = input.string('Fixed Range', 'Profile Lookback Range', options = ['Fixed Range', 'Visible Range'], group = vpGR, display = disp)
vpRL = vpLR == 'Visible Range'
vpLT = 'applicable when \'Lookback Range\' is selected as \'Fixed Range\''
vpLN = input.int(360, 'Lookback Length / Fixed Range', minval = 10, maxval = 5000, step = 10, group = vpGR, tooltip = vpLT, display = disp)
vpLN:= last_bar_index < vpLN ? last_bar_index : vpLN - 1

vpST = input.bool(true, 'Profile Stats', inline = 'STT', group = vpGR, display = disp)
ppLS = input.string('Small', "", options = ['Tiny', 'Small', 'Normal'], inline = 'STT', group = vpGR, display = disp)
lcDB = input.string('Top Right', '', options = ['Top Right', 'Middle Right', 'Bottom Left'], inline = 'STT', group = vpGR, display = disp)

vpLV = input.bool(true, 'Profile Price Levels', inline = 'BBe', group = vpGR)
rpLS = input.string('Small', "", options=['Tiny', 'Small', 'Normal'], inline = 'BBe', group = vpGR, display = disp)

vpPL = input.string('Right', 'Profile Placement', options = ['Right', 'Left'], group = vpGR, display = disp)
vpRT = vpPL == 'Right'
vpNR = input.int(100, 'Profile Number of Rows' , minval = 10, maxval = 150 , step = 10, group = vpGR, display = disp)
vpWD = input.float(31, 'Profile Width', minval = 0, maxval = 250, group = vpGR, display = disp) / 100
vpHO = input.int(13, 'Profile Horizontal Offset', maxval = 50, group = vpGR, display = disp)

vaBG = input.bool(false, 'Value Area Background  ', inline = 'vBG', group = vpGR)
vBGC = input.color(color.new(#2962ff, 89), '', inline = 'vBG', group = vpGR)

vpBG = input.bool(false, 'Profile Range Background ', inline = 'pBG', group = vpGR)
bgC  = input.color(color.new(#2962ff, 95), '', inline = 'pBG', group = vpGR)

vhGR  = 'Volume Histogram'

vhTT = 'The Volume indicator is used to measure how much of a given financial asset has traded in each specific candle'
vhSH = input.bool(true, 'Volume Histogram', group = vhGR, tooltip = vhTT)
vmaS = input.bool(true, 'Volume MA,         Length', inline='vol2', group = vhGR)
vmaL = input.int(21, '', minval = 1, inline='vol2', group = vhGR, display = disp)
vhUC = input.color(color.new(#26a69a, 30), '  Growing', inline='vol1', group = vhGR)
vhDC = input.color(color.new(#ef5350, 30), 'Falling', inline='vol1', group = vhGR)
vmaC = input.color(color.new(#2962ff, 0), 'Volume MA', inline='vol1', group = vhGR)
vhPL = input.string('Top', '  Placement', options = ['Top', 'Bottom'], group = vhGR, display = disp)
vhLP = vhPL  == 'Top'
vhHT = 11 - input.int(8, '  Hight' , minval = 1, maxval = 10, group = vhGR, display = disp)
vhVO = input.int(1, '  Vertical Offset', minval = 0 , maxval = 20, group = vhGR, display = disp) / 20

cbGR = 'Volume Weighted Colored Bars'

cbTT = 'Colors bars based on the bar\'s volume relative to volume moving average\n' +
         ' - Bold bars when bar\'s volume is above volume moving average * upper threshold\n' +
         ' - Light bars when bar\'s volume is below volume moving average * lower threshold'

vwcb = input.bool(false, 'Volume Weighted Colored Bars', group = cbGR, tooltip = cbTT)
upTH = input.float(1.618, '  Upper Threshold', minval=1., step=.1, group = cbGR, display = disp)
dnTH = input.float(0.618, '  Lower Threshold', minval=.1, step=.1, group = cbGR, display = disp)

//-----------------------------------------------------------------------------}
// User Defined Types
//-----------------------------------------------------------------------------{

type bar
    float o = open
    float h = high
    float l = low
    float c = close
    float v = volume
    int   i = bar_index

type barData
    float [] bh
    float [] bl
    float [] bv
    bool  [] bp
    int   [] bn

type volData
    float [] vt
    float [] vb
    float [] vd

type tVP
    box         []  vp
    chart.point []  pPC
    polyline        dPC
    int             pcL
    int             laP
    int             lbP
    int             sI

type tVH
    line        []  vh
    chart.point []  pMA
    polyline        vMA

//-----------------------------------------------------------------------------}
// Variables
//-----------------------------------------------------------------------------{

var barData bD = barData.new(
     array.new <float> (na),
     array.new <float> (na),
     array.new <float> (na),
     array.new <bool>  (na),
     array.new <int>   (na)
 )

volData vD = volData.new(
     array.new <float> (vpNR, 0.),
     array.new <float> (vpNR, 0.),
     array.new <float> (vpNR, 0.)
 )

var tVP VP = tVP.new(
     array.new<box>         (na),
     array.new<chart.point> (na),
     polyline.new           (na), na, na, na, na
 )

var tVH VH = tVH.new(
     array.new<line>        (na),
     array.new<chart.point> (na),
     polyline.new           (na)
 )

bar b = bar.new()
bar [] ltfBD = array.new<bar> (1, bar.new())

var float pHST = na
var float pLST = na
var string ltf = na

//-----------------------------------------------------------------------------}
// Functions / Methods
//-----------------------------------------------------------------------------{

f_drawLineX(_x1, _y1, _x2, _y2, _xloc, _extend, _color, _style, _width) =>
    var id = line.new(_x1, _y1, _x2, _y2, _xloc, _extend, _color, _style, _width)
    line.set_xy1(id, _x1, _y1)
    line.set_xy2(id, _x2, _y2)
    line.set_color(id, _color)

f_drawLabelX(_x, _y, _text, _color, _style, _textcolor, _size, _tooltip) =>
    var lb = label.new(_x, _y, _text, xloc.bar_index, yloc.price, _color, _style, _textcolor, _size, text.align_left, _tooltip)
    lb.set_xy(_x, _y)
    lb.set_text(_text)
    lb.set_tooltip(_tooltip)
    lb.set_textcolor(_textcolor)

getData(_ltf) => request.security_lower_tf(syminfo.tickerid, _ltf, bar.new(), ignore_invalid_timeframe = true)

f_gTF(_d) =>
    int tfInMs = timeframe.in_seconds(timeframe.period)
    int  mInMS = 60

    if _d == 2
        switch
            tfInMs <                 30  =>  '1S'
            tfInMs <          1 * mInMS  =>  '5S'

            tfInMs <=        15 * mInMS  =>   '1'
            tfInMs <=        60 * mInMS  =>   '5'
            tfInMs <=       240 * mInMS  =>  '15'
            tfInMs <=      1440 * mInMS  =>  '60'
            => 'D'

    else if _d == 1
        switch
            tfInMs <                 15  =>  '1S'
            tfInMs <                 30  =>  '5S'
            tfInMs <          1 * mInMS  => '15S'

            tfInMs <=         5 * mInMS  =>   '1'
            tfInMs <=        15 * mInMS  =>   '5'
            tfInMs <=        60 * mInMS  =>  '15'
            tfInMs <=       240 * mInMS  =>  '60'
            tfInMs <=      1440 * mInMS  => '240'
            => 'D'

f_gTS(_t) =>
    switch _t
        'Tiny'   => size.tiny
        'Small'  => size.small
        'Normal' => size.normal
        => size.auto

f_crossingLevelX(_price, _level) =>
    (_level > _price and _level < _price[1]) or (_level < _price and _level > _price[1])

alarm(_message) =>
    alert(syminfo.ticker + ' ' + _message + ', price ' + str.tostring(b.c, format.mintick) + ', timeframe ' + timeframe.period, alert.freq_once_per_bar)

//-----------------------------------------------------------------------------}
// Calculations Volume Profile
//-----------------------------------------------------------------------------{

nzV  = nz(b.v)
vSMA = ta.sma(nzV, vmaL)

rpS  = f_gTS(rpLS)
ppLS:= f_gTS(ppLS)

tPOS = lcDB == 'Top Right' ? position.top_right
     : lcDB == 'Middle Right' ? position.middle_right
     : position.bottom_left

if time == chart.left_visible_bar_time
    VP.sI := b.i

if vpRL
    vpLN := last_bar_index - VP.sI

if b.i == last_bar_index - vpLN
    VP.sI   := b.i
    pLST := b.l
    pHST := b.h
else if b.i > last_bar_index - vpLN
    pLST := math.min(b.l, pLST)
    pHST := math.max(b.h, pHST)

if vpLN <= 200
    ltf := f_gTF(2)
    ltfBD := getData(f_gTF(2))
else if vpLN <= 700
    ltf := f_gTF(1)
    ltfBD := getData(f_gTF(1))
else
    ltf := 'Chart'
    ltfBD := array.new<bar> (1, bar.new(b.o, b.h, b.l, b.c, b.v))

if barstate.ishistory and (b.i >= last_bar_index - vpLN) and b.i < last_bar_index and ltfBD.size() > 0

    if ltfBD.size() > 0 and not na(nz(ltfBD.get(0).v))
        for i = 0 to ltfBD.size() - 1
            bD.bh.push(ltfBD.get(i).h)
            bD.bl.push(ltfBD.get(i).l)
            bD.bv.push(ltfBD.get(i).v)

            if vsPT
                bD.bp.push(ltfBD.get(i).c > ltfBD.get(i).o)
            else
                bD.bp.push(ltfBD.get(i).c - ltfBD.get(i).l > ltfBD.get(i).h - ltfBD.get(i).c)

        bD.bn.push(ltfBD.size())

pSTP = (pHST - pLST) / vpNR

if barstate.islast and ltfBD.size() > 0

    if VP.vp.size() > 0
        for i = 0 to VP.vp.size() - 1
            box.delete(VP.vp.shift())

    if bD.bn.size() > vpLN
        qt = bD.bn.shift()
        for i = 0 to qt - 1
            bD.bh.shift()
            bD.bl.shift()
            bD.bv.shift()
            bD.bp.shift()

    VP.pPC.clear()
    VP.dPC.delete()

    if ltfBD.size() > 0 and not na(nz(ltfBD.get(0).v))
        for i = 0 to ltfBD.size() - 1
            bD.bh.push(ltfBD.get(i).h)
            bD.bl.push(ltfBD.get(i).l)
            bD.bv.push(ltfBD.get(i).v)

            if vsPT
                bD.bp.push(ltfBD.get(i).c > ltfBD.get(i).o)
            else
                bD.bp.push(ltfBD.get(i).c - ltfBD.get(i).l > ltfBD.get(i).h - ltfBD.get(i).c)

        bD.bn.push(ltfBD.size())

    bI  = vpLN
    bSZ = 0
    aSZ = bD.bv.size()

    for aI = 0 to aSZ - 1

        i = 0
        for pLL = pLST to pHST - pSTP by pSTP

            lH = bD.bh.get(aI)
            lL = bD.bl.get(aI)
            lV = bD.bv.get(aI)

            if lH >= pLL and lL < pLL + pSTP

                vPOR = if lL >= pLL and lH > pLL + pSTP
                    (pLL + pSTP - lL) / (lH - lL)
                else if lH <= pLL + pSTP and lL < pLL
                    (lH - pLL) / (lH - lL)
                else if lL >= pLL and lH <= pLL + pSTP
                    1
                else
                    pSTP / (lH - lL)

                vD.vt.set(i, vD.vt.get(i) + lV * vPOR)

                if bD.bp.get(aI)
                    vD.vb.set(i, vD.vb.get(i) + lV * vPOR)
            i += 1

        if pcSH == 'Developing POC'
            if aI == bD.bn.get(vpLN - bI)
                VP.pPC.push(chart.point.from_index(b.i[bI], math.avg(b.h[bI], b.l[bI])))
                VP.pPC.push(chart.point.from_index(b.i[bI] + 1, pLST + (vD.vt.indexof(vD.vt.max()) + .5) * pSTP))
                bSZ += bD.bn.get(vpLN - bI)
                bI  -= 1
            else if aI == (bSZ + bD.bn.get(vpLN - bI)) and bSZ != 0
                VP.pPC.push(chart.point.from_index(b.i[bI] + 1, pLST + (vD.vt.indexof(vD.vt.max()) + .5) * pSTP))
                bSZ += bD.bn.get(vpLN - bI)
                bI  -= 1
            else if bI == 0
                VP.pPC.push(chart.point.from_index(b.i[bI] + 1, pLST + (vD.vt.indexof(vD.vt.max()) + .5) * pSTP))
                bSZ += bD.bn.get(vpLN - bI)

    VP.dPC := polyline.new(VP.pPC, false, false, xloc.bar_index, pocC, color(na), line.style_solid, pocW)

    for i = 0 to vpNR - 1
        bbp = 2 * vD.vb.get(i) - vD.vt.get(i)
        vD.vd.set(i, vD.vd.get(i) + bbp * (bbp > 0 ? 1 : -1) )

    VP.pcL := vD.vt.indexof(vD.vt.max())
    ttV     = vD.vt.sum() * vpVA
    va      = vD.vt.get(VP.pcL)
    VP.laP := VP.pcL
    VP.lbP := VP.pcL

    while va < ttV
        if VP.lbP == 0 and VP.laP == vpNR - 1
            break

        vaP = 0.
        if VP.laP < vpNR - 1
            vaP := vD.vt.get(VP.laP + 1)

        vbP = 0.
        if VP.lbP > 0
            vbP := vD.vt.get(VP.lbP - 1)

        if vaP >= vbP
            va  += vaP
            VP.laP += 1
        else
            va  += vbP
            VP.lbP -= 1

    vaH = pLST + (VP.laP + 1.) * pSTP
    poc = pLST + (VP.pcL + .5) * pSTP
    vaL = pLST + (VP.lbP + .0) * pSTP
    pLN = vpLN > 360 ? 360 : vpLN

    if vahS
        f_drawLineX(VP.sI, vaH, vpRT ? (vpSH ? int((pLN * vpWD + vpHO)) : spSH ? vpHO : 0) + last_bar_index : last_bar_index, vaH, xloc.bar_index, extend.none, vahC, line.style_solid, vahW)

    if pcSH == 'Last (Line)'
        f_drawLineX(VP.sI, poc, last_bar_index, poc, xloc.bar_index, extend.none, pocC, line.style_solid, pocW)

    if vlSH
        f_drawLineX(VP.sI, vaL, vpRT ? (vpSH ? int((pLN * vpWD + vpHO)) : spSH ? vpHO : 0) + last_bar_index : last_bar_index, vaL, xloc.bar_index, extend.none, valC, line.style_solid, valW)

    if vaBG
        VP.vp.push(box.new(VP.sI, vaL, last_bar_index, vaH, vBGC, 1, line.style_dotted, bgcolor = vBGC))

    if vpBG
        VP.vp.push(box.new(VP.sI, pLST, last_bar_index, pHST, bgC, 1, line.style_dotted, bgcolor = bgC))

    if vpLV
        f_drawLabelX(vpRT ? (vpSH ? int((pLN * vpWD + vpHO)) : spSH ? vpHO : 0) + last_bar_index : last_bar_index, pHST,
                     str.tostring(pHST, format.mintick), color.new(chart.fg_color, 89), vpRT ? not vpSH and not spSH ? label.style_label_left : label.style_label_down : label.style_label_left, chart.fg_color, rpS,
                     'Profile High')

        f_drawLabelX(vpRT ? (vpSH ? int((pLN * vpWD + vpHO)) : spSH ? vpHO : 0) + last_bar_index + (spSH ? int(vD.vd.max() / vD.vt.max() * pLN * vpWD) : 0) : last_bar_index, vaH,
                     str.tostring(vaH, format.mintick), color.new(vahC, 89), label.style_label_left, vahC, rpS, 'Value Area High')

        f_drawLabelX(vpRT ? (vpSH ? int((pLN * vpWD + vpHO)) : spSH ? vpHO : 0) + last_bar_index + (spSH ? int(vD.vd.max() / vD.vt.max() * pLN * vpWD) : 0) : last_bar_index, poc,
                     str.tostring(poc, format.mintick), color.new(pocC, 89), label.style_label_left, pocC, rpS, 'Point of Control')

        f_drawLabelX(vpRT ? (vpSH ? int((pLN * vpWD + vpHO)) : spSH ? vpHO : 0) + last_bar_index + (spSH ? int(vD.vd.max() / vD.vt.max() * pLN * vpWD) : 0) : last_bar_index, vaL,
                     str.tostring(vaL, format.mintick), color.new(valC, 89), label.style_label_left, valC, rpS, 'Value Area Low')

        f_drawLabelX(vpRT ? (vpSH ? int((pLN * vpWD + vpHO)) : spSH ? vpHO : 0) + last_bar_index : last_bar_index, pLST,
                     str.tostring(pLST, format.mintick), color.new(chart.fg_color, 89), vpRT ? not vpSH and not spSH ? label.style_label_left : label.style_label_up : label.style_label_left, chart.fg_color, rpS,
                     'Profile Low')

    if vpST
        table change = table.new(tPOS, 2, 10, border_width = 3)
        tC = chart.fg_color
        table.cell(change, 0, 0, 'Profile High', text_color = tC, bgcolor = color.new(tC, 80), text_halign = text.align_left, text_size = ppLS,
                     tooltip = 'profile high - ' + str.tostring(pHST, format.mintick) + '\n %' + str.tostring((pHST - pLST) / pLST * 100, '#.##') + ' higher than the profile low (' + str.tostring(pLST, format.mintick) + ')')
        table.cell(change, 1, 0, str.tostring(pHST, format.mintick), text_color = tC, bgcolor = color.new(tC, 80), text_halign = text.align_right, text_size = ppLS)
        table.cell(change, 0, 1, 'Value Area High', text_color = tC, bgcolor = color.new(tC, 80), text_halign = text.align_left, text_size = ppLS)
        table.cell(change, 1, 1, str.tostring(vaH, format.mintick), text_color = tC, bgcolor = color.new(tC, 80), text_halign = text.align_right, text_size = ppLS)
        table.cell(change, 0, 2, 'Point of Control', text_color = tC, bgcolor = color.new(tC, 80), text_halign = text.align_left, text_size = ppLS)
        table.cell(change, 1, 2, str.tostring(poc, format.mintick), text_color = tC, bgcolor = color.new(tC, 80), text_halign = text.align_right, text_size = ppLS)
        table.cell(change, 0, 3, 'Value Area Low', text_color = tC, bgcolor = color.new(tC, 80), text_halign = text.align_left, text_size = ppLS)
        table.cell(change, 1, 3, str.tostring(vaL, format.mintick), text_color = tC, bgcolor = color.new(tC, 80), text_halign = text.align_right, text_size = ppLS)
        table.cell(change, 0, 4, 'Profile Low', text_color = tC, bgcolor = color.new(tC, 80), text_halign = text.align_left, text_size = ppLS,
                     tooltip = 'profile low - '  + str.tostring(pLST, format.mintick) + '\n %' + str.tostring((pHST - pLST) / pHST * 100, '#.##') + ' lower than the profile high (' + str.tostring(pHST, format.mintick) + ')')
        table.cell(change, 1, 4, str.tostring(pLST, format.mintick), text_color = tC, bgcolor = color.new(tC, 80), text_halign = text.align_right, text_size = ppLS)
        table.cell(change, 0, 5, 'Total Volume\nin VP Range', text_color = tC, bgcolor = color.new(tC, 80), text_halign = text.align_left, text_size = ppLS, tooltip = 'total traded volume in vp range')
        table.cell(change, 1, 5, str.tostring(vD.vt.sum(), format.volume), text_color = tC, bgcolor = color.new(tC, 80), text_halign = text.align_right, text_size = ppLS)
        table.cell(change, 0, 6, 'Avg Volume/Bar', text_color = tC, bgcolor = color.new(tC, 80), text_halign = text.align_left, text_size = ppLS, tooltip = 'average traded volume per bar in vp range')
        table.cell(change, 1, 6, str.tostring(vD.vt.sum() / (vpLN + 1), format.volume), text_color = tC, bgcolor = color.new(tC, 80), text_halign = text.align_right, text_size = ppLS)
        table.cell(change, 0, 7, 'Volume MA (' + str.tostring(vmaL) + ')', text_color = tC, bgcolor = color.new(tC, 80), text_halign = text.align_left, text_size = ppLS, tooltip = 'volume moving average')
        table.cell(change, 1, 7, str.tostring(vSMA, format.volume), text_color = tC, bgcolor = color.new(tC, 80), text_halign = text.align_right, text_size = ppLS)
        table.cell(change, 0, 8, 'Number of Bars', text_color = tC, bgcolor = color.new(tC, 80), text_halign = text.align_left, text_size = ppLS, tooltip = 'number of chart bars : ' + str.tostring(vpLN) + ' + 1 (developping bar)')
        table.cell(change, 1, 8, str.tostring(vpLN + 1), text_color = tC, bgcolor = color.new(tC, 80), text_halign = text.align_right, text_size = ppLS)
        table.cell(change, 0, 9, 'Data From', text_color = tC, bgcolor = color.new(tC, 80), text_halign = text.align_left, text_size = ppLS,
                     tooltip = 'volume data fetching logic\n\nif #bars <= 200\n -two lower timeframes\nelse if #bars <= 700\n -one lower timeframe\nelse\n -chart timeframe')
        table.cell(change, 1, 9, ltf + ' TF', text_color = tC, bgcolor = color.new(tC, 80), text_halign = text.align_right, text_size = ppLS)

    for i = 0 to vpNR - 1

        if vpSH
            sBI = vpRT ? int((pLN * vpWD + vpHO)) + int(last_bar_index - vD.vb.get(i) / vD.vt.max() * pLN * vpWD) : VP.sI
            eBI = vpRT ? int((pLN * vpWD + vpHO)) + last_bar_index : int(sBI + vD.vb.get(i) / vD.vt.max() * pLN * vpWD)
            VP.vp.push(box.new(sBI, pLST + (i + .1) * pSTP, eBI, pLST + (i + .9) * pSTP, color(na), bgcolor = i >= VP.lbP and i <= VP.laP ? vaUC : vpUC))

            sBI := vpRT ? sBI : eBI
            eBI := vpRT ? sBI - int( (vD.vt.get(i) - vD.vb.get(i)) / vD.vt.max() * pLN * vpWD) : sBI + int( (vD.vt.get(i) - vD.vb.get(i)) / vD.vt.max() * pLN * vpWD)
            VP.vp.push(box.new(sBI, pLST + (i + .1) * pSTP, eBI, pLST + (i + .9) * pSTP, color(na), bgcolor = i >= VP.lbP and i <= VP.laP ? vaDC : vpDC))

        if spSH
            sBI = vpRT ? (vpSH ? int((pLN * vpWD + vpHO)) : vpHO) + int(last_bar_index + vD.vd.get(i) / vD.vt.max() * pLN * vpWD) : VP.sI
            eBI = vpRT ? (vpSH ? int((pLN * vpWD + vpHO)) : vpHO) + last_bar_index : vpRL ? int(sBI + vD.vd.get(i) / vD.vt.max() * pLN * vpWD) : int(sBI - vD.vd.get(i) / vD.vt.max() * pLN * vpWD)

            bbp = 2 * vD.vb.get(i) - vD.vt.get(i)
            VP.vp.push(box.new(sBI, pLST + (i + .1) * pSTP, eBI, pLST + (i + .9) * pSTP, color(na), bgcolor = bbp > 0 ? spUC : spDC))

        if sdSH and vD.vt.get(i) / vD.vt.max() < sdTH
            sdC = pLST + (i + 0.50) * pSTP > pLST + (VP.pcL + .5) * pSTP ? sdSC : sdDC
            VP.vp.push(box.new(b.i[vpLN], pLST + (i + 1.) * pSTP, b.i, pLST + (i + .0) * pSTP, color(na), bgcolor = sdC ))

//-----------------------------------------------------------------------------}
// Calculations Volume Histogram
//-----------------------------------------------------------------------------{

pHSTv = ta.highest(b.h, vpLN < 497 ? vpLN : 496)
pLSTv = ta.lowest (b.l, vpLN < 497 ? vpLN : 496)
vHST  = ta.highest(nzV, vpLN < 497 ? vpLN : 496)
vMAR  = nzV / vSMA

if barstate.islast and not na(nzV) and vhSH and vSMA > 0

    pCHR = (pHSTv - pLSTv) / pHSTv

    if VH.vh.size() > 0
        for i = 0 to VH.vh.size() - 1
            line.delete(VH.vh.shift())

    VH.pMA.clear()
    VH.vMA.delete()

    for bI = 0 to vpLN

        if VH.vh.size() < 500
            VH.vh.push(line.new(
                 b.i[bI],  vhLP ? pHST + pHSTv * pCHR * vhVO : pLST - pLSTv * pCHR * vhVO,
                 b.i[bI], (vhLP ? pHST + pHSTv * pCHR * vhVO : pLST - pLSTv * pCHR * vhVO) * (1 + ( vhLP ? 1 : -1) * nzV[bI] / vHST * pCHR / vhHT),
                 xloc.bar_index, extend.none, b.c[bI] > b.o[bI] ? vhUC : vhDC, line.style_solid, 2))

            if vmaS and not na(vSMA[bI])
                VH.pMA.push(chart.point.from_index(b.i[bI], (vhLP ? pHST + pHSTv * pCHR * vhVO : pLST - pLSTv * pCHR * vhVO) * (1 + (vhLP ? 1 : -1) * nzV[bI] / vHST * pCHR / vhHT / vMAR[bI])))

    VH.vMA := polyline.new(VH.pMA, false, false, xloc.bar_index, vmaC, color(na), line.style_solid, 1)

//-----------------------------------------------------------------------------}
// Calculations Volume Weighted Colored Bars
//-----------------------------------------------------------------------------{

barcolor(vwcb and not na(nzV) ? nzV > vSMA * upTH ? b.o < b.c ? #006400 : #910000 : nzV < vSMA * dnTH ? b.o < b.c ? #7FFFD4 : #FF9800 : na : na, title='Volume Weighted Colored Bars', editable = false)

//-----------------------------------------------------------------------------}
// Alerts
//-----------------------------------------------------------------------------{

if f_crossingLevelX(b.c[1], pLST + (VP.pcL + .50) * pSTP) and pcSH != 'None'
    alarm('price action ' + (b.c[1] > pLST + (VP.pcL + .50) * pSTP ? 'crossed above ' : 'crossed below ') + 'the point of control line')

if f_crossingLevelX(b.c[1], pLST + (VP.laP + 1.00) * pSTP) and vahS
    alarm('price action ' + (b.c[1] > pLST + (VP.laP + 1.00) * pSTP ? 'crossed above ' : 'crossed below ') + 'the value area high line')

if f_crossingLevelX(b.c[1], pLST + (VP.lbP + 0.00) * pSTP) and vlSH
    alarm('price action ' + (b.c[1] > pLST + (VP.lbP + 0.00) * pSTP ? 'crossed above ' : 'crossed below ') + 'the value area low line')

if nzV > vSMA * upTH and (vwcb or vhSH)
    alarm('high volume detected')

if nzV > vSMA * 4.669 and (vwcb or vhSH)
    alarm('watch out volume spike detected, may be a sign of exhaustion')

//-----------------------------------------------------------------------------{

var table logo = table.new(position.bottom_right, 1, 1)
if barstate.islast
    table.cell(logo, 0, 0, '☼☾  ', text_size = size.normal, text_color = color.teal)

//-----------------------------------------------------------------------------}

Overview

Volume Profile and Indicator by DGT also plots a sentiment profile, a developing point of control, and value-area high and low around a configurable percentage. Optional supply and demand zones mark low-activity areas using a threshold percent. Lookback length, polarity method, colors, profile stats, and price-level labels are adjustable. No trade signals or exits are defined.

Details

Published by

namuan on GitHub

Type

Indicator, Pine Script v5

Draws

On the price chart

Category

Volume, Support & resistance

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

trading-strategiesmarket-analysisdtalestock-market-analysistelegram-botearnings-calendaroptions-trading

Settings

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

SettingTypeDefaultVariable
Volume ProfilebooltruevpSH
  Up Volume colorcolor.new(#5d606b, 50)vpUC
Down Volume colorcolor.new(#d1d4dc, 50)vpDC
  Value Area Upcolorcolor.new(#2962ff, 30)vaUC
Value Area Downcolorcolor.new(#fbc02d, 30)vaDC
Sentiment ProfilebooltruespSH
  Bullishcolorcolor.new(#26a69a, 30)spUC
Bearishcolorcolor.new(#ef5350, 30)spDC
Supply & Demand ZonesbooltruesdSH
  Supply & Demand Threshold %int15sdTH
  Supply Zonescolorcolor.new(#ec1313, 80)sdSC
Demand Zonescolorcolor.new(#0094FF, 80)sdDC
Show all 40 settings
SettingTypeDefaultVariable
Point of ControlstringDeveloping POCpcSH
pocCcolor#f44336pocC
pocWint2pocW
Value Area (%)float68vpVA
Value Area High (VAH)booltruevahS
vahCcolor#2962ffvahC
vahWint1vahW
Value Area Low (VAL)booltruevlSH
valCcolor#2962ffvalC
valWint1valW
Profile Polarity MethodstringspP1vpPT
Profile Lookback RangestringFixed RangevpLR
Lookback Length / Fixed Rangeint360vpLN
Profile StatsbooltruevpST
ppLSstringSmallppLS
lcDBstringTop RightlcDB
Profile Price LevelsbooltruevpLV
rpLSstringSmallrpLS
Profile PlacementstringRightvpPL
Profile Number of Rowsint100vpNR
Profile Widthfloat31vpWD
Profile Horizontal Offsetint13vpHO
Value Area Background  boolfalsevaBG
vBGCcolorcolor.new(#2962ff, 89)vBGC
Profile Range Background boolfalsevpBG
bgCcolorcolor.new(#2962ff, 95)bgC
Volume HistogrambooltruevhSH
Volume MA,         LengthbooltruevmaS
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

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

D/W/M VWAPs

by cryptorife
75 stars

This indicator plots daily, weekly, and monthly volume-weighted average prices on the price chart, using a selectable source that defaults to hlc3. For each enabled period it also draws two standard-deviation bands around the VWAP, with multipliers defaulting

Indicator v4 VolumeVolatility & bands
Updated 3 years ago · GPL-3.0 GitHub repository of D/W/M VWAPs

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