Skip to content

Instantly share code, notes, and snippets.

@4skinSkywalker
Last active February 7, 2026 13:48
Show Gist options
  • Select an option

  • Save 4skinSkywalker/d5e42f46851decf69054e0d0287ab6f5 to your computer and use it in GitHub Desktop.

Select an option

Save 4skinSkywalker/d5e42f46851decf69054e0d0287ab6f5 to your computer and use it in GitHub Desktop.
Volume Profile Visible Range in Pine Script
// 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))
@BreakNews
Copy link

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

@vovkapoc
Copy link

vovkapoc commented Mar 7, 2024

Thank you very much! Great work!🤟🏻

@rickinglob
Copy link

thanks Great Work

@Noob-dummy
Copy link

How do you even begin to know how to do this? This is amazing.

@4skinSkywalker
Copy link
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