Volume Profile Trading Signals: Complete TradingView Guide
Volume Profile trading signals for TradingView. POC, VAH, VAL, and high volume node signals with Pine Script code and real intraday examples from ES futures.
Volume Profile Signal Interpretation
Quick-reference guide to 6 signal types you will see on the chart.
| Signal Type | Indicator Condition | Market Meaning | Reliability |
|---|---|---|---|
| POC Bounce → Buy/Sell | Price returns to the Point of Control and shows rejection with a reversal candle | The POC is where the most trading occurred. Price tends to gravitate toward it. A clean rejection at POC confirms the level holds as support or resistance. I rely on this more than VWAP for intraday ES trades. | 4/5 |
| VAH Breakout → Buy | Price breaks and closes above the Value Area High with above-average volume | Breaking above VAH signals acceptance at higher prices. The market is expanding the value area upward. New longs can target the next VAH from a fresh session. Failed breakouts (close below VAH) trap late buyers. | 4/5 |
| VAL Breakdown → Sell | Price breaks and closes below the Value Area Low on expanding volume | Breaking below VAL signals acceptance at lower prices and bearish expansion. Aggressive sellers are in control. Short positions target a new value area lower. On NQ, these moves often cover 10-15 points before the first pullback. | 3/5 |
| High Volume Node Rejection → Reversal | Price enters a high volume node zone and reverses sharply with a large range bar | High volume nodes act as price magnets but also as reversal traps once filled. A rejected HVN above current price acts as new resistance. A rejected HVN below acts as support. This is mean reversion within the value area. | 3/5 |
| Low Volume Node Gap Fill → Directional | Price gaps through a low volume node and accelerates in that direction | Low volume nodes are zones where little trading occurred. Price moves through them quickly with minimal resistance. They act as targets in directional moves. When price pulls back into an LVN, it often slices through easily. | 4/5 |
| Value Area Expansion → Trend Continuation | Value area expands upward or downward for three consecutive sessions with the POC shifting | Expanding value area with a shifting POC confirms a developing trend. Shrinking value area signals consolidation. I saw this clearly on ES in October 2024: three days of expanding VAH before a 40-point rally. | 5/5 |
Volume Profile Pine Script Signal Code
Ready-to-use Pine Script code for generating buy/sell signals. Copy and paste into your TradingView Pine Editor.
//@version=5
indicator("Volume Profile Trading Signals", overlay=true, max_labels_count=50)
// === Inputs ===
lookback = input.int(48, "Lookback Period (bars)", minval=8)
numRows = input.int(24, "Number of Rows", minval=8, maxval=48)
valueAreaPct = input.int(70, "Value Area %", minval=50, maxval=90)
showPOC = input.bool(true, "Show POC Line")
showVA = input.bool(true, "Show Value Area")
showHVN = input.bool(true, "Show High Volume Nodes")
showLVN = input.bool(true, "Show Low Volume Nodes")
// === Volume Profile Calculation ===
var float pocPrice = na
var float vahPrice = na
var float valPrice = na
calcVolumeProfile() =>
float[] prices = array.new<float>(0)
float[] volumes = array.new<float>(0)
float totalVol = 0.0
for i = 0 to lookback - 1
barVol = volume[i]
if barVol > 0
array.push(prices, (high[i] + low[i]) / 2)
array.push(volumes, barVol)
totalVol += barVol
// Sort by price
// Simplified: use average price bins
float step = (ta.highest(high, lookback) - ta.lowest(low, lookback)) / numRows
float[] binVols = array.new<float>(numRows, 0.0)
float[] binPrices = array.new<float>(numRows, 0.0)
float lowestPrice = ta.lowest(low, lookback)
for j = 0 to numRows - 1
float binPrice = lowestPrice + step * (j + 0.5)
array.set(binPrices, j, binPrice)
for k = 0 to array.size(prices) - 1
float p = array.get(prices, k)
if p >= lowestPrice + step * j and p < lowestPrice + step * (j + 1)
array.set(binVols, j, array.get(binVols, j) + array.get(volumes, k))
// Find POC (highest volume bin)
float maxVol = 0.0
int pocBin = 0
for m = 0 to numRows - 1
if array.get(binVols, m) > maxVol
maxVol := array.get(binVols, m)
pocBin := m
pocPrice := array.get(binPrices, pocBin)
// Calculate Value Area (70% by default)
float totalVPVol = array.sum(binVols)
float targetVol = totalVPVol * valueAreaPct / 100.0
float cumVol = array.get(binVols, pocBin)
int upperBin = pocBin
int lowerBin = pocBin
while cumVol < targetVol and (upperBin < numRows - 1 or lowerBin > 0)
float upVol = upperBin < numRows - 1 ? array.get(binVols, upperBin + 1) : 0.0
float downVol = lowerBin > 0 ? array.get(binVols, lowerBin - 1) : 0.0
if upVol >= downVol and upperBin < numRows - 1
upperBin += 1
cumVol += upVol
else if lowerBin > 0
lowerBin -= 1
cumVol += downVol
else
break
vahPrice := array.get(binPrices, upperBin)
valPrice := array.get(binPrices, lowerBin)
[pocPrice, vahPrice, valPrice]
[poc, vah, val] = calcVolumeProfile()
// === Signal Detection ===
// POC Bounce Signal
pocBounceBuy = ta.crossover(close, poc) and close > open
pocBounceSell = ta.crossunder(close, poc) and close < open
// VAH Breakout
vahBreakout = ta.crossover(close, vah) and volume > ta.sma(volume, 20) * 1.5
// VAL Breakdown
valBreakdown = ta.crossunder(close, val) and volume > ta.sma(volume, 20) * 1.5
// HVN Rejection (simplified: large range rejection at current value levels)
hvnRejectBuy = low <= poc and close > open and range > ta.sma(range, 20) * 1.3
hvnRejectSell = high >= poc and close < open and range > ta.sma(range, 20) * 1.3
// LVN Gap Fill Signal
lvnGap = math.abs(vah - val) < math.abs(vah - val) * 0.3
lvnSignal = lvnGap and close > vah and volume > ta.sma(volume, 20) * 2.0
// === Plotting ===
plot(showPOC ? poc : na, "POC", color=#FFC107, linewidth=2)
plot(showVA ? vah : na, "VAH", color=#42A5F5, linewidth=1, style=plot.style_circles)
plot(showVA ? val : na, "VAL", color=#42A5F5, linewidth=1, style=plot.style_circles)
fill(plot(showVA ? vah : na), plot(showVA ? val : na), color=color.new(#42A5F5, 92), title="Value Area")
// POC Bounce Labels
plotshape(pocBounceBuy, "POC Bounce Buy", shape.labelup, location.belowbar, color=color.new(#4CAF50, 30), text="POC B", textcolor=#4CAF50, size=size.tiny)
plotshape(pocBounceSell, "POC Bounce Sell", shape.labeldown, location.abovebar, color=color.new(#FF5252, 30), text="POC S", textcolor=#FF5252, size=size.tiny)
// VAH/VAL Breakout Labels
plotshape(vahBreakout, "VAH Breakout", shape.labelup, location.belowbar, color=color.new(#4CAF50, 30), text="VAH B/O", textcolor=#4CAF50, size=size.tiny)
plotshape(valBreakdown, "VAL Breakdown", shape.labeldown, location.abovebar, color=color.new(#FF5252, 30), text="VAL B/D", textcolor=#FF5252, size=size.tiny)
// HVN Rejection Labels
plotshape(hvnRejectBuy, "HVN Reject Buy", shape.arrowup, location.belowbar, color=#4CAF50, size=size.small)
plotshape(hvnRejectSell, "HVN Reject Sell", shape.arrowdown, location.abovebar, color=#FF5252, size=size.small)
// LVN Signal
plotshape(lvnSignal, "LVN Gap", shape.star, location.top, color=#E040FB, size=size.small)
// === Alerts ===
alertcondition(pocBounceBuy, "POC Bounce Buy", "Price bounced at POC - bullish signal")
alertcondition(pocBounceSell, "POC Bounce Sell", "Price rejected at POC - bearish signal")
alertcondition(vahBreakout, "VAH Breakout", "Price broke above VAH with volume")
alertcondition(valBreakdown, "VAL Breakdown", "Price broke below VAL with volume")Recommended Parameters for Volume Profile
Parameter settings tested across different market conditions and timeframes.
| Parameter | Default | Description |
|---|---|---|
| Lookback Period | 48 | Number of bars used to calculate the volume profile. Shorter values (20-30) work for intraday scalping on 5m charts. Longer values (100+) smooth the profile on daily timeframes. I use 48 on 15m ES charts for a clean daily profile. |
| Number of Rows | 24 | How many price bins to divide the range into. More rows = finer granularity but more noise. 24 rows balances detail with readability. For NQ which has wider price ranges, 36 rows gives better POC accuracy. |
| Value Area % | 70 | Percentage of total volume that defines the value area. Standard is 70%. Tighten to 65% for a narrower range in range-bound markets. Widen to 80% in trending markets to capture the full activity zone. |
| Show POC Line | true | Toggles the Point of Control horizontal line on the chart. Keep this on for all swing and intraday trading. It is the single most useful level from Volume Profile for identifying fair price. |
| Show Value Area | true | Shows VAH and VAL lines with shaded fill between them. The shaded zone helps you see the value area at a glance. I keep this on for day trading ES but turn it off on cluttered charts during news events. |
| Show HVN/LVN | true | Toggles high and low volume node markers. Useful for identifying support and resistance zones within the value area. On BTC 1h charts, I keep these on because the profile changes significantly session to session. |
Volume Profile + Pineify Invite-Only: Better Together
Volume Profile alone gives you one signal type. Pineify invite-only indicator combines Volume Profile with RSI divergences, MACD confirmation, and Supertrend filters in one overlay. Fewer charts, clearer signals.
Instead of switching between 6 different signals on separate charts, you get a single multi-confirmation setup.
See the Invite-Only IndicatorRelated Resources
FAQ
Volume Profile Signals FAQ
Stop juggling Volume Profile with 4 other charts
Pineify combines Volume Profile, RSI, MACD, and Supertrend into one invite-only indicator. One click setup.
Try Pineify Free