What is Volume Profile?
Volume Profile is an advanced charting indicator that displays trading activity over a specified price range during a specified period. It shows the total volume traded at each price level, often represented as a horizontal histogram on the left or right side of the price chart. Unlike traditional volume indicators that show total volume traded over a specific time period (e.g., a bar), Volume Profile reveals *where* that volume was traded across different price points.
This insight into the distribution of volume provides a deeper understanding of market dynamics and participant behavior. Key components derived from the Volume Profile include:
- Point of Control (POC): The price level with the highest traded volume for the specified period. It represents the price where the most trading activity occurred and is considered a fair value area.
- Value Area (VA): The price range where a significant percentage of the total volume (typically 70% or 68%) was traded. It signifies where the majority of participants found value.
- High Volume Nodes (HVN): Price levels where a large amount of volume was traded, indicating areas of agreement or consolidation. These often act as strong support or resistance.
- Low Volume Nodes (LVN): Price levels where very little volume was traded, indicating areas of disagreement or rapid price movement. These often act as weak support/resistance and tend to be easily broken through.
Volume Profile is an indispensable tool for active traders, helping them identify key supply/demand zones, understand market sentiment, and plan their pine script strategies for entries, exits, and risk management.
Components and Calculation (Conceptual)
The Volume Profile is constructed by taking all the trades (volume) that occurred within a defined time window (e.g., a day, a week, or a fixed number of bars) and categorizing them into discrete price "bins" or levels. For each bin, the total volume traded at that price level is accumulated. This accumulation is then displayed as a horizontal bar, with longer bars indicating more volume traded at that price. The calculation conceptually involves:
- Define the Analysis Period: This can be a specific session (e.g., daily, weekly) or a fixed number of bars (e.g., last 100 bars).
- Determine Price Range: Identify the high and low prices within the analysis period.
- Define Bins: Divide the price range into a specified number of equal price "bins." For example, if the range is $10 and you want 10 bins, each bin would be $1 wide.
- Distribute Volume: For each bar within the analysis period, distribute its volume across the price bins that its `high`-`low` range covers. If a bar's `high` is in one bin and its `low` in another, its volume is proportionally distributed. Many implementations simply assign the bar's entire volume to the bin corresponding to its `close` price, or use a more complex mid-point distribution.
- Aggregate Volume per Bin: Sum up the volume for each price bin.
- Identify POC, VA, HVN, LVN: Once the volume distribution is complete, the POC is the bin with the highest volume. The Value Area is found by accumulating volume from the POC outwards until the specified percentage (e.g., 70%) of total volume is reached. HVNs are visually prominent large bars, and LVNs are visually prominent small bars or gaps.
Basic Volume Profile Implementation in Pine Script
Pine Script v5 significantly simplifies Volume Profile implementation with its dedicated `volume` module. It provides functions like `volume.profile_fixed()` and `volume.profile_session()` to draw these profiles directly on the chart.
//@version=5
indicator("My Volume Profile", overlay=true, max_bars_back=500) // overlay=true to plot on price chart.
// --- User Inputs ---
profileType = input.string("Fixed Range", title="Profile Type", options=["Fixed Range", "Session Profile"])
fixedRangeBars = input.int(100, title="Fixed Range Bars (for Fixed Range Profile)", minval=10, maxval=500, tooltip="Number of historical bars to calculate the fixed volume profile over.")
numberOfRows = input.int(20, title="Number of Rows (Bins)", minval=5, maxval=100, tooltip="Number of price bins for the volume profile histogram.")
valueAreaPercentage = input.int(70, title="Value Area (%)", minval=50, maxval=99, tooltip="Percentage of total volume contained within the Value Area.")
// --- Plotting Colors ---
upVolumeColor = input.color(color.new(color.lime, 40), title="Up Volume Color")
downVolumeColor = input.color(color.new(color.red, 40), title="Down Volume Color")
pocColor = input.color(color.new(color.purple, 0), title="POC Color")
vaColor = input.color(color.new(color.yellow, 60), title="Value Area Color")
// --- Implement Volume Profile Logic ---
if profileType == "Fixed Range"
// Use volume.profile_fixed for a profile calculated over a fixed number of recent bars.
profile = volume.profile_fixed(fixedRangeBars, numberOfRows, valueAreaPercentage)
if barstate.islast and not na(profile)
profile.plot(upVolumeColor, downVolumeColor, pocColor, vaColor)
else if profileType == "Session Profile"
profile = volume.profile_session(numberOfRows, valueAreaPercentage)
if not na(profile)
profile.plot(upVolumeColor, downVolumeColor, pocColor, vaColor)
// Note: Pine Script's built-in `volume` module handles the complex drawing
// of the histogram, POC line, and Value Area shading automatically.
// We just need to define the parameters and tell it to plot.
Practical Volume Profile Trading Strategies
1. Support and Resistance with HVNs & LVNs
HVNs act as strong areas of agreement and potential support/resistance, while LVNs represent areas of rapid transit and weak support/resistance.
- HVN as Support/Resistance: When price approaches an HVN, it's likely to consolidate or reverse as significant past trading activity suggests strong conviction at that level. Long entries near an HVN acting as support; short entries near an HVN acting as resistance.
- LVN as Price Magnet/Breakout: Price tends to move quickly through LVNs because there was little prior agreement. An LVN can act as a "price magnet" when price approaches it, or a zone where breakouts are likely to accelerate.
//@version=5
strategy("VP: HVN/LVN Strategy", overlay=true)
// Use a session profile for clear daily levels
numberOfRows = input.int(30, title="Number of Rows (Bins)", minval=5, maxval=100)
valueAreaPercentage = input.int(70, title="Value Area (%)", minval=50, maxval=99)
profile = volume.profile_session(numberOfRows, valueAreaPercentage)
// Plotting (kept for visual context, usually this is in a separate indicator script)
if not na(profile)
profile.plot(
color.new(color.lime, 40),
color.new(color.red, 40),
color.new(color.purple, 0),
color.new(color.yellow, 60)
)
// Example strategy logic (conceptual, as Pine Script strategy cannot directly access historical HVN/LVN)
// The `volume.profile_session` only returns the current session's profile.
// To get previous session's POC/VA, use request.security + profile_fixed
if not na(profile) and barstate.isconfirmed
pocPrice = profile.poc_price
// Simple strategy: Price crosses POC
longCondition = ta.crossover(close, pocPrice)
shortCondition = ta.crossunder(close, pocPrice)
if longCondition
strategy.entry("Long POC Break", strategy.long)
if shortCondition
strategy.entry("Short POC Break", strategy.short)
// Exit on opposite POC cross
strategy.close("Long POC Break", when=shortCondition)
strategy.close("Short POC Break", when=longCondition)
2. Value Area (VA) as Fair Price Zone
The Value Area represents where the majority of trades occurred and where market participants found "fair value."
- Trading within Value Area: Price tends to spend a significant amount of time within the Value Area. If price opens within the VA, it suggests a rotational or range-bound day.
- Opening outside Value Area: If price opens significantly outside the previous day's Value Area (and especially outside the Value Area High/Low), it often suggests a trending day, as the market is seeking a new fair value.
- Open above VAH (Value Area High): Strong bullish bias, target higher prices.
- Open below VAL (Value Area Low): Strong bearish bias, target lower prices.
- VA as Support/Resistance: The Value Area High (VAH) and Value Area Low (VAL) act as dynamic support and resistance levels.
//@version=5
strategy("VP: Value Area Strategy", overlay=true)
numberOfRows = input.int(30, title="Number of Rows (Bins)", minval=5, maxval=100)
valueAreaPercentage = input.int(70, title="Value Area (%)", minval=50, maxval=99)
profile = volume.profile_session(numberOfRows, valueAreaPercentage)
// Plotting
if not na(profile)
profile.plot(
color.new(color.lime, 40),
color.new(color.red, 40),
color.new(color.purple, 0),
color.new(color.yellow, 60)
)
// Store previous session VAH/VAL manually
var float prevVAH = na
var float prevVAL = na
isNewSession = ta.change(time("D"))
if isNewSession[1] and not na(profile[1])
prevVAH := profile[1].value_area_high
prevVAL := profile[1].value_area_low
prevVAH := nz(prevVAH[1], prevVAH)
prevVAL := nz(prevVAL[1], prevVAL)
if not na(prevVAH) and not na(prevVAL)
// Absorption entries
longAbsorption = open < prevVAL and close > prevVAL
shortAbsorption = open > prevVAH and close < prevVAH
if (longAbsorption)
strategy.entry("Long VA Absorb", strategy.long)
strategy.exit("Long VA Absorb Exit", profit=prevVAH, stop=prevVAL - syminfo.mintick * 10)
if (shortAbsorption)
strategy.entry("Short VA Absorb", strategy.short)
strategy.exit("Short VA Absorb Exit", profit=prevVAL, stop=prevVAH + syminfo.mintick * 10)
// Trend continuation entries
longTrendDay = open > prevVAH and close > open and close > prevVAH
shortTrendDay = open < prevVAL and close < open and close < prevVAL
if (longTrendDay)
strategy.entry("Long VA Trend", strategy.long)
strategy.exit("Long VA Trend Exit", profit=strategy.position_avg_price + (prevVAH - prevVAL) * 1.5, stop=prevVAH)
if (shortTrendDay)
strategy.entry("Short VA Trend", strategy.short)
strategy.exit("Short VA Trend Exit", profit=strategy.position_avg_price - (prevVAH - prevVAL) * 1.5, stop=prevVAL)
3. POC Rejection/Breakout
The Point of Control (POC) is the single most traded price level. It acts as a significant magnet and a strong area of support/resistance.
- POC Rejection: Price rallies towards the POC and then reverses, suggesting strong supply at POC. Or declines to POC and reverses, suggesting strong demand. Often seen on less volatile days.
- POC Breakout: Price decisively breaks and holds above/below the POC, often indicating a shift in fair value and potential trend continuation. A breakout of POC, especially with increased volume, is a strong signal that market participants are accepting higher/lower prices.
//@version=5
strategy("VP: POC Strategy", overlay=true)
numberOfRows = input.int(30, title="Number of Rows (Bins)", minval=5, maxval=100)
valueAreaPercentage = input.int(70, title="Value Area (%)", minval=50, maxval=99)
profile = volume.profile_session(numberOfRows, valueAreaPercentage)
// Plotting
if not na(profile)
profile.plot(
color.new(color.lime, 40),
color.new(color.red, 40),
color.new(color.purple, 0),
color.new(color.yellow, 60)
)
// Get POC from previous session
var float prevPOC = na
isNewSession = ta.change(time("D"))
if isNewSession[1] and not na(profile[1])
prevPOC := profile[1].poc_price
prevPOC := nz(prevPOC[1], prevPOC)
// Strategy Logic
if not na(prevPOC)
// Rejection logic
longPOCRejection = low < prevPOC and close > prevPOC and close[1] < prevPOC[1]
shortPOCRejection = high > prevPOC and close < prevPOC and close[1] > prevPOC[1]
if (longPOCRejection)
strategy.entry("Long POC Rejection", strategy.long)
strategy.exit(
"Long POC Rejection Exit",
profit=prevPOC + (prevPOC - open) * 1.0,
stop=prevPOC - (prevPOC - low) * 1.0
)
if (shortPOCRejection)
strategy.entry("Short POC Rejection", strategy.short)
strategy.exit(
"Short POC Rejection Exit",
profit=prevPOC - (open - prevPOC) * 1.0,
stop=prevPOC + (high - prevPOC) * 1.0
)
// Breakout logic
longPOCBreakout = close > prevPOC and close[1] <= prevPOC[1] and volume > ta.sma(volume, 20) * 1.2
shortPOCBreakout = close < prevPOC and close[1] >= prevPOC[1] and volume > ta.sma(volume, 20) * 1.2
if (longPOCBreakout)
strategy.entry("Long POC Breakout", strategy.long)
strategy.exit(
"Long POC Breakout Exit",
profit=strategy.position_avg_price + (high - prevPOC) * 1.5,
stop=prevPOC
)
if (shortPOCBreakout)
strategy.entry("Short POC Breakout", strategy.short)
strategy.exit(
"Short POC Breakout Exit",
profit=strategy.position_avg_price - (prevPOC - low) * 1.5,
stop=prevPOC
)
Optimizing Volume Profile Performance
To get the most from Volume Profile in Pine Script:
- Contextual Analysis: Volume Profile is best used in conjunction with price action and overall market context. Understand the broader trend before trading individual VP levels.
- Timeframe Selection: The chosen `profileType` ("Fixed Range" vs. "Session Profile") and the chart's timeframe greatly impact the profile's relevance. Daily session profiles are excellent for intraday decisions, while fixed profiles over longer periods can highlight significant longer-term supply/demand zones.
- Number of Rows (Bins): Experiment with the `numberOfRows`. Too few bins can make the profile too coarse, missing subtle nuances. Too many can make it overly detailed and noisy. Start with 20-30 and adjust.
- Value Area Percentage: The default 70% is common, but some traders prefer 68% or other percentages depending on their focus (e.g., tighter VA for strong agreement).
- Confluence with Other Indicators: Volume Profile levels (POC, VAH/VAL, HVN/LVN) gain significant strength when they align with other technical indicators like:
- Moving Averages
- Fibonacci Retracements/Extensions
- Trendlines
- Psychological price levels
- Volume Confirmation: Always seek confirmation from volume. A breakout of a key level with strong, increasing volume is more reliable than a weak breakout.
- Market Open/Close Behavior: Pay attention to how price reacts to the previous session's POC and Value Area boundaries at the market open and near the close.
- Fixed vs. Session Profile: Understand when to use each. `volume.profile_session` is for recurring periods (e.g., daily) while `volume.profile_fixed` is for analyzing a specific range of bars, useful for studying reactions to news events or specific trend segments.
Common Volume Profile Pitfalls
- Lagging Nature: Volume Profile is a lagging indicator. It shows where volume *has been* traded, not where it *will* be traded. Use it for confirmation and understanding market structure, not as a standalone predictive tool.
- False Signals: Price can temporarily penetrate or "fake out" around key Volume Profile levels, especially in low-liquidity markets or during news events. Confirmation from price action and other indicators is essential.
- Over-Reliance: Using Volume Profile as the sole decision-making tool without considering the broader market context, fundamental news, or other technical analysis can lead to poor trading decisions.
- Data Quality: The accuracy of Volume Profile is highly dependent on the quality and granularity of volume data. Tick volume is more precise but not always available.
- Visual Clutter: With too many profiles or too many rows, the chart can become overly cluttered and difficult to read. Keep settings clean and focused.
- Dynamic Nature in Strategies: Implementing strategies based on *previous* session's POC/VAH/VAL can be tricky in Pine Script because `volume.profile_session` only provides the *current* session's data. You often need `request.security` to fetch previous session data, which can add complexity.
Conclusion
Volume Profile is an exceptionally powerful and insightful technical analysis tool available in Pine Script for TradingView. By providing a clear visualization of trading activity across different price levels, it allows traders to identify key areas of supply and demand, understand market conviction, and pinpoint significant support and resistance zones. Mastering its components – the Point of Control (POC), Value Area (VA), High Volume Nodes (HVN), and Low Volume Nodes (LVN) – can significantly enhance your pine script strategies. While requiring careful consideration of its settings and integration with other technical analysis, Volume Profile provides a unique "x-ray" view into market structure, helping you make more informed and robust trading decisions by understanding where the true battle between buyers and sellers took place.