Volume Profile, Pivot Anchored by DGT

dgtrd · study · 309 行 · 点赞 21,716 · TradingView 原页

本页源码来自 TradingView 公开发布的开源脚本,版权归原作者所有, 请遵循其原始许可(Pine 脚本常见 CC BY-NC-SA / MPL-2.0 / MIT)。 本项目仅用于研究检索与许可范围内的移植。

Pine Script

//@version=5
// ══════════════════════════════════════════════════════════════════════════════════════════════════ //
//# * ══════════════════════════════════════════════════════════════════════════════════════════════
//# *
//# * Study       : Volume Profile, Pivot Anchored
//# * Author      : © dgtrd
//# *
//# * Revision History
//# *  Release    : Jun 06, 2022 : Initial Release
//# *
//# * ══════════════════════════════════════════════════════════════════════════════════════════════
// ══════════════════════════════════════════════════════════════════════════════════════════════════ //
 
// ---------------------------------------------------------------------------------------------- //
// Functions  ----------------------------------------------------------------------------------- //
 
f_drawOnlyLineX(_x1, _y1, _x2, _y2, _xloc, _extend, _color, _style, _width) =>
    id = line.new(_x1, _y1, _x2, _y2, _xloc, _extend, _color, _style, _width)
 
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)
    id
 
f_drawOnlyBoxX(_left, _top, _right, _bottom, _border_color, _border_width, _border_style) =>
    box.new(_left, _top, _right, _bottom, _border_color, _border_width, _border_style, bgcolor=_border_color)
 
f_drawOnlyLabelX(_x, _y, _text, _xloc, _yloc, _color, _style, _textcolor, _size, _textalign, _tooltip) =>
    label.new(_x, _y, _text, _xloc, _yloc, _color, _style, _textcolor, _size, _textalign, _tooltip)
 
f_drawLabelX(_x, _y, _text, _xloc, _yloc, _color, _style, _textcolor, _size, _textalign, _tooltip) =>
    var id = label.new(_x, _y, _text, _xloc, _yloc, _color, _style, _textcolor, _size, _textalign, _tooltip)
    label.set_xy(id, _x, _y)
    label.set_text(id, _text)
    label.set_tooltip(id, _tooltip)
 
f_getHighLow(_len, _calc, _offset) =>
    if _calc
        htf_l = low [_offset]
        htf_h = high[_offset]
        
        for x = 1 to _len
            htf_l := math.min(low [_offset + x], htf_l)
            htf_h := math.max(high[_offset + x], htf_h)
 
        [htf_h, htf_l]
 
// check for box breaches - code snippet from pine user guide
f_checkBreaches(arrayOfBoxes, extend) =>
    int qtyOfBoxes = array.size(arrayOfBoxes)
    for boxNo = 0 to (qtyOfBoxes > 0 ? qtyOfBoxes - 1 : na)
        if boxNo < array.size(arrayOfBoxes)
            box   currentBox    = array.get(arrayOfBoxes, boxNo)
            float boxMidLevel   = math.avg(box.get_bottom(currentBox), box.get_top(currentBox))
            bool  boxWasCrossed = math.sign(close[1] - boxMidLevel) != math.sign(close - boxMidLevel)
 
            if boxWasCrossed and extend == 'Until Bar Cross'
                array.remove(arrayOfBoxes, boxNo)
                int(na)
            else
                box.set_right(currentBox, bar_index)
                int(na)
 
// Functions  ----------------------------------------------------------------------------------- //
// ---------------------------------------------------------------------------------------------- //
 
indicator("Volume Profile, Pivot Anchored by DGT", "VP-PA ʙʏ DGT ☼☾", true, max_bars_back = 5000, max_boxes_count = 500)//, max_lines_count = 100, max_labels_count = 100)
 
// ---------------------------------------------------------------------------------------------- //
// Inputs --------------------------------------------------------------------------------------- //
 
group_volume_profile    = 'Pivot Points Volume Profile'
 
tooltip_pvt       = 'The Pivot Points High Low indicator is used to determine and anticipate potential changes in market price and reversals\n' +
                     '\'Volume Profile, Pivot Points Anchored\' Custom indicator addtionally calculates the trading activity between two Pivot Points'
pvtLength         = input.int(20, "Pivot Points Left/Right Length", minval=1, group = group_volume_profile, tooltip = tooltip_pvt)
 
tooltip_vp        = 'Common Interest Profile (Total Volume) - displays total trading activity over a specified time period at specific price levels'
volumeProfile     = input.bool(true, 'Volume Profile (Common Interest)'             , inline='BB3', group = group_volume_profile, tooltip = tooltip_vp)
totalVolumeColor  = input.color(color.new(#fbc02d, 35), ''                          , inline='BB3', group = group_volume_profile)
vaVolumeColor     = input.color(color.new(#434651, 35), ''                          , inline='BB3', group = group_volume_profile)
 
tooltip_va        = 'Value Area (VA) – The range of price levels in which a specified percentage of all volume was traded during the time period'
isValueArea       = input.float(68, "Value Area Volume %", minval = 0, maxval = 100               , group = group_volume_profile, tooltip = tooltip_va) / 100
 
tooltip_poc       = 'Point of Control (POC) - The price level for the time period with the highest traded volume'
pointOfControl    = input.bool(true, 'Point of Control (PoC)'                       , inline='PoC', group = group_volume_profile, tooltip = tooltip_poc)
pocColor          = input.color(color.new(#ff0000, 0), ''                           , inline='PoC', group = group_volume_profile)
pocExtend         = input.string('None', 'Extend Point of Control (PoC)', options=['Until Last Bar', 'Until Bar Cross', 'None'], group = group_volume_profile)
 
tooltip_vah       = 'Value Area High (VAH) - The highest price level within the value area'
valueAreaHigh     = input.bool(true, 'Value Area High (VAH)'                        , inline='VAH', group = group_volume_profile, tooltip = tooltip_vah)
vahColor          = input.color(color.new(#2962ff, 0), ''                           , inline='VAH', group = group_volume_profile)
 
tooltip_val       = 'Value Area Low (VAL) - The lowest price level within the value area'
valueAreaLow      = input.bool(true, 'Value Area Low (VAL) '                        , inline='VAL', group = group_volume_profile, tooltip = tooltip_val)
valColor          = input.color(color.new(#2962ff, 0), ''                           , inline='VAL', group = group_volume_profile)
 
vaBackground      = input.bool(true, 'Background Fill of Value Area (VA)'           , inline='vBG', group = group_volume_profile)
vaBackgroundColor = input.color(color.new(#2962ff, 89), ''                          , inline='vBG', group = group_volume_profile)
 
priceLevels       = input.string('Pivot Points', 'Price Level Labels', options = ['Profile High/Low', 'Value Area High/Low', 'Pivot Points', 'None'], group = group_volume_profile)
 
profileLevels     = input.int(25, 'Number of Rows' , minval = 10, maxval = 100 , step = 1         , group = group_volume_profile)
profilePlacement  = input.string('Left', 'Placment', options = ['Right', 'Left']                  , group = group_volume_profile)
profileWidth      = input.int(30, 'Profile Width %', minval = 0, maxval = 100                     , group = group_volume_profile) / 100
backgroundFill    = input.bool(true, 'Background Fill of Profile Range'             , inline ='BG', group = group_volume_profile)
backgroundColor   = input.color(color.new(#2962ff, 95), ''                          , inline ='BG', group = group_volume_profile)
 
tooltip_vwcb      = 'Colors bars based on the bar\'s volume relative to volume moving average'
group_vwcb        = 'Volume Weighted Colored Bars'
vwcb              = input.bool(true, 'Volume Weighted Colored Bars', group=group_vwcb, tooltip = tooltip_vwcb)
 
// ---------------------------------------------------------------------------------------------- //
// Definitions ---------------------------------------------------------------------------------- //
 
barPriceLow       = low
barPriceHigh      = high
bullCandle        = close > open
nzVolume          = nz(volume)
 
volumeStorageT    = array.new_float(profileLevels + 1, 0.)
var a_poc         = array.new_box()
 
var x1            = 0
var x2            = 0
var levelAbovePoc = 0
var levelBelowPoc = 0
 
// Definitions ---------------------------------------------------------------------------------- //
// ---------------------------------------------------------------------------------------------- //
// Calculations --------------------------------------------------------------------------------- //
 
pvtHigh           = ta.pivothigh(pvtLength, pvtLength)
pvtLow            = ta.pivotlow (pvtLength, pvtLength)
proceed           = not na(pvtHigh) or not na(pvtLow)
 
if proceed
    x1 := x2
    x2 := bar_index
 
profileLength = x2 - x1
 
[priceHighest, priceLowest] = f_getHighLow(profileLength, proceed, pvtLength)
priceStep = (priceHighest - priceLowest) / profileLevels
 
if proceed and nzVolume and priceStep > 0 and bar_index > profileLength and profileLength > 0
 
    for barIndexx = 1 to profileLength
        level = 0
        barIndex = barIndexx + pvtLength
        
        for priceLevel = priceLowest to priceHighest by priceStep
            if barPriceHigh[barIndex] >= priceLevel and barPriceLow[barIndex] < priceLevel + priceStep
                array.set(volumeStorageT, level, array.get(volumeStorageT, level) + nzVolume[barIndex] * ((barPriceHigh[barIndex] - barPriceLow[barIndex]) == 0 ? 1 : priceStep / (barPriceHigh[barIndex] - barPriceLow[barIndex])) )
            level += 1
 
    pocLevel          = array.indexof(volumeStorageT, array.max(volumeStorageT))
    totalVolumeTraded = array.sum(volumeStorageT) * isValueArea
    valueArea         = array.get(volumeStorageT, pocLevel)
    levelAbovePoc    := pocLevel
    levelBelowPoc    := pocLevel
    
    while valueArea < totalVolumeTraded
        if levelBelowPoc == 0 and levelAbovePoc == profileLevels - 1
            break
 
        volumeAbovePoc = 0.
        if levelAbovePoc < profileLevels - 1 
            volumeAbovePoc := array.get(volumeStorageT, levelAbovePoc + 1)
 
        volumeBelowPoc = 0.
        if levelBelowPoc > 0
            volumeBelowPoc := array.get(volumeStorageT, levelBelowPoc - 1)
        
        if volumeBelowPoc == 0 and volumeAbovePoc == 0
            break
        
        if volumeAbovePoc >= volumeBelowPoc
            valueArea     += volumeAbovePoc
            levelAbovePoc += 1
        else
            valueArea     += volumeBelowPoc
            levelBelowPoc -= 1
 
    for level = 0 to profileLevels - 1
        if volumeProfile
            startBoxIndex = profilePlacement == 'Right' ? bar_index - int(array.get(volumeStorageT, level) / array.max(volumeStorageT) * profileLength * profileWidth)  : bar_index - profileLength
            endBoxIndex   = profilePlacement == 'Right' ? bar_index  :  startBoxIndex + int( array.get(volumeStorageT, level) / array.max(volumeStorageT) * profileLength * profileWidth)
            f_drawOnlyBoxX(startBoxIndex - pvtLength, priceLowest + (level + 0.1) * priceStep, endBoxIndex - pvtLength, priceLowest + (level + 0.9) * priceStep, level >= levelBelowPoc and level <= levelAbovePoc ? totalVolumeColor : vaVolumeColor, 1, line.style_solid)
 
    if backgroundFill
        f_drawOnlyBoxX(bar_index[pvtLength] - profileLength, priceHighest, bar_index[pvtLength], priceLowest, backgroundColor, 1, line.style_dotted)
 
    if pointOfControl
        array.push(a_poc, box.new(bar_index[pvtLength] - profileLength, priceLowest + (array.indexof(volumeStorageT, array.max(volumeStorageT)) + .40) * priceStep, bar_index[pvtLength], priceLowest + (array.indexof(volumeStorageT, array.max(volumeStorageT)) + .60) * priceStep, pocColor, bgcolor = pocColor ))
 
    vah = f_drawOnlyLineX(bar_index[pvtLength] - profileLength, priceLowest + (levelAbovePoc + 1.00) * priceStep, bar_index[pvtLength], priceLowest + (levelAbovePoc + 1.00) * priceStep, xloc.bar_index, extend.none, valueAreaHigh ? vahColor : #00000000, line.style_solid, 2)
    val = f_drawOnlyLineX(bar_index[pvtLength] - profileLength, priceLowest + (levelBelowPoc + 0.00) * priceStep, bar_index[pvtLength], priceLowest + (levelBelowPoc + 0.00) * priceStep, xloc.bar_index, extend.none, valueAreaLow  ? valColor : #00000000, line.style_solid, 2)
 
    if vaBackground
        linefill.new(vah, val, vaBackgroundColor)
 
    if priceLevels != 'None'
        upperPriceLevel = priceLevels == 'Value Area High/Low' ? priceLowest + (levelAbovePoc + 1.00) * priceStep : priceHighest
        lowerPriceLevel = priceLevels == 'Value Area High/Low' ? priceLowest + (levelBelowPoc + 0.00) * priceStep : priceLowest
        
        if priceLevels != 'Pivot Points'
            f_drawOnlyLabelX(bar_index[pvtLength] - profileLength / 2, upperPriceLevel, str.tostring(upperPriceLevel, format.mintick), xloc.bar_index, yloc.price, chart.fg_color, label.style_label_down, chart.bg_color, size.normal, text.align_left, 'Profile High - ' + str.tostring(priceHighest, format.mintick) + '\n %' + str.tostring((priceHighest - priceLowest) / priceLowest  * 100, '#.##') + ' higher than the Profile Low\n\nValue Area High - ' + str.tostring(priceLowest + (levelAbovePoc + 1.00) * priceStep, format.mintick) + '\n value area volume %' + str.tostring(isValueArea * 100) + '\n value area width %' + str.tostring((upperPriceLevel - lowerPriceLevel) / (priceHighest - priceLowest) * 100, '#.##') + '\n\nPoint Of Control - ' + str.tostring(priceLowest + (array.indexof(volumeStorageT, array.max(volumeStorageT)) + .50) * priceStep, format.mintick) + '\n\nNumber of bars : ' + str.tostring(profileLength) )
            f_drawOnlyLabelX(bar_index[pvtLength] - profileLength / 2, lowerPriceLevel, str.tostring(lowerPriceLevel, format.mintick), xloc.bar_index, yloc.price, chart.fg_color, label.style_label_up  , chart.bg_color, size.normal, text.align_left, 'Profile Low - '  + str.tostring(priceLowest, format.mintick)  + '\n %' + str.tostring((priceHighest - priceLowest) / priceHighest * 100, '#.##') + ' lower than the Profile High\n\nValue Area Low - '  + str.tostring(priceLowest + (levelBelowPoc + 0.00) * priceStep, format.mintick) + '\n value area volume %' + str.tostring(isValueArea * 100) + '\n value area width %' + str.tostring((upperPriceLevel - lowerPriceLevel) / (priceHighest - priceLowest) * 100, '#.##') + '\n\nPoint Of Control - ' + str.tostring(priceLowest + (array.indexof(volumeStorageT, array.max(volumeStorageT)) + .50) * priceStep, format.mintick) + '\n\nNumber of bars : ' + str.tostring(profileLength) )
        else
            if not na(pvtHigh)
                f_drawOnlyLabelX(bar_index[pvtLength], pvtHigh, str.tostring(pvtHigh, format.mintick), xloc.bar_index, yloc.price, chart.fg_color, label.style_label_down, chart.bg_color, size.normal, text.align_left, 'Pivot High\nNumber of bars : ' + str.tostring(profileLength) )
            if not na(pvtLow)
                f_drawOnlyLabelX(bar_index[pvtLength], pvtLow , str.tostring(pvtLow , format.mintick), xloc.bar_index, yloc.price, chart.fg_color, label.style_label_up  , chart.bg_color, size.normal, text.align_left, 'Pivot Low\nNumber of bars : '  + str.tostring(profileLength) )
 
if pointOfControl and pocExtend != 'None' 
    f_checkBreaches(a_poc, pocExtend)
 
var a_profileD    = array.new_box()
profileLength    := barstate.islast ? last_bar_index - x2 + pvtLength  : 1
priceHighest     := ta.highest(high, profileLength > 0 ? profileLength + 1 : 1)
priceLowest      := ta.lowest (low , profileLength > 0 ? profileLength + 1 : 1)
priceStep        := (priceHighest - priceLowest) / profileLevels
 
if barstate.islast and nzVolume and profileLength > 0 and priceStep > 0
    
    if array.size(a_profileD) > 0
        for i = 0 to array.size(a_profileD) - 1
            box.delete(array.shift(a_profileD))
 
    for barIndexx = 1 to profileLength
        level = 0
        barIndex = barIndexx + pvtLength
        
        for priceLevel = priceLowest to priceHighest by priceStep
            if barPriceHigh[barIndex] >= priceLevel and barPriceLow[barIndex] < priceLevel + priceStep
                array.set(volumeStorageT, level, array.get(volumeStorageT, level) + nzVolume[barIndex] * ((barPriceHigh[barIndex] - barPriceLow[barIndex]) == 0 ? 1 : priceStep / (barPriceHigh[barIndex] - barPriceLow[barIndex])) )
            level += 1
 
    pocLevel          = array.indexof(volumeStorageT, array.max(volumeStorageT))
    totalVolumeTraded = array.sum(volumeStorageT) * isValueArea
    valueArea         = array.get(volumeStorageT, pocLevel)
    levelAbovePoc    := pocLevel
    levelBelowPoc    := pocLevel
    
    while valueArea < totalVolumeTraded
        if levelBelowPoc == 0 and levelAbovePoc == profileLevels - 1
            break
 
        volumeAbovePoc = 0.
        if levelAbovePoc < profileLevels - 1 
            volumeAbovePoc := array.get(volumeStorageT, levelAbovePoc + 1)
 
        volumeBelowPoc = 0.
        if levelBelowPoc > 0
            volumeBelowPoc := array.get(volumeStorageT, levelBelowPoc - 1)
            
        if volumeBelowPoc == 0 and volumeAbovePoc == 0
            break
        
        if volumeAbovePoc >= volumeBelowPoc
            valueArea     += volumeAbovePoc
            levelAbovePoc += 1
        else
            valueArea     += volumeBelowPoc
            levelBelowPoc -= 1
 
    for level = 0 to profileLevels - 1
        if volumeProfile
            startBoxIndex = profilePlacement == 'Right' ? bar_index - int(array.get(volumeStorageT, level) / array.max(volumeStorageT) * profileLength * profileWidth)  : bar_index - profileLength
            endBoxIndex   = profilePlacement == 'Right' ? bar_index  :  startBoxIndex + int( array.get(volumeStorageT, level) / array.max(volumeStorageT) * profileLength * profileWidth)
            array.push(a_profileD, box.new(startBoxIndex, priceLowest + (level + 0.1) * priceStep, endBoxIndex, priceLowest + (level + 0.9) * priceStep, level >= levelBelowPoc and level <= levelAbovePoc ? totalVolumeColor : vaVolumeColor, bgcolor = level >= levelBelowPoc and level <= levelAbovePoc ? totalVolumeColor : vaVolumeColor ))
 
    if backgroundFill
        array.push(a_profileD, box.new(bar_index - profileLength, priceHighest, bar_index, priceLowest, backgroundColor, bgcolor = backgroundColor ))
 
    if pointOfControl
        array.push(a_profileD, box.new(bar_index - profileLength, priceLowest + (array.indexof(volumeStorageT, array.max(volumeStorageT)) + .40) * priceStep, bar_index, priceLowest + (array.indexof(volumeStorageT, array.max(volumeStorageT)) + .60) * priceStep, pocColor, bgcolor = pocColor ))
 
    vah = f_drawLineX(bar_index - profileLength, priceLowest + (levelAbovePoc + 1.00) * priceStep, bar_index, priceLowest + (levelAbovePoc + 1.00) * priceStep, xloc.bar_index, extend.none, valueAreaHigh ? vahColor : #00000000, line.style_solid, 2)
    val = f_drawLineX(bar_index - profileLength, priceLowest + (levelBelowPoc + 0.00) * priceStep, bar_index, priceLowest + (levelBelowPoc + 0.00) * priceStep, xloc.bar_index, extend.none, valueAreaLow  ? valColor : #00000000, line.style_solid, 2)
 
    if vaBackground
        linefill.new(vah, val, vaBackgroundColor)
 
    if priceLevels != 'None'
        upperPriceLevel = priceLevels == 'Value Area High/Low' ? priceLowest + (levelAbovePoc + 1.00) * priceStep : priceHighest
        lowerPriceLevel = priceLevels == 'Value Area High/Low' ? priceLowest + (levelBelowPoc + 0.00) * priceStep : priceLowest
        
        if priceLevels != 'Pivot Points'
            f_drawLabelX(bar_index - profileLength / 2, upperPriceLevel, str.tostring(upperPriceLevel, format.mintick), xloc.bar_index, yloc.price, chart.fg_color, label.style_label_down, chart.bg_color, size.normal, text.align_left, 'Profile High - ' + str.tostring(priceHighest, format.mintick) + '\n %' + str.tostring((priceHighest - priceLowest) / priceLowest  * 100, '#.##') + ' higher than the Profile Low\n\nValue Area High - ' + str.tostring(priceLowest + (levelAbovePoc + 1.00) * priceStep, format.mintick) + '\n value area volume %' + str.tostring(isValueArea * 100) + '\n value area width %' + str.tostring((upperPriceLevel - lowerPriceLevel) / (priceHighest - priceLowest) * 100, '#.##') + '\n\nPoint Of Control - ' + str.tostring(priceLowest + (array.indexof(volumeStorageT, array.max(volumeStorageT)) + .50) * priceStep, format.mintick) + '\n\nNumber of bars : ' + str.tostring(profileLength) )
            f_drawLabelX(bar_index - profileLength / 2, lowerPriceLevel, str.tostring(lowerPriceLevel, format.mintick), xloc.bar_index, yloc.price, chart.fg_color, label.style_label_up  , chart.bg_color, size.normal, text.align_left, 'Profile Low - '  + str.tostring(priceLowest, format.mintick)  + '\n %' + str.tostring((priceHighest - priceLowest) / priceHighest * 100, '#.##') + ' lower than the Profile High\n\nValue Area Low - '  + str.tostring(priceLowest + (levelBelowPoc + 0.00) * priceStep, format.mintick) + '\n value area volume %' + str.tostring(isValueArea * 100) + '\n value area width %' + str.tostring((upperPriceLevel - lowerPriceLevel) / (priceHighest - priceLowest) * 100, '#.##') + '\n\nPoint Of Control - ' + str.tostring(priceLowest + (array.indexof(volumeStorageT, array.max(volumeStorageT)) + .50) * priceStep, format.mintick) + '\n\nNumber of bars : ' + str.tostring(profileLength) )
 
//plot(barstate.islast ? priceLowest + (array.indexof(volumeStorageT, array.max(volumeStorageT)) + .50) * priceStep : na, 'Developing PoC', pocColor, display=display.none)
//plot(barstate.islast ? priceLowest + (levelAbovePoc + 1.00) * priceStep : na, 'Developing VAH', vahColor, display=display.none)
//plot(barstate.islast ? priceLowest + (levelBelowPoc + 0.00) * priceStep : na, 'Developing VAL', valColor, display=display.none)
// ---------------------------------------------------------------------------------------------- //
// Volume Weighted Colored Bars ----------------------------------------------------------------- //
 
vSMA = ta.sma(nzVolume, input.int(89, 'Volume Moving Average Length', group = group_vwcb))
barcolor(vwcb and nzVolume ? nzVolume > vSMA * input.float(1.618, 'Higher Theshold', minval=1., step=.1, group=group_vwcb) ? bullCandle ? #006400 : #910000 : nzVolume < vSMA * input.float(0.618, 'Lower Theshold', minval=.1, step=.1, group=group_vwcb) ? bullCandle ? #7FFFD4 : #FF9800 : bullCandle ? color.green : color.red : na, title='Volume Weighted Colored Bars')
// ---------------------------------------------------------------------------------------------- //
 
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)

← 返回列表