-
W posted in the group AI Trading Lab
PineScript for TradingView
Volume Profile// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) https://creativecommons.org/licenses/by-nc-sa/4.0/
// © LuxAlgo
//@version=5indicator(“Volume Profile with Node Detection [LuxAlgo]”, “LuxAlgo – Volume Profile with Node Detection”, overlay = true, max_boxes_count = 500, max_bars_back = 5000)
//———————————————————————————————————————
// Settings
//———————————————————————————————————————{display = display.all – display.status_line
vn_volumeNodesGroup = ‘Volume Nodes’
vn_peakTTip = ‘A volume peak node is recognized when the volume profile nodes for the N preceding and N succeeding nodes are lower than that of the evaluated one, where N is determined by the \’Node Detection Percent %\’ option’
vn_peaksShow = input.string(‘Peaks’, ‘Volume Peaks’, options = [‘Peaks’, ‘Clusters’, ‘None’], inline = ‘vnP’, tooltip = vn_peakTTip, group = vn_volumeNodesGroup, display = display)
vn_peakVolumeColor = input.color(color.new(color.blue, 50), ”, inline = ‘vnP’, group = vn_volumeNodesGroup)
vn_peaksNumberOfNodes = input.int(9, ‘ Node Detection Percent %’, minval = 0, maxval = 100, group = vn_volumeNodesGroup, display = display) / 100
vn_peaksShow := vn_peaksNumberOfNodes == 0 ? ‘None’ : vn_peaksShowvn_troughsTTip = ‘A volume trough node is recognized when the volume profile nodes for the N preceding and N succeeding nodes exceed that of the evaluated one, where N is determined by the \’Node Detection Percent %\’ option’
vn_troughsShow = input.string(‘None’, ‘Volume Troughs’, options = [‘Troughs’, ‘Clusters’, ‘None’], inline = ‘vnT’, tooltip = vn_troughsTTip, group = vn_volumeNodesGroup, display = display)
vn_troughVolumeColor = input.color(color.new(color.gray, 50), ”, inline = ‘vnT’, group = vn_volumeNodesGroup)
vn_troughsNumberOfNodes = input.int(7, ‘ Node Detection Percent %’, minval = 0, maxval = 100, group = vn_volumeNodesGroup, display = display) / 100
vn_troughsShow := vn_troughsNumberOfNodes == 0 ? ‘None’ : vn_troughsShowvn_thresholdTTip = ‘A threshold value specified as a percentage is utilized to detect peak/trough volume nodes. If a value is set, the detection will disregard volume node values lower than the specified threshold.’
vn_VolumeNodeThreshold = input.int(1, ‘Volume Node Threshold %’, minval = 0, maxval = 100, tooltip = vn_thresholdTTip, group = vn_volumeNodesGroup, display = display) / 100vn_highestNVolumeNodes = input.int(0, ‘Highest Volume Nodes’, minval = 0, maxval = 31, inline = ‘vnL’, group = vn_volumeNodesGroup, display = display)
vn_highestVolumeColor = input.color(color.new(color.orange, 25), ”, inline = ‘vnL’, group = vn_volumeNodesGroup)vn_lowestNVolumeNodes = input.int(0, ‘Lowest Volume Nodes’, minval = 0, maxval = 31, inline = ‘vnH’, group = vn_volumeNodesGroup, display = display)
vn_lowestVolumeColor = input.color(color.new(color.navy, 25), ”, inline = ‘vnH’, group = vn_volumeNodesGroup)vp_componentsGroup = ‘Volume Profile – Components’
vp_profileShow = input.bool(true, ‘Volume Profile’, inline = ‘vp’, group = vp_componentsGroup)
vp_profileGradientColors = input.string(‘Gradient Colors’, ”, options = [‘Gradient Colors’, ‘Classic Colors’ ], inline = ‘vp’, group = vp_componentsGroup)
vp_valueAreaUpColor = input.color(color.new(#2962ff, 30), ‘ Value Area Up / Down’, inline = ‘VA’, group = vp_componentsGroup)
vp_valueAreaDwonColor = input.color(color.new(#fbc02d, 30), ‘/’, inline = ‘VA’, group = vp_componentsGroup)
vp_profileUpVolumeColor = input.color(color.new(#5d606b, 50), ‘ Profile Up / Down Volume’, inline = ‘VP’, group = vp_componentsGroup)
vp_profileDownVolumeColor = input.color(color.new(#d1d4dc, 50), ‘/’, inline = ‘VP’, group = vp_componentsGroup)vp_pocShow = input.string(‘None’, ‘Point of Control’, options = [‘Developing’, ‘Regular’, ‘None’], inline = ‘poc’, group = vp_componentsGroup, display = display)
vp_pocColor = input.color(#fbc02d, ”, inline = ‘poc’, group = vp_componentsGroup)
vp_pocWidth = input.int(2, ‘Width’, inline = ‘poc’, group = vp_componentsGroup, display = display)vp_vahShow = input.bool(false, ‘Value Area High (VAH)’, inline = ‘vah’, group = vp_componentsGroup)
vp_vahColor = input.color(#2962ff, ”, inline = ‘vah’, group = vp_componentsGroup)vp_valShow = input.bool(false, ‘Value Area Low (VAL)’, inline = ‘val’, group = vp_componentsGroup)
vp_valColor = input.color(#2962ff, ”, inline = ‘val’, group = vp_componentsGroup)vp_profileLevels = input.string(‘Small’, “Profile Price Labels”, options=[‘Tiny’, ‘Small’, ‘Normal’, ‘None’], group = vp_componentsGroup, display = display)
vp_displayGroup = ‘Volume Profile – Display Settings’
vp_profileLength = input.int(360, ‘Profile Lookback Length’, minval = 10, maxval = 5000, step = 10, group = vp_displayGroup, display = display)
vp_profileLength:= last_bar_index < vp_profileLength ? last_bar_index : vp_profileLength – 1vp_valueAreaThreshold = input.float(70, 'Value Area (%)', minval = 0, maxval = 100, group = vp_displayGroup, display = display) / 100
vp_profilePlracment = input.string('Right', 'Profile Placement', options = ['Right', 'Left'], group = vp_displayGroup, display = display), profilePlacementRight = vp_profilePlracment == 'Right'
vp_profileNumberOfRows = input.int(100, 'Profile Number of Rows' , minval = 30, maxval = 130 , step = 10, group = vp_displayGroup, display = display)
vp_profileWidth = input.float(31, 'Profile Width', minval = 0, maxval = 250, group = vp_displayGroup, display = display) / 100
vp_profileHorizontalOffset = input.int(13, 'Profile Horizontal Offset', maxval = 50, group = vp_displayGroup, display = display)vp_valueAreaBackground = input.bool(false, 'Value Area Background ', inline = 'vBG', group = vp_displayGroup)
vp_valueAreaBackgroundColor = input.color(color.new(#2962ff, 89), '', inline = 'vBG', group = vp_displayGroup)vp_profileBackground = input.bool(false, 'Profile Range Background ', inline = 'pBG', group = vp_displayGroup)
vp_profileBackgroundColor = input.color(color.new(#2962ff, 95), '', inline = 'pBG', group = vp_displayGroup)//———————————————————————————————————————}
// User Defined Types
//———————————————————————————————————————{type BAR
float open = open
float high = high
float low = low
float close = close
float volume = volume
int index = bar_indextype barData
float [] barHigh
float [] barLow
float [] barVolume
bool [] barPolarity
int [] barCounttype volumeData
float [] totalVolume
float [] bullishVolume
float [] bearishVolume
int [] endProfileIndex
bool [] peakVolume
bool [] troughVolumetype volumeProfile
box [] boxes
chart.point [] pocPoints
polyline pocPolyline
int pocLevel
int vahLevel
int valLevel
int startIndex//———————————————————————————————————————}
// Variables
//———————————————————————————————————————{BAR bar = BAR.new()
BAR [] ltfBarData = array.new (1, BAR.new())var barData barDataArray = barData.new(
array.new (na),
array.new (na),
array.new (na),
array.new (na),
array.new (na)
)volumeData volumeDataArray = volumeData.new(
array.new (vp_profileNumberOfRows, 0.),
array.new (vp_profileNumberOfRows, 0.),
array.new (vp_profileNumberOfRows, 0.),
array.new (vp_profileNumberOfRows, 0 ),
array.new (vp_profileNumberOfRows, 0.),
array.new (vp_profileNumberOfRows, 0.)
)var volumeProfile VP = volumeProfile.new(
array.new (na),
array.new (na),
polyline.new (na), na, na, na, na
)var float highestPrice = na
var float lowestPrice = na//———————————————————————————————————————}
// Functions / Methods
//———————————————————————————————————————{renderLine(_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)renderLabel(_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)requestBarData(_lowerTimeframe) => request.security_lower_tf(syminfo.tickerid, _lowerTimeframe, BAR.new(), ignore_invalid_timeframe = true)
calculateTimeframe(_depth) =>
int tfInMs = timeframe.in_seconds(timeframe.period)
int mInMS = 60if _depth == 2
switch
tfInMs ‘1S’
tfInMs ‘5S’tfInMs ‘1’
tfInMs ‘5’
tfInMs ’15’
tfInMs ’60’
=> ‘D’else if _depth == 1
switch
tfInMs ‘1S’
tfInMs ‘5S’
tfInMs ’15S’tfInMs ‘1’
tfInMs ‘5’
tfInMs ’15’
tfInMs ’60’
tfInMs ‘240’
=> ‘D’getTextSize(_text) =>
if _text != ‘None’
switch _text
‘Tiny’ => size.tiny
‘Small’ => size.small
‘Normal’ => size.normal
=> size.auto//———————————————————————————————————————}
// Calculations – Volume Profile
//———————————————————————————————————————{profileLevesSize = getTextSize(vp_profileLevels)
if bar.index == last_bar_index – vp_profileLength
VP.startIndex := bar.index
lowestPrice := bar.low
highestPrice := bar.high
else if bar.index > last_bar_index – vp_profileLength
lowestPrice := math.min(bar.low, lowestPrice)
highestPrice := math.max(bar.high, highestPrice)//if vp_profileLength <= 200
// ltfBarData := requestBarData(calculateTimeframe(2))
//else
if vp_profileLength <= 700
ltfBarData := requestBarData(calculateTimeframe(2))
else
ltfBarData := array.new (1, BAR.new(bar.open, bar.high, bar.low, bar.close, bar.volume))if barstate.ishistory and (bar.index >= last_bar_index – vp_profileLength) and bar.index 0
log.info(“yaz_kizim {0} {1}”, ltfBarData.get(0).volume, na(nz(ltfBarData.get(0).volume)) )
if ltfBarData.size() > 0 and not na(nz(ltfBarData.get(0).volume))
for currentLtfBar = 0 to ltfBarData.size() – 1
barDataArray.barHigh.push(ltfBarData.get(currentLtfBar).high)
barDataArray.barLow.push(ltfBarData.get(currentLtfBar).low)
barDataArray.barVolume.push(ltfBarData.get(currentLtfBar).volume)
barDataArray.barPolarity.push(ltfBarData.get(currentLtfBar).close > ltfBarData.get(currentLtfBar).open)barDataArray.barCount.push(ltfBarData.size())
priceStep = (highestPrice – lowestPrice) / vp_profileNumberOfRows
if barstate.islast and ltfBarData.size() > 0 // barDataArray.barVolume.size() > 0 //
if VP.boxes.size() > 0
for boxIndex = 0 to VP.boxes.size() – 1
box.delete(VP.boxes.shift())if barDataArray.barCount.size() > vp_profileLength
barCount = barDataArray.barCount.shift()
for barCountIndex = 0 to barCount – 1
barDataArray.barHigh.shift()
barDataArray.barLow.shift()
barDataArray.barVolume.shift()
barDataArray.barPolarity.shift()VP.pocPoints.clear()
VP.pocPolyline.delete()if ltfBarData.size() > 0 and not na(nz(ltfBarData.get(0).volume))
for currentLtfBar = 0 to ltfBarData.size() – 1
barDataArray.
About Me
Futures Speculator in Slippers
Chief Financial Analyst at home, as never seen on Forbes or CNBC.
Discovered trading in 2006. Took me exactly 20 years of pain, market cycles, and weight gain to finally go full-time in 2026. And, well, normal jobs feel suspicious.
If I'm going to stay depressed inside my appartment, I might as well get paid for it.
Don't contact me unless it's about why NQ made that 100 point move without any reason.
