Last active
February 7, 2026 13:48
-
-
Save 4skinSkywalker/d5e42f46851decf69054e0d0287ab6f5 to your computer and use it in GitHub Desktop.
Volume Profile Visible Range in Pine Script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ | |
| // © Fr3d0C0rl30n3 | |
| //@version=6 | |
| indicator("Fr3d0's Volume Profile Visible Range", "VPVR", overlay=true, max_boxes_count=500) | |
| LINE_COLOR = color.new(color.black, 0) | |
| POC_LINE_COLOR = color.new(color.red, 0) | |
| VALUE_AREA_LINE_COLOR = color.new(color.yellow, 0) | |
| BUY_COLOR = color.new(color.green, 50) | |
| SELL_COLOR = color.new(color.red, 50) | |
| MAX_BARS = 365 | |
| topBottomLineColor = input.color(LINE_COLOR, "Top/bottom Line Color") | |
| pocLineColor = input.color(POC_LINE_COLOR, "PoC Line Color") | |
| valueAreaLineColor = input.color(VALUE_AREA_LINE_COLOR, "Value Area Line Color") | |
| buyBarColor = input.color(BUY_COLOR, "Buy Bar Color") | |
| sellBarColor = input.color(SELL_COLOR, "Sell Bar Color") | |
| numOfBars = input.int(90, 'Number of bars', minval=21, maxval=MAX_BARS) | |
| distLastCandle = input.int(2, 'Distance from last candle', minval=1, maxval=MAX_BARS) | |
| lastBar = bar_index - distLastCandle | |
| firstBar = lastBar - numOfBars + 1 | |
| visibleBars = lastBar - firstBar + 1 | |
| numOfHists = input.int(100, 'Number of hists', minval=20, maxval=200) | |
| widestHistWidth = visibleBars | |
| histLowList = array.new_float(numOfHists, na) | |
| histHighList = array.new_float(numOfHists, na) | |
| histPriceList = array.new_float(numOfHists, 0.0) | |
| histBuyVolumeList = array.new_float(numOfHists, 0.0) | |
| histSellVolumeList = array.new_float(numOfHists, 0.0) | |
| histVolumePercentageList = array.new_float(numOfHists, 0.0) | |
| // Clean up drawings every tick | |
| var buyBars = array.new_box(MAX_BARS, na) | |
| for i=0 to MAX_BARS-1 | |
| box.delete(array.get(buyBars, i)) | |
| var sellBars = array.new_box(MAX_BARS, na) | |
| for i=0 to MAX_BARS-1 | |
| box.delete(array.get(sellBars, i)) | |
| var line topLine = na | |
| line.delete(topLine) | |
| var line bottomLine = na | |
| line.delete(bottomLine) | |
| var line pocLine = na | |
| line.delete(pocLine) | |
| var line vahLine = na | |
| line.delete(vahLine) | |
| var line valLine = na | |
| line.delete(valLine) | |
| var totalVolume = 0.0 | |
| var float volumeAccum = 0 | |
| var float VAH = na | |
| var float VAL = na | |
| var float rangeHigh = na | |
| var float rangeLow = na | |
| var float rangeHeight = na | |
| var float histHeight = na | |
| if barstate.islast | |
| // Define range height | |
| rangeHigh := high[distLastCandle] | |
| rangeLow := low[distLastCandle] | |
| for _i = 1 to numOfBars - 1 | |
| i = distLastCandle + _i | |
| rangeHigh := math.max(rangeHigh, high[i]) | |
| rangeLow := math.min(rangeLow, low[i]) | |
| rangeHeight := rangeHigh - rangeLow | |
| histHeight := rangeHeight / numOfHists | |
| // Define lows and highs of the hists | |
| for i = 0 to numOfHists - 1 | |
| histLow = rangeLow + histHeight * i | |
| histHigh = rangeLow + histHeight * (i + 1) | |
| array.set(histLowList, i, histLow) | |
| array.set(histHighList, i, histHigh) | |
| array.set(histPriceList, i, (histLow + histHigh) / 2) | |
| // Assign bar's volumes to hists | |
| for _i = 0 to numOfBars - 1 | |
| i = distLastCandle + _i | |
| totalVolume := totalVolume + volume[i] | |
| currentBarHeight = high[i] - low[i] | |
| currentBuyVolume = (high[i] == low[i]) ? 0 : volume[i] * (close[i] - low[i]) / currentBarHeight | |
| currentSellVolume = (high[i] == low[i]) ? 0 : volume[i] * (high[i] - close[i]) / currentBarHeight | |
| // Define the percentages of the current volume to give to hists | |
| for j = 0 to numOfHists - 1 | |
| histLow = array.get(histLowList, j) | |
| histHigh = array.get(histHighList, j) | |
| target = (math.max(histHigh, high[i]) - math.min(histLow, low[i])) | |
| - (math.max(histHigh, high[i]) - math.min(histHigh, high[i])) | |
| - (math.max(histLow, low[i]) - math.min(histLow, low[i])) | |
| histVolumePercentage = target / currentBarHeight | |
| histBuyVolume = array.get(histBuyVolumeList, j) | |
| histSellVolume = array.get(histSellVolumeList, j) | |
| // If there is at least one hist affected | |
| // then divide the current volume by the number of hists affected | |
| if histVolumePercentage > 0 | |
| array.set(histBuyVolumeList, j, histBuyVolume + currentBuyVolume * histVolumePercentage) | |
| array.set(histSellVolumeList, j, histSellVolume + currentSellVolume * histVolumePercentage) | |
| // Find the hist with the highest volume | |
| highestHistVolume = 0.0 | |
| pocIndex = 0 | |
| for i = 0 to numOfHists - 1 | |
| histBuyVolume = array.get(histBuyVolumeList, i) | |
| histSellVolume = array.get(histSellVolumeList, i) | |
| histVolume = histBuyVolume + histSellVolume | |
| if histVolume > highestHistVolume | |
| highestHistVolume := histVolume | |
| pocIndex := i | |
| // Draw top and bottom of the range considered | |
| topLine := line.new(firstBar, rangeHigh, lastBar, rangeHigh, xloc=xloc.bar_index, color=topBottomLineColor, width = 2) | |
| bottomLine := line.new(firstBar, rangeLow, lastBar, rangeLow, xloc=xloc.bar_index, color=topBottomLineColor, width = 2) | |
| // Draw Point of Control | |
| pocHistLow = array.get(histLowList, pocIndex) | |
| pocHistHigh = array.get(histHighList, pocIndex) | |
| pocPos = pocHistLow + (pocHistHigh - pocHistLow) / 2 | |
| pocLine := line.new(firstBar, pocPos, lastBar + 1, pocPos, xloc=xloc.bar_index, color=pocLineColor, width = 2) | |
| // Value area calculation | |
| valueAreaVolume = totalVolume * 0.7 | |
| volumeAccum := array.get(histBuyVolumeList, pocIndex) + array.get(histSellVolumeList, pocIndex) | |
| VAH := pocPos | |
| VAL := pocPos | |
| upIndex = pocIndex + 1 | |
| downIndex = pocIndex - 1 | |
| for _ = 0 to numOfHists - 1 | |
| volUp = (upIndex < numOfHists) ? (array.get(histBuyVolumeList, upIndex) + array.get(histSellVolumeList, upIndex)) : 0.0 | |
| volDown = (downIndex >= 0) ? (array.get(histBuyVolumeList, downIndex) + array.get(histSellVolumeList, downIndex)) : 0.0 | |
| if volumeAccum >= valueAreaVolume | |
| break | |
| if volUp >= volDown and upIndex < numOfHists | |
| VAH := array.get(histPriceList, upIndex) | |
| volumeAccum += volUp | |
| upIndex += 1 | |
| else if downIndex >= 0 | |
| VAL := array.get(histPriceList, downIndex) | |
| volumeAccum += volDown | |
| downIndex -= 1 | |
| vahLine := line.new(firstBar, VAH, lastBar, VAH, color=valueAreaLineColor, width=2, style=line.style_dashed) // VA High | |
| valLine := line.new(firstBar, VAL, lastBar, VAL, color=valueAreaLineColor, width=2, style=line.style_dashed) | |
| // Draw hists and highlight the Point of Control | |
| for i = 0 to numOfHists - 1 | |
| histLow = array.get(histLowList, i) | |
| histHigh = array.get(histHighList, i) | |
| histBuyVolume = array.get(histBuyVolumeList, i) | |
| histSellVolume = array.get(histSellVolumeList, i) | |
| histVolume = histBuyVolume + histSellVolume | |
| histWidth = histVolume * widestHistWidth / highestHistVolume | |
| histBuyWidth = math.floor(histBuyVolume * histWidth / histVolume) | |
| histSellWidth = math.floor(histSellVolume * histWidth / histVolume) | |
| // Draw buy and sell hists | |
| buyHistEnd = firstBar + histBuyWidth | |
| array.set(buyBars, i, box.new( | |
| left=firstBar, | |
| top=histHigh, | |
| right=buyHistEnd, | |
| bottom=histLow, | |
| bgcolor=buyBarColor, | |
| border_width=0)) | |
| array.set(sellBars, i, box.new( | |
| left=buyHistEnd, | |
| top=histHigh, | |
| right=buyHistEnd + histSellWidth, | |
| bottom=histLow, | |
| bgcolor=sellBarColor, | |
| border_width=0)) |
Thank you very much! Great work!🤟🏻
thanks Great Work
How do you even begin to know how to do this? This is amazing.
Author
Thanks! 💕
There is the article that explains how I did it: Fredo's VPVR
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Anyway can I get this script compatible with Webull? It seems like Webull uses a mix of Pine script and easy language but I'm no coder so idk