Came across this one - https://www.tradingview.com/script/qZRH ... nd-Filter/ - and seemed interesting. Used an Mladen's version of Sylvain Vervoort Bollinger Band indie as a basis ("sve bollinger band_main_mtf + alerts.mq4").
It basically counts how many times the price crosses the upper channel or the lower channel. The original version resets when the price crosses the opposite channel. I did add the option to reset the counter to 0 when the middle band is crossed, which could potentially indicate a ranging market. First impression is that this option is better set to FALSE when using "SVE BB" channel.
BB Channel with and without reset when middle band is crossed:
Re: Already Converted TradingView Indicators to MT4 Indicators
622
Hi Mr.Tools
Please help.
Do you have an indicator that detects, retrieves, or automatically separates the last 20 candlesticks, excluding the current one?
Thanks in advance
Please help.
Do you have an indicator that detects, retrieves, or automatically separates the last 20 candlesticks, excluding the current one?
Thanks in advance
Re: Already Converted TradingView Indicators to MT4 Indicators
623Starter02 wrote: Wed May 21, 2025 12:39 am Hi Mr.Tools
Please help.
Do you have an indicator that detects, retrieves, or automatically separates the last 20 candlesticks, excluding the current one?
Thanks in advance
Hello, don't have one.
Re: Already Converted TradingView Indicators to MT4 Indicators
624Hello and regards to everyone,
This LuxAlgo indicator is very useful — especially the way it automatically identifies peak points and draws support and resistance levels based on volume peaks and valleys.
I would really appreciate it if this indicator could be converted to MQL4 so that it can be used in MetaTrader 4.
Also, it would be great if the indicator could be anchored manually, similar to Anchored Volume Profile — allowing the user to move and resize the range between lines, rather than relying on a fixed number of bars.
If you need any additional information to help with the conversion, I am more than happy to provide it.
Thank you very much in advance for making this available for MT4!
https://www.luxalgo.com/library/indicat ... detection/
Main code:
This LuxAlgo indicator is very useful — especially the way it automatically identifies peak points and draws support and resistance levels based on volume peaks and valleys.
I would really appreciate it if this indicator could be converted to MQL4 so that it can be used in MetaTrader 4.
Also, it would be great if the indicator could be anchored manually, similar to Anchored Volume Profile — allowing the user to move and resize the range between lines, rather than relying on a fixed number of bars.
If you need any additional information to help with the conversion, I am more than happy to provide it.
Thank you very much in advance for making this available for MT4!
https://www.luxalgo.com/library/indicat ... detection/
Main code:
Code: Select all
// 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=5
indicator("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_peaksShow
vn_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_troughsShow
vn_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) / 100
vn_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 - 1
vp_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_index
type barData
float [] barHigh
float [] barLow
float [] barVolume
bool [] barPolarity
int [] barCount
type volumeData
float [] totalVolume
float [] bullishVolume
float [] bearishVolume
int [] endProfileIndex
bool [] peakVolume
bool [] troughVolume
type 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<BAR> (1, BAR.new())
var barData barDataArray = barData.new(
array.new <float> (na),
array.new <float> (na),
array.new <float> (na),
array.new <bool> (na),
array.new <int> (na)
)
volumeData volumeDataArray = volumeData.new(
array.new <float> (vp_profileNumberOfRows, 0.),
array.new <float> (vp_profileNumberOfRows, 0.),
array.new <float> (vp_profileNumberOfRows, 0.),
array.new <int> (vp_profileNumberOfRows, 0 ),
array.new <bool> (vp_profileNumberOfRows, 0.),
array.new <bool> (vp_profileNumberOfRows, 0.)
)
var volumeProfile VP = volumeProfile.new(
array.new<box> (na),
array.new<chart.point> (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 = 60
if _depth == 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 _depth == 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'
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<BAR> (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 < last_bar_index and ltfBarData.size() > 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.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())
barIndex = vp_profileLength
numberOfBars = 0
arraySize = barDataArray.barVolume.size()
for arrayIndex = 0 to arraySize - 1
levelHigh = barDataArray.barHigh.get(arrayIndex)
levelLow = barDataArray.barLow.get(arrayIndex)
levelVolume = barDataArray.barVolume.get(arrayIndex)
// Shoutout to @tkarolak for contributing to the code's optimization! Much appreciated.
int startSlotIndex = math.max(math.floor((levelLow - lowestPrice) / priceStep), 0)
int endSlotIndex = math.min(math.floor((levelHigh - lowestPrice) / priceStep), vp_profileNumberOfRows - 1)
for priceLevelIndex = startSlotIndex to endSlotIndex
float priceLevel = lowestPrice + priceLevelIndex * priceStep
volumeProportion = switch
levelLow >= priceLevel and levelHigh > priceLevel + priceStep => (priceLevel + priceStep - levelLow) / (levelHigh - levelLow)
levelHigh <= priceLevel + priceStep and levelLow < priceLevel => (levelHigh - priceLevel) / (levelHigh - levelLow)
levelLow >= priceLevel and levelHigh <= priceLevel + priceStep => 1
=> priceStep / (levelHigh - levelLow)
volumeDataArray.totalVolume.set(priceLevelIndex, volumeDataArray.totalVolume.get(priceLevelIndex) + levelVolume * volumeProportion)
if barDataArray.barPolarity.get(arrayIndex)
volumeDataArray.bullishVolume.set(priceLevelIndex, volumeDataArray.bullishVolume.get(priceLevelIndex) + levelVolume * volumeProportion)
// priceLevelIndex = 0
// for priceLevel = lowestPrice to highestPrice - priceStep by priceStep
//
// if levelHigh >= priceLevel and levelLow < priceLevel + priceStep
//
// volumeProportion = if levelLow >= priceLevel and levelHigh > priceLevel + priceStep
// (priceLevel + priceStep - levelLow) / (levelHigh - levelLow)
// else if levelHigh <= priceLevel + priceStep and levelLow < priceLevel
// (levelHigh - priceLevel) / (levelHigh - levelLow)
// else if levelLow >= priceLevel and levelHigh <= priceLevel + priceStep
// 1
// else
// priceStep / (levelHigh - levelLow)
//
// volumeDataArray.totalVolume.set(priceLevelIndex, volumeDataArray.totalVolume.get(priceLevelIndex) + levelVolume * volumeProportion)
//
// if barDataArray.barPolarity.get(arrayIndex)
// volumeDataArray.bullishVolume.set(priceLevelIndex, volumeDataArray.bullishVolume.get(priceLevelIndex) + levelVolume * volumeProportion)
// priceLevelIndex += 1
if vp_pocShow == 'Developing'
if arrayIndex == barDataArray.barCount.get(vp_profileLength - barIndex)
VP.pocPoints.push(chart.point.from_index(bar.index[barIndex], math.avg(bar.high[barIndex], bar.low[barIndex])))
VP.pocPoints.push(chart.point.from_index(bar.index[barIndex] + 1, lowestPrice + (volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.max()) + .5) * priceStep))
numberOfBars += barDataArray.barCount.get(vp_profileLength - barIndex)
barIndex -= 1
else if arrayIndex == (numberOfBars + barDataArray.barCount.get(vp_profileLength - barIndex)) and numberOfBars != 0
VP.pocPoints.push(chart.point.from_index(bar.index[barIndex] + 1, lowestPrice + (volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.max()) + .5) * priceStep))
numberOfBars += barDataArray.barCount.get(vp_profileLength - barIndex)
barIndex -= 1
else if barIndex == 0
VP.pocPoints.push(chart.point.from_index(bar.index[barIndex] + 1, lowestPrice + (volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.max()) + .5) * priceStep))
numberOfBars += barDataArray.barCount.get(vp_profileLength - barIndex)
VP.pocPolyline := polyline.new(VP.pocPoints, false, false, xloc.bar_index, vp_pocColor, color(na), line.style_solid, vp_pocWidth)
for volumeIndex = 0 to vp_profileNumberOfRows - 1
bearishVolume = 2 * volumeDataArray.bullishVolume.get(volumeIndex) - volumeDataArray.totalVolume.get(volumeIndex)
volumeDataArray.bearishVolume.set(volumeIndex, volumeDataArray.bearishVolume.get(volumeIndex) + bearishVolume * (bearishVolume > 0 ? 1 : -1) )
VP.pocLevel := volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.max())
totalTradedVolume = volumeDataArray.totalVolume.sum() * vp_valueAreaThreshold
valueAreaVolume = VP.pocLevel != -1 ? volumeDataArray.totalVolume.get(VP.pocLevel) : 0
VP.vahLevel := VP.pocLevel
VP.valLevel := VP.pocLevel
while valueAreaVolume < totalTradedVolume
if VP.valLevel == 0 and VP.vahLevel == vp_profileNumberOfRows - 1
break
volumeAbovePOC = 0.
if VP.vahLevel < vp_profileNumberOfRows - 1
volumeAbovePOC := volumeDataArray.totalVolume.get(VP.vahLevel + 1)
volumeBelowPOC = 0.
if VP.valLevel > 0
volumeBelowPOC := volumeDataArray.totalVolume.get(VP.valLevel - 1)
if volumeBelowPOC == 0 and volumeAbovePOC == 0
break
if volumeAbovePOC >= volumeBelowPOC
valueAreaVolume += volumeAbovePOC
VP.vahLevel += 1
else
valueAreaVolume += volumeBelowPOC
VP.valLevel -= 1
vahPrice = lowestPrice + (VP.vahLevel + 1.) * priceStep
pocPrice = lowestPrice + (VP.pocLevel + .5) * priceStep
valPrice = lowestPrice + (VP.valLevel + .0) * priceStep
profilePlottingLength = vp_profileLength > 360 ? 360 : vp_profileLength
profileWidth = profilePlottingLength * vp_profileWidth
profileHorizontalOffset = int(profileWidth + vp_profileHorizontalOffset)
if vp_profileShow and profilePlacementRight and vp_pocShow == 'Developing'
renderLine(last_bar_index, pocPrice, profileHorizontalOffset + int(last_bar_index - profileWidth + 1), pocPrice, xloc.bar_index, extend.none, vp_pocColor, line.style_solid, vp_pocWidth)
if vp_vahShow
renderLine(VP.startIndex, vahPrice,
profilePlacementRight ? (vp_profileShow ? profileHorizontalOffset : 0) + last_bar_index : last_bar_index,
vahPrice, xloc.bar_index, extend.none, vp_vahColor, line.style_solid, 1)
if vp_pocShow == 'Regular'
renderLine(VP.startIndex, pocPrice, profilePlacementRight ? vp_profileShow ? profileHorizontalOffset + int(last_bar_index - profileWidth + 1) : last_bar_index : last_bar_index, pocPrice, xloc.bar_index, extend.none, vp_pocColor, line.style_solid, vp_pocWidth)
if vp_valShow
renderLine(VP.startIndex, valPrice,
profilePlacementRight ? (vp_profileShow ? profileHorizontalOffset : 0) + last_bar_index : last_bar_index,
valPrice, xloc.bar_index, extend.none, vp_valColor, line.style_solid, 1)
if vp_valueAreaBackground
VP.boxes.push(box.new(VP.startIndex, valPrice, last_bar_index, vahPrice, vp_valueAreaBackgroundColor, 1, line.style_dotted, bgcolor = vp_valueAreaBackgroundColor))
if vp_profileBackground
VP.boxes.push(box.new(VP.startIndex, lowestPrice, last_bar_index, highestPrice, vp_profileBackgroundColor, 1, line.style_dotted, bgcolor = vp_profileBackgroundColor))
if vp_profileLevels != 'None' and VP.pocLevel != -1
renderLabel(profilePlacementRight ? (vp_profileShow ? profileHorizontalOffset : 0) + last_bar_index : vp_profileShow ? VP.startIndex : last_bar_index,
highestPrice, str.tostring(highestPrice, format.mintick), color.new(chart.fg_color, 89), label.style_label_down, chart.fg_color, profileLevesSize, 'Profile High')
renderLabel(profilePlacementRight ? (vp_profileShow ? profileHorizontalOffset : 0) + last_bar_index : last_bar_index,
vahPrice, str.tostring(vahPrice, format.mintick), color.new(vp_vahColor, 89), label.style_label_left, vp_vahColor, profileLevesSize, 'Value Area High')
renderLabel(profilePlacementRight ? (vp_profileShow ? profileHorizontalOffset : 0) + last_bar_index : last_bar_index,
pocPrice, str.tostring(pocPrice, format.mintick), color.new(vp_pocColor, 89), label.style_label_left, vp_pocColor, profileLevesSize, 'Point of Control')
renderLabel(profilePlacementRight ? (vp_profileShow ? profileHorizontalOffset : 0) + last_bar_index : last_bar_index,
valPrice, str.tostring(valPrice, format.mintick), color.new(vp_valColor, 89), label.style_label_left, vp_valColor, profileLevesSize, 'Value Area Low')
renderLabel(profilePlacementRight ? (vp_profileShow ? profileHorizontalOffset : 0) + last_bar_index : vp_profileShow ? VP.startIndex : last_bar_index,
lowestPrice, str.tostring(lowestPrice, format.mintick), color.new(chart.fg_color, 89), label.style_label_up, chart.fg_color, profileLevesSize, 'Profile Low')
for volumeNodeLevel = 0 to vp_profileNumberOfRows - 1
if vp_profileShow
if vp_profileGradientColors == 'Gradient Colors'
vp_valueAreaUpColor := color.from_gradient(volumeDataArray.totalVolume.get(volumeNodeLevel) / volumeDataArray.totalVolume.max(), 0, 1, color.new(vp_valueAreaUpColor , 95), color.new(vp_valueAreaUpColor , 0))
vp_valueAreaDwonColor := color.from_gradient(volumeDataArray.totalVolume.get(volumeNodeLevel) / volumeDataArray.totalVolume.max(), 0, 1, color.new(vp_valueAreaDwonColor , 95), color.new(vp_valueAreaDwonColor , 0))
vp_profileUpVolumeColor := color.from_gradient(volumeDataArray.totalVolume.get(volumeNodeLevel) / volumeDataArray.totalVolume.max(), 0, 1, color.new(vp_profileUpVolumeColor , 95), color.new(vp_profileUpVolumeColor , 0))
vp_profileDownVolumeColor := color.from_gradient(volumeDataArray.totalVolume.get(volumeNodeLevel) / volumeDataArray.totalVolume.max(), 0, 1, color.new(vp_profileDownVolumeColor, 95), color.new(vp_profileDownVolumeColor, 0))
startProfileIndex = profilePlacementRight ?
profileHorizontalOffset + int(last_bar_index - volumeDataArray.bullishVolume.get(volumeNodeLevel) / volumeDataArray.totalVolume.max() * profileWidth) :
VP.startIndex
endProfileIndex = profilePlacementRight ?
profileHorizontalOffset + last_bar_index :
int(startProfileIndex + volumeDataArray.bullishVolume.get(volumeNodeLevel) / volumeDataArray.totalVolume.max() * profileWidth)
VP.boxes.push(box.new(startProfileIndex, lowestPrice + (volumeNodeLevel + .1) * priceStep, endProfileIndex, lowestPrice + (volumeNodeLevel + .9) * priceStep,
color(na), bgcolor = volumeNodeLevel >= VP.valLevel and volumeNodeLevel <= VP.vahLevel ? vp_valueAreaUpColor : vp_profileUpVolumeColor))
startProfileIndex := profilePlacementRight ? startProfileIndex : endProfileIndex
endProfileIndex := profilePlacementRight ?
startProfileIndex - int( (volumeDataArray.totalVolume.get(volumeNodeLevel) - volumeDataArray.bullishVolume.get(volumeNodeLevel)) / volumeDataArray.totalVolume.max() * profileWidth) :
startProfileIndex + int( (volumeDataArray.totalVolume.get(volumeNodeLevel) - volumeDataArray.bullishVolume.get(volumeNodeLevel)) / volumeDataArray.totalVolume.max() * profileWidth)
VP.boxes.push(box.new(startProfileIndex, lowestPrice + (volumeNodeLevel + .1) * priceStep, endProfileIndex, lowestPrice + (volumeNodeLevel + .9) * priceStep,
color(na), bgcolor = volumeNodeLevel >= VP.valLevel and volumeNodeLevel <= VP.vahLevel ? vp_valueAreaDwonColor : vp_profileDownVolumeColor))
volumeDataArray.endProfileIndex.set(volumeNodeLevel, endProfileIndex)
if vn_peaksShow != 'None' or vn_troughsShow != 'None'
var int startVolumeNodeIndex = na, var int endVolumeNodeIndex = na
var bool peakUpperNth = na, var bool peakLowerNth = na
peaksNumberOfNodes = int(vp_profileNumberOfRows * vn_peaksNumberOfNodes)
tempPeakTotalVolume = volumeDataArray.totalVolume.copy()
for index = 1 to peaksNumberOfNodes
tempPeakTotalVolume.unshift(0.)
tempPeakTotalVolume.push(0.)
for volumeNodeLevel = 0 to vp_profileNumberOfRows - 1 + 2 * peaksNumberOfNodes
if vn_peaksShow != 'None' and volumeNodeLevel >= 2 * peaksNumberOfNodes
for currentVolumeNode = volumeNodeLevel - 2 * peaksNumberOfNodes to volumeNodeLevel - peaksNumberOfNodes - 1
if tempPeakTotalVolume.get(volumeNodeLevel - peaksNumberOfNodes) <= tempPeakTotalVolume.get(currentVolumeNode)
peakUpperNth := false
break
else
peakUpperNth := true
for currentVolumeNode = volumeNodeLevel - peaksNumberOfNodes + 1 to volumeNodeLevel
if tempPeakTotalVolume.get(volumeNodeLevel - peaksNumberOfNodes) <= tempPeakTotalVolume.get(currentVolumeNode)
peakLowerNth := false
break
else
peakLowerNth := true
if peakUpperNth and peakLowerNth and tempPeakTotalVolume.get(volumeNodeLevel - peaksNumberOfNodes) / tempPeakTotalVolume.max() > vn_VolumeNodeThreshold
startVolumeNodeIndex := vp_profileShow ? profilePlacementRight ?
VP.startIndex :
volumeDataArray.endProfileIndex.get(volumeNodeLevel - 2 * peaksNumberOfNodes) : //VP.startIndex + int(volumeDataArray.totalVolume.get(volumeNodeLevel - vn_peaksNumberOfNodes) / volumeDataArray.totalVolume.max() * profileWidth) :
VP.startIndex
endVolumeNodeIndex := vp_profileShow ? profilePlacementRight ?
volumeDataArray.endProfileIndex.get(volumeNodeLevel - 2 * peaksNumberOfNodes) : //profileHorizontalOffset + int(last_bar_index - volumeDataArray.totalVolume.get(volumeNodeLevel - vn_peaksNumberOfNodes) / volumeDataArray.totalVolume.max() * profileWidth) :
last_bar_index :
last_bar_index
vn_peakVolumeColor := vn_peaksShow == 'Peaks' ? vn_peakVolumeColor : color.from_gradient(tempPeakTotalVolume.get(volumeNodeLevel - peaksNumberOfNodes) / tempPeakTotalVolume.max(), 0, 1, color.new(vn_peakVolumeColor, 95), color.new(vn_peakVolumeColor, 65))
VP.boxes.push(box.new(startVolumeNodeIndex, lowestPrice + (volumeNodeLevel - 2 * peaksNumberOfNodes + .1) * priceStep, endVolumeNodeIndex, lowestPrice + (volumeNodeLevel - 2 * peaksNumberOfNodes + .9) * priceStep,
color(na), bgcolor = vn_peakVolumeColor))
if vn_peaksShow == 'Clusters'
for currentVolumeNode = volumeNodeLevel - 2 * peaksNumberOfNodes to volumeNodeLevel
if currentVolumeNode >= peaksNumberOfNodes and currentVolumeNode <= vp_profileNumberOfRows - 1 + peaksNumberOfNodes
if not volumeDataArray.peakVolume.get(currentVolumeNode - peaksNumberOfNodes)
startVolumeNodeIndex := vp_profileShow ? profilePlacementRight ?
VP.startIndex :
volumeDataArray.endProfileIndex.get(currentVolumeNode - peaksNumberOfNodes) : //VP.startIndex + int(volumeDataArray.totalVolume.get(currentVolumeNode) / volumeDataArray.totalVolume.max() * profileWidth) :
VP.startIndex
endVolumeNodeIndex := vp_profileShow ? profilePlacementRight ?
volumeDataArray.endProfileIndex.get(currentVolumeNode - peaksNumberOfNodes) : //profileHorizontalOffset + int(last_bar_index - volumeDataArray.totalVolume.get(currentVolumeNode) / volumeDataArray.totalVolume.max() * profileWidth) :
last_bar_index :
last_bar_index
VP.boxes.push(box.new(startVolumeNodeIndex, lowestPrice + (currentVolumeNode - peaksNumberOfNodes + .0) * priceStep, endVolumeNodeIndex, lowestPrice + (currentVolumeNode - peaksNumberOfNodes + 1.) * priceStep,
color(na), bgcolor = vn_peakVolumeColor))
volumeDataArray.peakVolume.set(currentVolumeNode - peaksNumberOfNodes, true)
tempPeakTotalVolume.clear()
var bool troughUpperNth = na, var bool troughLowerNth = na
troughsNumberOfNodes = int(vp_profileNumberOfRows * vn_troughsNumberOfNodes)
tempTroughTotalVolume = volumeDataArray.totalVolume.copy()
for index = 1 to troughsNumberOfNodes
tempTroughTotalVolume.unshift(volumeDataArray.totalVolume.max())
tempTroughTotalVolume.push(volumeDataArray.totalVolume.max())
for volumeNodeLevel = 0 to vp_profileNumberOfRows - 1 + 2 * troughsNumberOfNodes
if vn_troughsShow != 'None' and volumeNodeLevel >= 2 * troughsNumberOfNodes
for currentVolumeNode = volumeNodeLevel - 2 * troughsNumberOfNodes to volumeNodeLevel - troughsNumberOfNodes - 1
if tempTroughTotalVolume.get(volumeNodeLevel - troughsNumberOfNodes) >= tempTroughTotalVolume.get(currentVolumeNode)
troughUpperNth := false
break
else
troughUpperNth := true
for currentVolumeNode = volumeNodeLevel - troughsNumberOfNodes + 1 to volumeNodeLevel
if tempTroughTotalVolume.get(volumeNodeLevel - troughsNumberOfNodes) >= tempTroughTotalVolume.get(currentVolumeNode)
troughLowerNth := false
break
else
troughLowerNth := true
if troughUpperNth and troughLowerNth and tempTroughTotalVolume.get(volumeNodeLevel - troughsNumberOfNodes) / tempTroughTotalVolume.max() > vn_VolumeNodeThreshold
startVolumeNodeIndex := vp_profileShow ? profilePlacementRight ?
VP.startIndex :
volumeDataArray.endProfileIndex.get(volumeNodeLevel - 2 * troughsNumberOfNodes) : //VP.startIndex + int(volumeDataArray.totalVolume.get(volumeNodeLevel - vn_troughsNumberOfNodes) / volumeDataArray.totalVolume.max() * profileWidth) :
VP.startIndex
endVolumeNodeIndex := vp_profileShow ? profilePlacementRight ?
volumeDataArray.endProfileIndex.get(volumeNodeLevel - 2 * troughsNumberOfNodes) : //profileHorizontalOffset + int(last_bar_index - volumeDataArray.totalVolume.get(volumeNodeLevel - vn_troughsNumberOfNodes) / volumeDataArray.totalVolume.max() * profileWidth) :
last_bar_index :
last_bar_index
vn_troughVolumeColor := vn_troughsShow == 'Troughs' ? vn_troughVolumeColor : color.from_gradient(tempTroughTotalVolume.get(volumeNodeLevel - troughsNumberOfNodes) / tempTroughTotalVolume.max(), 0, 1, color.new(vn_troughVolumeColor, 95), color.new(vn_troughVolumeColor, 31))
VP.boxes.push(box.new(startVolumeNodeIndex, lowestPrice + (volumeNodeLevel - 2 * troughsNumberOfNodes + .1) * priceStep, endVolumeNodeIndex, lowestPrice + (volumeNodeLevel - 2 * troughsNumberOfNodes + .9) * priceStep,
color(na), bgcolor = vn_troughVolumeColor))
if vn_troughsShow == 'Clusters'
for currentVolumeNode = volumeNodeLevel - 2 * troughsNumberOfNodes to volumeNodeLevel
if currentVolumeNode >= troughsNumberOfNodes and currentVolumeNode <= vp_profileNumberOfRows - 1 + troughsNumberOfNodes
if not volumeDataArray.troughVolume.get(currentVolumeNode - troughsNumberOfNodes)
startVolumeNodeIndex := vp_profileShow ? profilePlacementRight ?
VP.startIndex :
volumeDataArray.endProfileIndex.get(currentVolumeNode - troughsNumberOfNodes) : //VP.startIndex + int(volumeDataArray.totalVolume.get(currentVolumeNode) / volumeDataArray.totalVolume.max() * profileWidth) :
VP.startIndex
endVolumeNodeIndex := vp_profileShow ? profilePlacementRight ?
volumeDataArray.endProfileIndex.get(currentVolumeNode - troughsNumberOfNodes) : //profileHorizontalOffset + int(last_bar_index - volumeDataArray.totalVolume.get(currentVolumeNode) / volumeDataArray.totalVolume.max() * profileWidth) :
last_bar_index :
last_bar_index
VP.boxes.push(box.new(startVolumeNodeIndex, lowestPrice + (currentVolumeNode - troughsNumberOfNodes + .0) * priceStep, endVolumeNodeIndex, lowestPrice + (currentVolumeNode - troughsNumberOfNodes + 1.) * priceStep,
color(na), bgcolor = vn_troughVolumeColor))
volumeDataArray.troughVolume.set(currentVolumeNode - troughsNumberOfNodes, true)
tempTroughTotalVolume.clear()
if vn_highestNVolumeNodes > 0
for highestNode = 0 to vn_highestNVolumeNodes - 1
startVolumeNodeIndex = vp_profileShow ? profilePlacementRight ?
VP.startIndex :
volumeDataArray.endProfileIndex.get(volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.max(highestNode))) : //VP.startIndex + int(volumeDataArray.totalVolume.get(volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.max(highestNode))) / volumeDataArray.totalVolume.max() * profileWidth) :
VP.startIndex
endVolumeNodeIndex = vp_profileShow ? profilePlacementRight ?
volumeDataArray.endProfileIndex.get(volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.max(highestNode))) : //profileHorizontalOffset + int(last_bar_index - volumeDataArray.totalVolume.get(volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.max(highestNode))) / volumeDataArray.totalVolume.max() * profileWidth) :
last_bar_index :
last_bar_index
VP.boxes.push(box.new(startVolumeNodeIndex, lowestPrice + (volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.max(highestNode)) + .1) * priceStep, endVolumeNodeIndex, lowestPrice + (volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.max(highestNode)) + .9) * priceStep, color(na), bgcolor = vn_highestVolumeColor))
if vn_lowestNVolumeNodes > 0
lowestNVolumeNodeCount = 0
lowestNVolumeNodeIndex = 0//volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.min())
lowestNVolumeNodeValue = 0.
while lowestNVolumeNodeCount < vn_lowestNVolumeNodes
if lowestNVolumeNodeIndex == vp_profileNumberOfRows
break
if volumeDataArray.totalVolume.min(lowestNVolumeNodeIndex) != lowestNVolumeNodeValue
lowestNVolumeNodeValue := volumeDataArray.totalVolume.min(lowestNVolumeNodeIndex)
startVolumeNodeIndex = vp_profileShow ? profilePlacementRight ?
VP.startIndex :
volumeDataArray.endProfileIndex.get(volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.min(lowestNVolumeNodeIndex))) : //VP.startIndex + int(volumeDataArray.totalVolume.get(volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.min(lowestNVolumeNodeIndex))) / volumeDataArray.totalVolume.max() * profileWidth) :
VP.startIndex
endVolumeNodeIndex = vp_profileShow ? profilePlacementRight ?
volumeDataArray.endProfileIndex.get(volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.min(lowestNVolumeNodeIndex))) : //profileHorizontalOffset + int(last_bar_index - volumeDataArray.totalVolume.get(volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.min(lowestNVolumeNodeIndex))) / volumeDataArray.totalVolume.max() * profileWidth) :
last_bar_index :
last_bar_index
VP.boxes.push(box.new(startVolumeNodeIndex, lowestPrice + (volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.min(lowestNVolumeNodeIndex)) + .1) * priceStep, endVolumeNodeIndex, lowestPrice + (volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.min(lowestNVolumeNodeIndex)) + .9) * priceStep, color(na), bgcolor = vn_lowestVolumeColor))
lowestNVolumeNodeCount += 1
lowestNVolumeNodeIndex += 1
log.info("yaz_kizim {0} {1}", VP.boxes.size(), volumeDataArray.totalVolume.size() )
//---------------------------------------------------------------------------------------------------------------------}
- These users thanked the author iardavan for the post:
- RodrigoRT7
When your strategy is based on hope, it's a HOPELESS strategy!
Re: Already Converted TradingView Indicators to MT4 Indicators
625Very interesting to mark points of interest of the market profileiardavan wrote: Wed Jun 11, 2025 10:34 am Hello and regards to everyone,
This LuxAlgo indicator is very useful — especially the way it automatically identifies peak points and draws support and resistance levels based on volume peaks and valleys.
I would really appreciate it if this indicator could be converted to MQL4 so that it can be used in MetaTrader 4.
Also, it would be great if the indicator could be anchored manually, similar to Anchored Volume Profile — allowing the user to move and resize the range between lines, rather than relying on a fixed number of bars.
If you need any additional information to help with the conversion, I am more than happy to provide it.
Thank you very much in advance for making this available for MT4!
https://www.luxalgo.com/library/indicat ... detection/
Main code:
Code: Select all
// 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=5 indicator("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_peaksShow vn_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_troughsShow vn_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) / 100 vn_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 - 1 vp_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_index type barData float [] barHigh float [] barLow float [] barVolume bool [] barPolarity int [] barCount type volumeData float [] totalVolume float [] bullishVolume float [] bearishVolume int [] endProfileIndex bool [] peakVolume bool [] troughVolume type 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<BAR> (1, BAR.new()) var barData barDataArray = barData.new( array.new <float> (na), array.new <float> (na), array.new <float> (na), array.new <bool> (na), array.new <int> (na) ) volumeData volumeDataArray = volumeData.new( array.new <float> (vp_profileNumberOfRows, 0.), array.new <float> (vp_profileNumberOfRows, 0.), array.new <float> (vp_profileNumberOfRows, 0.), array.new <int> (vp_profileNumberOfRows, 0 ), array.new <bool> (vp_profileNumberOfRows, 0.), array.new <bool> (vp_profileNumberOfRows, 0.) ) var volumeProfile VP = volumeProfile.new( array.new<box> (na), array.new<chart.point> (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 = 60 if _depth == 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 _depth == 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' 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<BAR> (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 < last_bar_index and ltfBarData.size() > 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.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()) barIndex = vp_profileLength numberOfBars = 0 arraySize = barDataArray.barVolume.size() for arrayIndex = 0 to arraySize - 1 levelHigh = barDataArray.barHigh.get(arrayIndex) levelLow = barDataArray.barLow.get(arrayIndex) levelVolume = barDataArray.barVolume.get(arrayIndex) // Shoutout to @tkarolak for contributing to the code's optimization! Much appreciated. int startSlotIndex = math.max(math.floor((levelLow - lowestPrice) / priceStep), 0) int endSlotIndex = math.min(math.floor((levelHigh - lowestPrice) / priceStep), vp_profileNumberOfRows - 1) for priceLevelIndex = startSlotIndex to endSlotIndex float priceLevel = lowestPrice + priceLevelIndex * priceStep volumeProportion = switch levelLow >= priceLevel and levelHigh > priceLevel + priceStep => (priceLevel + priceStep - levelLow) / (levelHigh - levelLow) levelHigh <= priceLevel + priceStep and levelLow < priceLevel => (levelHigh - priceLevel) / (levelHigh - levelLow) levelLow >= priceLevel and levelHigh <= priceLevel + priceStep => 1 => priceStep / (levelHigh - levelLow) volumeDataArray.totalVolume.set(priceLevelIndex, volumeDataArray.totalVolume.get(priceLevelIndex) + levelVolume * volumeProportion) if barDataArray.barPolarity.get(arrayIndex) volumeDataArray.bullishVolume.set(priceLevelIndex, volumeDataArray.bullishVolume.get(priceLevelIndex) + levelVolume * volumeProportion) // priceLevelIndex = 0 // for priceLevel = lowestPrice to highestPrice - priceStep by priceStep // // if levelHigh >= priceLevel and levelLow < priceLevel + priceStep // // volumeProportion = if levelLow >= priceLevel and levelHigh > priceLevel + priceStep // (priceLevel + priceStep - levelLow) / (levelHigh - levelLow) // else if levelHigh <= priceLevel + priceStep and levelLow < priceLevel // (levelHigh - priceLevel) / (levelHigh - levelLow) // else if levelLow >= priceLevel and levelHigh <= priceLevel + priceStep // 1 // else // priceStep / (levelHigh - levelLow) // // volumeDataArray.totalVolume.set(priceLevelIndex, volumeDataArray.totalVolume.get(priceLevelIndex) + levelVolume * volumeProportion) // // if barDataArray.barPolarity.get(arrayIndex) // volumeDataArray.bullishVolume.set(priceLevelIndex, volumeDataArray.bullishVolume.get(priceLevelIndex) + levelVolume * volumeProportion) // priceLevelIndex += 1 if vp_pocShow == 'Developing' if arrayIndex == barDataArray.barCount.get(vp_profileLength - barIndex) VP.pocPoints.push(chart.point.from_index(bar.index[barIndex], math.avg(bar.high[barIndex], bar.low[barIndex]))) VP.pocPoints.push(chart.point.from_index(bar.index[barIndex] + 1, lowestPrice + (volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.max()) + .5) * priceStep)) numberOfBars += barDataArray.barCount.get(vp_profileLength - barIndex) barIndex -= 1 else if arrayIndex == (numberOfBars + barDataArray.barCount.get(vp_profileLength - barIndex)) and numberOfBars != 0 VP.pocPoints.push(chart.point.from_index(bar.index[barIndex] + 1, lowestPrice + (volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.max()) + .5) * priceStep)) numberOfBars += barDataArray.barCount.get(vp_profileLength - barIndex) barIndex -= 1 else if barIndex == 0 VP.pocPoints.push(chart.point.from_index(bar.index[barIndex] + 1, lowestPrice + (volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.max()) + .5) * priceStep)) numberOfBars += barDataArray.barCount.get(vp_profileLength - barIndex) VP.pocPolyline := polyline.new(VP.pocPoints, false, false, xloc.bar_index, vp_pocColor, color(na), line.style_solid, vp_pocWidth) for volumeIndex = 0 to vp_profileNumberOfRows - 1 bearishVolume = 2 * volumeDataArray.bullishVolume.get(volumeIndex) - volumeDataArray.totalVolume.get(volumeIndex) volumeDataArray.bearishVolume.set(volumeIndex, volumeDataArray.bearishVolume.get(volumeIndex) + bearishVolume * (bearishVolume > 0 ? 1 : -1) ) VP.pocLevel := volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.max()) totalTradedVolume = volumeDataArray.totalVolume.sum() * vp_valueAreaThreshold valueAreaVolume = VP.pocLevel != -1 ? volumeDataArray.totalVolume.get(VP.pocLevel) : 0 VP.vahLevel := VP.pocLevel VP.valLevel := VP.pocLevel while valueAreaVolume < totalTradedVolume if VP.valLevel == 0 and VP.vahLevel == vp_profileNumberOfRows - 1 break volumeAbovePOC = 0. if VP.vahLevel < vp_profileNumberOfRows - 1 volumeAbovePOC := volumeDataArray.totalVolume.get(VP.vahLevel + 1) volumeBelowPOC = 0. if VP.valLevel > 0 volumeBelowPOC := volumeDataArray.totalVolume.get(VP.valLevel - 1) if volumeBelowPOC == 0 and volumeAbovePOC == 0 break if volumeAbovePOC >= volumeBelowPOC valueAreaVolume += volumeAbovePOC VP.vahLevel += 1 else valueAreaVolume += volumeBelowPOC VP.valLevel -= 1 vahPrice = lowestPrice + (VP.vahLevel + 1.) * priceStep pocPrice = lowestPrice + (VP.pocLevel + .5) * priceStep valPrice = lowestPrice + (VP.valLevel + .0) * priceStep profilePlottingLength = vp_profileLength > 360 ? 360 : vp_profileLength profileWidth = profilePlottingLength * vp_profileWidth profileHorizontalOffset = int(profileWidth + vp_profileHorizontalOffset) if vp_profileShow and profilePlacementRight and vp_pocShow == 'Developing' renderLine(last_bar_index, pocPrice, profileHorizontalOffset + int(last_bar_index - profileWidth + 1), pocPrice, xloc.bar_index, extend.none, vp_pocColor, line.style_solid, vp_pocWidth) if vp_vahShow renderLine(VP.startIndex, vahPrice, profilePlacementRight ? (vp_profileShow ? profileHorizontalOffset : 0) + last_bar_index : last_bar_index, vahPrice, xloc.bar_index, extend.none, vp_vahColor, line.style_solid, 1) if vp_pocShow == 'Regular' renderLine(VP.startIndex, pocPrice, profilePlacementRight ? vp_profileShow ? profileHorizontalOffset + int(last_bar_index - profileWidth + 1) : last_bar_index : last_bar_index, pocPrice, xloc.bar_index, extend.none, vp_pocColor, line.style_solid, vp_pocWidth) if vp_valShow renderLine(VP.startIndex, valPrice, profilePlacementRight ? (vp_profileShow ? profileHorizontalOffset : 0) + last_bar_index : last_bar_index, valPrice, xloc.bar_index, extend.none, vp_valColor, line.style_solid, 1) if vp_valueAreaBackground VP.boxes.push(box.new(VP.startIndex, valPrice, last_bar_index, vahPrice, vp_valueAreaBackgroundColor, 1, line.style_dotted, bgcolor = vp_valueAreaBackgroundColor)) if vp_profileBackground VP.boxes.push(box.new(VP.startIndex, lowestPrice, last_bar_index, highestPrice, vp_profileBackgroundColor, 1, line.style_dotted, bgcolor = vp_profileBackgroundColor)) if vp_profileLevels != 'None' and VP.pocLevel != -1 renderLabel(profilePlacementRight ? (vp_profileShow ? profileHorizontalOffset : 0) + last_bar_index : vp_profileShow ? VP.startIndex : last_bar_index, highestPrice, str.tostring(highestPrice, format.mintick), color.new(chart.fg_color, 89), label.style_label_down, chart.fg_color, profileLevesSize, 'Profile High') renderLabel(profilePlacementRight ? (vp_profileShow ? profileHorizontalOffset : 0) + last_bar_index : last_bar_index, vahPrice, str.tostring(vahPrice, format.mintick), color.new(vp_vahColor, 89), label.style_label_left, vp_vahColor, profileLevesSize, 'Value Area High') renderLabel(profilePlacementRight ? (vp_profileShow ? profileHorizontalOffset : 0) + last_bar_index : last_bar_index, pocPrice, str.tostring(pocPrice, format.mintick), color.new(vp_pocColor, 89), label.style_label_left, vp_pocColor, profileLevesSize, 'Point of Control') renderLabel(profilePlacementRight ? (vp_profileShow ? profileHorizontalOffset : 0) + last_bar_index : last_bar_index, valPrice, str.tostring(valPrice, format.mintick), color.new(vp_valColor, 89), label.style_label_left, vp_valColor, profileLevesSize, 'Value Area Low') renderLabel(profilePlacementRight ? (vp_profileShow ? profileHorizontalOffset : 0) + last_bar_index : vp_profileShow ? VP.startIndex : last_bar_index, lowestPrice, str.tostring(lowestPrice, format.mintick), color.new(chart.fg_color, 89), label.style_label_up, chart.fg_color, profileLevesSize, 'Profile Low') for volumeNodeLevel = 0 to vp_profileNumberOfRows - 1 if vp_profileShow if vp_profileGradientColors == 'Gradient Colors' vp_valueAreaUpColor := color.from_gradient(volumeDataArray.totalVolume.get(volumeNodeLevel) / volumeDataArray.totalVolume.max(), 0, 1, color.new(vp_valueAreaUpColor , 95), color.new(vp_valueAreaUpColor , 0)) vp_valueAreaDwonColor := color.from_gradient(volumeDataArray.totalVolume.get(volumeNodeLevel) / volumeDataArray.totalVolume.max(), 0, 1, color.new(vp_valueAreaDwonColor , 95), color.new(vp_valueAreaDwonColor , 0)) vp_profileUpVolumeColor := color.from_gradient(volumeDataArray.totalVolume.get(volumeNodeLevel) / volumeDataArray.totalVolume.max(), 0, 1, color.new(vp_profileUpVolumeColor , 95), color.new(vp_profileUpVolumeColor , 0)) vp_profileDownVolumeColor := color.from_gradient(volumeDataArray.totalVolume.get(volumeNodeLevel) / volumeDataArray.totalVolume.max(), 0, 1, color.new(vp_profileDownVolumeColor, 95), color.new(vp_profileDownVolumeColor, 0)) startProfileIndex = profilePlacementRight ? profileHorizontalOffset + int(last_bar_index - volumeDataArray.bullishVolume.get(volumeNodeLevel) / volumeDataArray.totalVolume.max() * profileWidth) : VP.startIndex endProfileIndex = profilePlacementRight ? profileHorizontalOffset + last_bar_index : int(startProfileIndex + volumeDataArray.bullishVolume.get(volumeNodeLevel) / volumeDataArray.totalVolume.max() * profileWidth) VP.boxes.push(box.new(startProfileIndex, lowestPrice + (volumeNodeLevel + .1) * priceStep, endProfileIndex, lowestPrice + (volumeNodeLevel + .9) * priceStep, color(na), bgcolor = volumeNodeLevel >= VP.valLevel and volumeNodeLevel <= VP.vahLevel ? vp_valueAreaUpColor : vp_profileUpVolumeColor)) startProfileIndex := profilePlacementRight ? startProfileIndex : endProfileIndex endProfileIndex := profilePlacementRight ? startProfileIndex - int( (volumeDataArray.totalVolume.get(volumeNodeLevel) - volumeDataArray.bullishVolume.get(volumeNodeLevel)) / volumeDataArray.totalVolume.max() * profileWidth) : startProfileIndex + int( (volumeDataArray.totalVolume.get(volumeNodeLevel) - volumeDataArray.bullishVolume.get(volumeNodeLevel)) / volumeDataArray.totalVolume.max() * profileWidth) VP.boxes.push(box.new(startProfileIndex, lowestPrice + (volumeNodeLevel + .1) * priceStep, endProfileIndex, lowestPrice + (volumeNodeLevel + .9) * priceStep, color(na), bgcolor = volumeNodeLevel >= VP.valLevel and volumeNodeLevel <= VP.vahLevel ? vp_valueAreaDwonColor : vp_profileDownVolumeColor)) volumeDataArray.endProfileIndex.set(volumeNodeLevel, endProfileIndex) if vn_peaksShow != 'None' or vn_troughsShow != 'None' var int startVolumeNodeIndex = na, var int endVolumeNodeIndex = na var bool peakUpperNth = na, var bool peakLowerNth = na peaksNumberOfNodes = int(vp_profileNumberOfRows * vn_peaksNumberOfNodes) tempPeakTotalVolume = volumeDataArray.totalVolume.copy() for index = 1 to peaksNumberOfNodes tempPeakTotalVolume.unshift(0.) tempPeakTotalVolume.push(0.) for volumeNodeLevel = 0 to vp_profileNumberOfRows - 1 + 2 * peaksNumberOfNodes if vn_peaksShow != 'None' and volumeNodeLevel >= 2 * peaksNumberOfNodes for currentVolumeNode = volumeNodeLevel - 2 * peaksNumberOfNodes to volumeNodeLevel - peaksNumberOfNodes - 1 if tempPeakTotalVolume.get(volumeNodeLevel - peaksNumberOfNodes) <= tempPeakTotalVolume.get(currentVolumeNode) peakUpperNth := false break else peakUpperNth := true for currentVolumeNode = volumeNodeLevel - peaksNumberOfNodes + 1 to volumeNodeLevel if tempPeakTotalVolume.get(volumeNodeLevel - peaksNumberOfNodes) <= tempPeakTotalVolume.get(currentVolumeNode) peakLowerNth := false break else peakLowerNth := true if peakUpperNth and peakLowerNth and tempPeakTotalVolume.get(volumeNodeLevel - peaksNumberOfNodes) / tempPeakTotalVolume.max() > vn_VolumeNodeThreshold startVolumeNodeIndex := vp_profileShow ? profilePlacementRight ? VP.startIndex : volumeDataArray.endProfileIndex.get(volumeNodeLevel - 2 * peaksNumberOfNodes) : //VP.startIndex + int(volumeDataArray.totalVolume.get(volumeNodeLevel - vn_peaksNumberOfNodes) / volumeDataArray.totalVolume.max() * profileWidth) : VP.startIndex endVolumeNodeIndex := vp_profileShow ? profilePlacementRight ? volumeDataArray.endProfileIndex.get(volumeNodeLevel - 2 * peaksNumberOfNodes) : //profileHorizontalOffset + int(last_bar_index - volumeDataArray.totalVolume.get(volumeNodeLevel - vn_peaksNumberOfNodes) / volumeDataArray.totalVolume.max() * profileWidth) : last_bar_index : last_bar_index vn_peakVolumeColor := vn_peaksShow == 'Peaks' ? vn_peakVolumeColor : color.from_gradient(tempPeakTotalVolume.get(volumeNodeLevel - peaksNumberOfNodes) / tempPeakTotalVolume.max(), 0, 1, color.new(vn_peakVolumeColor, 95), color.new(vn_peakVolumeColor, 65)) VP.boxes.push(box.new(startVolumeNodeIndex, lowestPrice + (volumeNodeLevel - 2 * peaksNumberOfNodes + .1) * priceStep, endVolumeNodeIndex, lowestPrice + (volumeNodeLevel - 2 * peaksNumberOfNodes + .9) * priceStep, color(na), bgcolor = vn_peakVolumeColor)) if vn_peaksShow == 'Clusters' for currentVolumeNode = volumeNodeLevel - 2 * peaksNumberOfNodes to volumeNodeLevel if currentVolumeNode >= peaksNumberOfNodes and currentVolumeNode <= vp_profileNumberOfRows - 1 + peaksNumberOfNodes if not volumeDataArray.peakVolume.get(currentVolumeNode - peaksNumberOfNodes) startVolumeNodeIndex := vp_profileShow ? profilePlacementRight ? VP.startIndex : volumeDataArray.endProfileIndex.get(currentVolumeNode - peaksNumberOfNodes) : //VP.startIndex + int(volumeDataArray.totalVolume.get(currentVolumeNode) / volumeDataArray.totalVolume.max() * profileWidth) : VP.startIndex endVolumeNodeIndex := vp_profileShow ? profilePlacementRight ? volumeDataArray.endProfileIndex.get(currentVolumeNode - peaksNumberOfNodes) : //profileHorizontalOffset + int(last_bar_index - volumeDataArray.totalVolume.get(currentVolumeNode) / volumeDataArray.totalVolume.max() * profileWidth) : last_bar_index : last_bar_index VP.boxes.push(box.new(startVolumeNodeIndex, lowestPrice + (currentVolumeNode - peaksNumberOfNodes + .0) * priceStep, endVolumeNodeIndex, lowestPrice + (currentVolumeNode - peaksNumberOfNodes + 1.) * priceStep, color(na), bgcolor = vn_peakVolumeColor)) volumeDataArray.peakVolume.set(currentVolumeNode - peaksNumberOfNodes, true) tempPeakTotalVolume.clear() var bool troughUpperNth = na, var bool troughLowerNth = na troughsNumberOfNodes = int(vp_profileNumberOfRows * vn_troughsNumberOfNodes) tempTroughTotalVolume = volumeDataArray.totalVolume.copy() for index = 1 to troughsNumberOfNodes tempTroughTotalVolume.unshift(volumeDataArray.totalVolume.max()) tempTroughTotalVolume.push(volumeDataArray.totalVolume.max()) for volumeNodeLevel = 0 to vp_profileNumberOfRows - 1 + 2 * troughsNumberOfNodes if vn_troughsShow != 'None' and volumeNodeLevel >= 2 * troughsNumberOfNodes for currentVolumeNode = volumeNodeLevel - 2 * troughsNumberOfNodes to volumeNodeLevel - troughsNumberOfNodes - 1 if tempTroughTotalVolume.get(volumeNodeLevel - troughsNumberOfNodes) >= tempTroughTotalVolume.get(currentVolumeNode) troughUpperNth := false break else troughUpperNth := true for currentVolumeNode = volumeNodeLevel - troughsNumberOfNodes + 1 to volumeNodeLevel if tempTroughTotalVolume.get(volumeNodeLevel - troughsNumberOfNodes) >= tempTroughTotalVolume.get(currentVolumeNode) troughLowerNth := false break else troughLowerNth := true if troughUpperNth and troughLowerNth and tempTroughTotalVolume.get(volumeNodeLevel - troughsNumberOfNodes) / tempTroughTotalVolume.max() > vn_VolumeNodeThreshold startVolumeNodeIndex := vp_profileShow ? profilePlacementRight ? VP.startIndex : volumeDataArray.endProfileIndex.get(volumeNodeLevel - 2 * troughsNumberOfNodes) : //VP.startIndex + int(volumeDataArray.totalVolume.get(volumeNodeLevel - vn_troughsNumberOfNodes) / volumeDataArray.totalVolume.max() * profileWidth) : VP.startIndex endVolumeNodeIndex := vp_profileShow ? profilePlacementRight ? volumeDataArray.endProfileIndex.get(volumeNodeLevel - 2 * troughsNumberOfNodes) : //profileHorizontalOffset + int(last_bar_index - volumeDataArray.totalVolume.get(volumeNodeLevel - vn_troughsNumberOfNodes) / volumeDataArray.totalVolume.max() * profileWidth) : last_bar_index : last_bar_index vn_troughVolumeColor := vn_troughsShow == 'Troughs' ? vn_troughVolumeColor : color.from_gradient(tempTroughTotalVolume.get(volumeNodeLevel - troughsNumberOfNodes) / tempTroughTotalVolume.max(), 0, 1, color.new(vn_troughVolumeColor, 95), color.new(vn_troughVolumeColor, 31)) VP.boxes.push(box.new(startVolumeNodeIndex, lowestPrice + (volumeNodeLevel - 2 * troughsNumberOfNodes + .1) * priceStep, endVolumeNodeIndex, lowestPrice + (volumeNodeLevel - 2 * troughsNumberOfNodes + .9) * priceStep, color(na), bgcolor = vn_troughVolumeColor)) if vn_troughsShow == 'Clusters' for currentVolumeNode = volumeNodeLevel - 2 * troughsNumberOfNodes to volumeNodeLevel if currentVolumeNode >= troughsNumberOfNodes and currentVolumeNode <= vp_profileNumberOfRows - 1 + troughsNumberOfNodes if not volumeDataArray.troughVolume.get(currentVolumeNode - troughsNumberOfNodes) startVolumeNodeIndex := vp_profileShow ? profilePlacementRight ? VP.startIndex : volumeDataArray.endProfileIndex.get(currentVolumeNode - troughsNumberOfNodes) : //VP.startIndex + int(volumeDataArray.totalVolume.get(currentVolumeNode) / volumeDataArray.totalVolume.max() * profileWidth) : VP.startIndex endVolumeNodeIndex := vp_profileShow ? profilePlacementRight ? volumeDataArray.endProfileIndex.get(currentVolumeNode - troughsNumberOfNodes) : //profileHorizontalOffset + int(last_bar_index - volumeDataArray.totalVolume.get(currentVolumeNode) / volumeDataArray.totalVolume.max() * profileWidth) : last_bar_index : last_bar_index VP.boxes.push(box.new(startVolumeNodeIndex, lowestPrice + (currentVolumeNode - troughsNumberOfNodes + .0) * priceStep, endVolumeNodeIndex, lowestPrice + (currentVolumeNode - troughsNumberOfNodes + 1.) * priceStep, color(na), bgcolor = vn_troughVolumeColor)) volumeDataArray.troughVolume.set(currentVolumeNode - troughsNumberOfNodes, true) tempTroughTotalVolume.clear() if vn_highestNVolumeNodes > 0 for highestNode = 0 to vn_highestNVolumeNodes - 1 startVolumeNodeIndex = vp_profileShow ? profilePlacementRight ? VP.startIndex : volumeDataArray.endProfileIndex.get(volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.max(highestNode))) : //VP.startIndex + int(volumeDataArray.totalVolume.get(volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.max(highestNode))) / volumeDataArray.totalVolume.max() * profileWidth) : VP.startIndex endVolumeNodeIndex = vp_profileShow ? profilePlacementRight ? volumeDataArray.endProfileIndex.get(volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.max(highestNode))) : //profileHorizontalOffset + int(last_bar_index - volumeDataArray.totalVolume.get(volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.max(highestNode))) / volumeDataArray.totalVolume.max() * profileWidth) : last_bar_index : last_bar_index VP.boxes.push(box.new(startVolumeNodeIndex, lowestPrice + (volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.max(highestNode)) + .1) * priceStep, endVolumeNodeIndex, lowestPrice + (volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.max(highestNode)) + .9) * priceStep, color(na), bgcolor = vn_highestVolumeColor)) if vn_lowestNVolumeNodes > 0 lowestNVolumeNodeCount = 0 lowestNVolumeNodeIndex = 0//volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.min()) lowestNVolumeNodeValue = 0. while lowestNVolumeNodeCount < vn_lowestNVolumeNodes if lowestNVolumeNodeIndex == vp_profileNumberOfRows break if volumeDataArray.totalVolume.min(lowestNVolumeNodeIndex) != lowestNVolumeNodeValue lowestNVolumeNodeValue := volumeDataArray.totalVolume.min(lowestNVolumeNodeIndex) startVolumeNodeIndex = vp_profileShow ? profilePlacementRight ? VP.startIndex : volumeDataArray.endProfileIndex.get(volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.min(lowestNVolumeNodeIndex))) : //VP.startIndex + int(volumeDataArray.totalVolume.get(volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.min(lowestNVolumeNodeIndex))) / volumeDataArray.totalVolume.max() * profileWidth) : VP.startIndex endVolumeNodeIndex = vp_profileShow ? profilePlacementRight ? volumeDataArray.endProfileIndex.get(volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.min(lowestNVolumeNodeIndex))) : //profileHorizontalOffset + int(last_bar_index - volumeDataArray.totalVolume.get(volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.min(lowestNVolumeNodeIndex))) / volumeDataArray.totalVolume.max() * profileWidth) : last_bar_index : last_bar_index VP.boxes.push(box.new(startVolumeNodeIndex, lowestPrice + (volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.min(lowestNVolumeNodeIndex)) + .1) * priceStep, endVolumeNodeIndex, lowestPrice + (volumeDataArray.totalVolume.indexof(volumeDataArray.totalVolume.min(lowestNVolumeNodeIndex)) + .9) * priceStep, color(na), bgcolor = vn_lowestVolumeColor)) lowestNVolumeNodeCount += 1 lowestNVolumeNodeIndex += 1 log.info("yaz_kizim {0} {1}", VP.boxes.size(), volumeDataArray.totalVolume.size() ) //---------------------------------------------------------------------------------------------------------------------}
