Last active
January 28, 2026 23:51
-
-
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, 15) | |
| POC_LINE_COLOR = color.new(color.red, 30) | |
| VALUE_AREA_LINE_COLOR = color.new(color.yellow, 30) | |
| BORDER_COLOR = color.new(color.black, 70) | |
| BUY_COLOR = color.new(color.green, 15) | |
| SELL_COLOR = color.new(color.red, 15) | |
| TIME_UNIT = time - time[1] | |
| 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=14, maxval=MAX_BARS) | |
| distLastCandle = input.int(2, 'Distance from last candle', minval=2, maxval=20) | |
| rangeHigh = ta.highest(high, numOfBars) | |
| rangeLow = ta.lowest(low, numOfBars) | |
| rangeHeight = rangeHigh - rangeLow | |
| firstBar = bar_index - numOfBars + 1 | |
| lastBar = bar_index | |
| visibleBars = lastBar - firstBar + 1 | |
| numOfHistograms = input.int(50, 'Number of histograms', minval=10, maxval=200) | |
| widestHistogramWidth = visibleBars | |
| histogramHeight = rangeHeight / numOfHistograms | |
| histogramLowList = array.new_float(numOfHistograms, na) | |
| histogramHighList = array.new_float(numOfHistograms, na) | |
| histogramPriceList = array.new_float(numOfHistograms, 0.0) | |
| histogramBuyVolumeList = array.new_float(numOfHistograms, 0.0) | |
| histogramSellVolumeList = array.new_float(numOfHistograms, 0.0) | |
| histogramVolumePercentageList = array.new_float(numOfHistograms, 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 | |
| if barstate.islast | |
| // Define lows and highs of the histograms | |
| for i = 0 to numOfHistograms - 1 | |
| histogramLow = rangeLow + histogramHeight * i | |
| histogramHigh = rangeLow + histogramHeight * (i + 1) | |
| array.set(histogramLowList, i, histogramLow) | |
| array.set(histogramHighList, i, histogramHigh) | |
| array.set(histogramPriceList, i, (histogramLow + histogramHigh) / 2) | |
| // Assign bar's volumes to histograms | |
| for i = 0 to numOfBars - 1 | |
| 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 histograms | |
| for j = 0 to numOfHistograms - 1 | |
| histogramLow = array.get(histogramLowList, j) | |
| histogramHigh = array.get(histogramHighList, j) | |
| target = (math.max(histogramHigh, high[i]) - math.min(histogramLow, low[i])) | |
| - (math.max(histogramHigh, high[i]) - math.min(histogramHigh, high[i])) | |
| - (math.max(histogramLow, low[i]) - math.min(histogramLow, low[i])) | |
| histogramVolumePercentage = target / currentBarHeight | |
| histogramBuyVolume = array.get(histogramBuyVolumeList, j) | |
| histogramSellVolume = array.get(histogramSellVolumeList, j) | |
| // If there is at least one histogram affected | |
| // then divide the current volume by the number of histograms affected | |
| if histogramVolumePercentage > 0 | |
| array.set(histogramBuyVolumeList, j, histogramBuyVolume + currentBuyVolume * histogramVolumePercentage) | |
| array.set(histogramSellVolumeList, j, histogramSellVolume + currentSellVolume * histogramVolumePercentage) | |
| // Find the histogram with the highest volume | |
| highestHistogramVolume = 0.0 | |
| pocIndex = 0 | |
| for i = 0 to numOfHistograms - 1 | |
| histogramBuyVolume = array.get(histogramBuyVolumeList, i) | |
| histogramSellVolume = array.get(histogramSellVolumeList, i) | |
| histogramVolume = histogramBuyVolume + histogramSellVolume | |
| if histogramVolume > highestHistogramVolume | |
| highestHistogramVolume := histogramVolume | |
| pocIndex := i | |
| timeUnit = time - time[1] | |
| // Draw top and bottom of the range considered | |
| topLine := line.new(time[numOfBars], rangeHigh, time_close + distLastCandle * timeUnit, rangeHigh, xloc=xloc.bar_time, color=topBottomLineColor, width = 2) | |
| bottomLine := line.new(time[numOfBars], rangeLow, time_close + distLastCandle * timeUnit, rangeLow, xloc=xloc.bar_time, color=topBottomLineColor, width = 2) | |
| // Draw Point of Control | |
| histLow = array.get(histogramLowList, pocIndex) | |
| histHigh = array.get(histogramHighList, pocIndex) | |
| pocPos = histLow + (histHigh - histLow) / 2 | |
| pocLine := line.new(time[numOfBars], pocPos, time_close + distLastCandle * timeUnit, pocPos, xloc=xloc.bar_time, color=pocLineColor, width = 2) | |
| // Value area calculation | |
| valueAreaVolume = totalVolume * 0.7 | |
| volumeAccum := array.get(histogramBuyVolumeList, pocIndex) + array.get(histogramSellVolumeList, pocIndex) | |
| VAH := pocPos | |
| VAL := pocPos | |
| upIndex = pocIndex + 1 | |
| downIndex = pocIndex - 1 | |
| for _ = 0 to numOfHistograms - 1 | |
| volUp = (upIndex < numOfHistograms) ? (array.get(histogramBuyVolumeList, upIndex) + array.get(histogramSellVolumeList, upIndex)) : 0.0 | |
| volDown = (downIndex >= 0) ? (array.get(histogramBuyVolumeList, downIndex) + array.get(histogramSellVolumeList, downIndex)) : 0.0 | |
| if volumeAccum >= valueAreaVolume | |
| break | |
| if volUp >= volDown and upIndex < numOfHistograms | |
| VAH := array.get(histogramPriceList, upIndex) | |
| volumeAccum += volUp | |
| upIndex += 1 | |
| else if downIndex >= 0 | |
| VAL := array.get(histogramPriceList, 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 histograms and highlight the Point of Control | |
| for i = 0 to numOfHistograms - 1 | |
| histogramLow = array.get(histogramLowList, i) | |
| histogramHigh = array.get(histogramHighList, i) | |
| histogramBuyVolume = array.get(histogramBuyVolumeList, i) | |
| histogramSellVolume = array.get(histogramSellVolumeList, i) | |
| histogramVolume = histogramBuyVolume + histogramSellVolume | |
| histogramWidth = widestHistogramWidth * histogramVolume / highestHistogramVolume | |
| histogramBuyWidth = math.floor(histogramWidth * histogramBuyVolume / histogramVolume) | |
| histogramSellWidth = math.floor(histogramWidth * histogramSellVolume / histogramVolume) | |
| // Draw buy and sell histograms | |
| array.set(buyBars, i, box.new( | |
| left=firstBar, | |
| top=histogramHigh, | |
| right=firstBar + histogramBuyWidth, | |
| bottom=histogramLow, | |
| bgcolor=buyBarColor, | |
| border_color=BORDER_COLOR)) | |
| array.set(sellBars, i, box.new( | |
| left=firstBar + histogramBuyWidth, | |
| top=histogramHigh, | |
| right=firstBar + histogramBuyWidth + histogramSellWidth, | |
| bottom=histogramLow, | |
| bgcolor=sellBarColor, | |
| border_color=BORDER_COLOR)) |
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