Which TradingView volume profile fits your task?
There is no single best volume profile indicator for every chart. Use the range definition that answers your question. Native calculations use lower-timeframe bars when available; the selected interval varies by tool and available history.
| Method | Range | Useful for | Constraint |
|---|---|---|---|
| Fixed Range (FRVP) | Two selected anchors | Comparing the same event or consolidation | Keep anchors fixed; Extend Right changes the sample |
| Visible Range (VRVP) | Bars visible on screen | Exploring the current chart window | Panning or zooming changes the profiled period |
| Session Volume Profile | Defined trading sessions | Comparing separate sessions | Match regular/extended hours and exchange timezone |
| This CSV analyzer | All imported rows | Inspecting a documented OHLCV estimate | No intrabar requests, delta or native-profile replication |
| Pine example below | Rolling chart-bar lookback | Editing the approximation on a chart | Latest profile only; includes the developing bar |
Check TradingView's current plan comparison for native feature access. A drawing tool, built-in indicator and community script can have different availability. This page does not require a TradingView subscription to calculate CSV estimates.
POC and value area in this analyzer
POC is displayed at the center of the largest estimated-volume bin. VAH is the top edge of the highest included bin; VAL is the bottom edge of the lowest. The percentage is a configurable volume target, not a standard deviation or confidence interval.
Each candle contributes volume × overlap / (high − low) to each intersecting bin. A zero-range candle contributes all its volume to its price bin. This assumes uniform volume across the candle range; OHLCV alone cannot recover the actual path or trades at each price.
The largest bin starts the value area. We add the larger adjacent bin until the target is met or exceeded, so the included percentage can overshoot. Equal POC volumes select the lower bin; equal adjacent volumes expand downward first. These explicit rules differ from TradingView's documented stopping and tie-breaking rules. Rows here are equal price intervals, without native tick-size rounding.
Compare on the same sample
- Select one symbol and data feed on standard candles. Record interval, timezone, session hours, start and end timestamps.
- Apply Fixed Range to those timestamps, with Extend Right disabled. Record row size and value-area percentage.
- Export exactly that OHLCV range to CSV. Match the analyzer bin count and value-area percentage; native tick rounding may still create different boundaries.
- Compare POC, VAH and VAL in price units and in bin widths. Repeat at a finer source interval and note whether conclusions change.
This is a comparison procedure, not a completed benchmark. No accuracy percentage or native-level agreement is claimed.
Delta volume profile is a separate calculation
TradingView's native profile delta subtracts down volume from up volume using its bar-direction classification. That is different from identifying trades executed at bid or ask. This analyzer and the Pine example show total estimated volume only.
Editable Pine Script v6 approximation
Paste this complete indicator into Pine Editor and add it to the chart. It draws a rolling profile on the last bar; it does not expose a historical signal series or alerts. The live bar can move the levels. No profile is drawn until the full lookback has volume data, positive total volume and a nonzero price range. Missing volume is never replaced with invented activity.
//@version=6
indicator("Volume Profile Approximation [Pineify]", overlay = true, max_boxes_count = 500, max_lines_count = 500, max_bars_back = 300)
// ---------------------------------------------------------
// Inputs & Configuration
// ---------------------------------------------------------
int lookbackBars = input.int(60, "Lookback Period (Bars)", minval = 10, maxval = 300, tooltip = "Number of historical bars to aggregate volume distribution")
int numBins = input.int(24, "Price Levels (Bins)", minval = 10, maxval = 50, tooltip = "Number of horizontal price buckets")
int vaPercent = input.int(70, "Value Area Volume (%)", minval = 50, maxval = 90, tooltip = "Standard percentage of total volume to include in Value Area (70% standard)")
color pocColor = input.color(color.new(#f59e0b, 0), "Point of Control (POC) Color")
color vaColor = input.color(color.new(#3b82f6, 65), "Value Area Box Color")
color nonVaColor = input.color(color.new(#94a3b8, 80), "Outside VA Box Color")
int profileWidthBars = input.int(25, "Histogram Width (Bars)", minval = 5, maxval = 80, tooltip = "Maximum bar length of the horizontal histogram")
// ---------------------------------------------------------
// Drawing Object Storage
// ---------------------------------------------------------
var box[] profileBoxes = array.new_box()
var line pocLine = na
var line vahLine = na
var line valLine = na
// ---------------------------------------------------------
// Volume-at-Price Calculation (Executed on Last Bar Only)
// ---------------------------------------------------------
float highestPrice = ta.highest(high, lookbackBars)
float lowestPrice = ta.lowest(low, lookbackBars)
float windowVolume = math.sum(nz(volume, 0), lookbackBars)
float missingVolumeBars = math.sum(na(volume) ? 1.0 : 0.0, lookbackBars)
if barstate.islast
// Clean up historical drawing objects to preserve memory
if array.size(profileBoxes) > 0
for i = 0 to array.size(profileBoxes) - 1
box.delete(array.get(profileBoxes, i))
array.clear(profileBoxes)
line.delete(pocLine)
line.delete(vahLine)
line.delete(valLine)
// Find extreme high and low across the lookback period
float priceRange = highestPrice - lowestPrice
if bar_index >= lookbackBars - 1 and priceRange > 0 and windowVolume > 0 and missingVolumeBars == 0
float binSize = priceRange / numBins
array<float> binVolumes = array.new_float(numBins, 0.0)
float totalVol = 0.0
// Distribute volume across price bins proportionally
for b = 0 to lookbackBars - 1
float bHigh = high[b]
float bLow = low[b]
float bVol = volume[b]
float bSpan = bHigh - bLow
if bSpan > 0
int startBin = math.max(0, math.floor((bLow - lowestPrice) / binSize))
int endBin = math.min(numBins - 1, math.floor((bHigh - lowestPrice) / binSize))
for bin = startBin to endBin
float binFloor = lowestPrice + bin * binSize
float binCeil = binFloor + binSize
float overlap = math.max(0.0, math.min(bHigh, binCeil) - math.max(bLow, binFloor))
float allocatedVol = bVol * (overlap / bSpan)
array.set(binVolumes, bin, array.get(binVolumes, bin) + allocatedVol)
else
int targetBin = math.min(numBins - 1, math.max(0, math.floor((close[b] - lowestPrice) / binSize)))
array.set(binVolumes, targetBin, array.get(binVolumes, targetBin) + bVol)
totalVol += bVol
// Find Point of Control (POC: bin with highest estimated volume)
float maxVol = 0.0
int pocIndex = 0
for i = 0 to numBins - 1
float v = array.get(binVolumes, i)
if v > maxVol
maxVol := v
pocIndex := i
// Calculate Value Area (70% total volume around POC)
float targetVaVol = totalVol * (vaPercent / 100.0)
float currentVaVol = array.get(binVolumes, pocIndex)
int vaLowIdx = pocIndex
int vaHighIdx = pocIndex
while currentVaVol < targetVaVol and (vaLowIdx > 0 or vaHighIdx < numBins - 1)
float lowerVol = vaLowIdx > 0 ? array.get(binVolumes, vaLowIdx - 1) : 0.0
float upperVol = vaHighIdx < numBins - 1 ? array.get(binVolumes, vaHighIdx + 1) : 0.0
if lowerVol >= upperVol and vaLowIdx > 0
vaLowIdx -= 1
currentVaVol += lowerVol
else if vaHighIdx < numBins - 1
vaHighIdx += 1
currentVaVol += upperVol
else if vaLowIdx > 0
vaLowIdx -= 1
currentVaVol += lowerVol
// Render horizontal histogram boxes
int startBarIdx = bar_index
for i = 0 to numBins - 1
float bVolume = array.get(binVolumes, i)
float ratio = maxVol > 0 ? (bVolume / maxVol) : 0.0
int barLen = math.round(ratio * profileWidthBars)
if barLen > 0
float bBottom = lowestPrice + i * binSize
float bTop = bBottom + binSize
bool isInVA = (i >= vaLowIdx and i <= vaHighIdx)
color bColor = (i == pocIndex) ? color.new(pocColor, 30) : (isInVA ? vaColor : nonVaColor)
color bBorder = (i == pocIndex) ? pocColor : color.new(bColor, 40)
box bx = box.new(left = startBarIdx, top = bTop, right = startBarIdx + barLen, bottom = bBottom,
border_color = bBorder, border_width = 1, bgcolor = bColor)
array.push(profileBoxes, bx)
// Draw POC, VAH, and VAL horizontal reference lines
float pocPrice = lowestPrice + (pocIndex + 0.5) * binSize
float vahPrice = lowestPrice + (vaHighIdx + 1) * binSize
float valPrice = lowestPrice + vaLowIdx * binSize
pocLine := line.new(x1 = bar_index - lookbackBars + 1, y1 = pocPrice, x2 = bar_index + profileWidthBars, y2 = pocPrice,
color = pocColor, width = 2, style = line.style_solid)
vahLine := line.new(x1 = bar_index - lookbackBars + 1, y1 = vahPrice, x2 = bar_index + profileWidthBars, y2 = vahPrice,
color = color.green, width = 1, style = line.style_dashed)
valLine := line.new(x1 = bar_index - lookbackBars + 1, y1 = valPrice, x2 = bar_index + profileWidthBars, y2 = valPrice,
color = color.red, width = 1, style = line.style_dashed)
CSV inputs and limits
Use the upload button with an unquoted CSV containing date (or time), high, low, close and volume. Open is optional and unused. Keep prices and volume units consistent. The tool accepts 2 to 50,000 rows and files up to 10 MB. It rejects missing or non-finite values, negative volume, closes outside the high-low range, zero total volume and a flat full range. Duplicate timestamps are counted as separate rows; remove duplicates before importing.
For further chart methods, see TradingView indicators or the fixed range volume profile guide. For custom calculation and alert logic, use Pine Script AI Agent and review the generated source before use.
Sources and interpretation
- TradingView: calculation, volume types, value area and delta
- TradingView: fixed range data selection and row sizing
- TradingView: visible range volume profile
Profiles describe activity within a selected historical sample. A POC or value-area boundary does not establish fair value, institutional intent or a profitable entry. Educational information only, not investment advice.