The volume_profile source carries a variable number of price-level buckets per bar — each bucket is [priceLow, priceHigh, buyVol, sellVol]. Because the bucket count changes from bar to bar, the source has no scalar properties; you can't read .buy / .sell off it directly. Instead, use these accessor functions to pull scalar timeseries out of the profile.
Data structure
Each bar of a volume_profile timeseries is a row shaped like:
[ timestamp, [priceLow, priceHigh, buyVol, sellVol], [priceLow, priceHigh, buyVol, sellVol], … ]
- Slot
0is the bar timestamp. - Every later slot is one price-level bucket:
[priceLow, priceHigh, buyVol, sellVol]. - The number of buckets varies per bar — it depends on the bar's price range and
ticksPerBar.
For scalar values, prefer the vp* accessors below. To iterate the buckets yourself — e.g. to draw one marker or pie per price level with plotBatches — read the raw row directly: vpa[0] is the current bar's row, and vpa[0][i + 1] is the i-th bucket (slot 0 is the timestamp):
timeseries vpa = volume_profile(symbol=currentSymbol, exchange=currentExchange);
func drawBucket(i) {
var bucket = vpa[0][i + 1]; // [priceLow, priceHigh, buyVol, sellVol]
var price = (bucket[0] + bucket[1]) / 2; // bucket midprice
var buyVol = bucket[2];
var sellVol = bucket[3];
plotPie(value=[buyVol, sellVol], price=price, radius=8, colors=["#22c55e", "#ef4444"], display="none");
}
plotBatches(vpBucketCount(vpa), drawBucket);Accessor functions
Open the source first, then pass it to any accessor. Besides the required symbol and exchange, it accepts an optional ticksPerBar (default 1) that merges every N price levels into one bucket — fewer, wider buckets, which lowers vpBucketCount — and an optional currency ("USD" or "Coin", default "Coin") that quotes each bucket's volume in USD (dollar notional) instead of coins (base-asset units), mirroring the Volume Footprint indicator's currency toggle:
timeseries vpa = volume_profile(symbol=currentSymbol, exchange=currentExchange);
var totalBuy = vpBuy(vpa);
var totalSell = vpSell(vpa);
var poc = vpPoc(vpa);
// Optional: coarsen the ladder (merge every 5 price levels into one bucket)
timeseries vpaCoarse = volume_profile(symbol=currentSymbol, exchange=currentExchange, ticksPerBar=5);
// Optional: quote bucket volume in USD (dollar notional) instead of coins
timeseries vpaUsd = volume_profile(symbol=currentSymbol, exchange=currentExchange, currency="USD");| Function | Description |
|---|---|
vpBuy | Total buy volume across all price buckets at the bar |
vpSell | Total sell volume across all price buckets at the bar |
vpDelta | Net buy/sell delta (vpBuy − vpSell) at the bar |
vpTotal | Combined buy + sell volume across all buckets at the bar |
vpPoc | Point of Control — price of the highest-volume bucket |
vpPocVolume | Combined volume at the POC bucket |
vpBucketCount | Number of price-level buckets at the bar |
vpPriceHigh | Highest price covered by the profile at the bar |
vpPriceLow | Lowest price covered by the profile at the bar |
vpBuy
vpBuy(source: TimeSeries): number — total buy volume summed across all price-level buckets at the current bar.
| Parameter | Type | Description |
|---|---|---|
source | TimeSeries | A volume_profile timeseries |
Returns: number — total buy volume at this bar.
timeseries vpa = volume_profile(symbol=currentSymbol, exchange=currentExchange);
timeseries totalBuy = vpBuy(vpa);
plotLine(value=totalBuy, colors=["#26a69a"], width=2, label=["Total Buy"], desc=["Sum of buy volume per bar"]);vpSell
vpSell(source: TimeSeries): number — total sell volume summed across all price-level buckets at the current bar.
| Parameter | Type | Description |
|---|---|---|
source | TimeSeries | A volume_profile timeseries |
Returns: number — total sell volume at this bar.
timeseries vpa = volume_profile(symbol=currentSymbol, exchange=currentExchange);
timeseries totalSell = vpSell(vpa);
plotLine(value=totalSell, colors=["#ef5350"], width=2, label=["Total Sell"], desc=["Sum of sell volume per bar"]);vpDelta
vpDelta(source: TimeSeries): number — net buy/sell delta at the current bar (vpBuy − vpSell). Positive = buy dominant, negative = sell dominant.
| Parameter | Type | Description |
|---|---|---|
source | TimeSeries | A volume_profile timeseries |
Returns: number — buy minus sell volume at this bar.
timeseries vpa = volume_profile(symbol=currentSymbol, exchange=currentExchange);
timeseries delta = vpDelta(vpa);
plotBar(value=delta, colors=["#26a69a", "#ef5350"], label=["Delta"], desc=["Net buy/sell pressure"]);vpTotal
vpTotal(source: TimeSeries): number — total volume (buy + sell) summed across all buckets at the current bar.
| Parameter | Type | Description |
|---|---|---|
source | TimeSeries | A volume_profile timeseries |
Returns: number — combined buy + sell volume at this bar.
timeseries vpa = volume_profile(symbol=currentSymbol, exchange=currentExchange);
timeseries total = vpTotal(vpa);
plotLine(value=total, colors=["#9e9e9e"], width=2, label=["Total"], desc=["Combined volume"]);vpPoc
vpPoc(source: TimeSeries): number — Point of Control: the midprice of the bucket with the highest combined buy + sell volume at the current bar.
| Parameter | Type | Description |
|---|---|---|
source | TimeSeries | A volume_profile timeseries |
Returns: number — POC price (NaN if no buckets at this bar).
timeseries vpa = volume_profile(symbol=currentSymbol, exchange=currentExchange);
timeseries poc = vpPoc(vpa);
plotLine(value=poc, colors=["#ff9800"], width=2, label=["POC"], desc=["Point of Control"]);vpPocVolume
vpPocVolume(source: TimeSeries): number — combined buy + sell volume at the POC bucket (the bucket with the highest combined volume).
| Parameter | Type | Description |
|---|---|---|
source | TimeSeries | A volume_profile timeseries |
Returns: number — volume at the POC bucket.
timeseries vpa = volume_profile(symbol=currentSymbol, exchange=currentExchange);
timeseries pocVol = vpPocVolume(vpa);vpBucketCount
vpBucketCount(source: TimeSeries): number — number of price-level buckets present at the current bar.
| Parameter | Type | Description |
|---|---|---|
source | TimeSeries | A volume_profile timeseries |
Returns: number — count of price buckets at this bar.
timeseries vpa = volume_profile(symbol=currentSymbol, exchange=currentExchange);
timeseries depth = vpBucketCount(vpa);vpPriceHigh
vpPriceHigh(source: TimeSeries): number — highest priceHigh across all buckets at the current bar (top of the volume-profile range).
| Parameter | Type | Description |
|---|---|---|
source | TimeSeries | A volume_profile timeseries |
Returns: number — highest price covered by the profile (NaN if empty).
timeseries vpa = volume_profile(symbol=currentSymbol, exchange=currentExchange);
timeseries top = vpPriceHigh(vpa);vpPriceLow
vpPriceLow(source: TimeSeries): number — lowest priceLow across all buckets at the current bar (bottom of the volume-profile range).
| Parameter | Type | Description |
|---|---|---|
source | TimeSeries | A volume_profile timeseries |
Returns: number — lowest price covered by the profile (NaN if empty).
timeseries vpa = volume_profile(symbol=currentSymbol, exchange=currentExchange);
timeseries bottom = vpPriceLow(vpa);Best Practices
volume_profile source has no scalar properties — reading .buy / .sell directly will not work. Pull every value through the vp* accessors.vpPoc with vpPocVolume to gauge how dominant that level is.vpDelta summarizes net aggressor flow per bar. Sustained positive delta signals buy-side control; sustained negative delta signals sell-side control.