Volume Profile
Volume profile snapshots with native summary, range, POC, value area, and rebucketing helpers.
data.VOLUME exposes a price-by-price volume profile for the subscribed feed.
data.VOLUME supports aggregated exchange strings such as "binancef:bybitf".
data.VOLUME uses the non-BOOK plan limit: 10,000 retained bars on Free, 20,000 on Pro.
const volume = subscribe(data.VOLUME)Functions
Snapshot Metadata
volume.unix(offset?) -> number
volume.binSize(offset?) -> number
volume.numLevels(offset?) -> numberPer-Level Accessors
volume.price(level, offset?) -> number
volume.buyVol(level, offset?) -> number
volume.sellVol(level, offset?) -> numberStructured Snapshot Access
volume.dataView(offset?) -> VolumeDataView
volume.data(offset?) -> VolumeDataViewSummary and Range Helpers
volume.summary(offset?) -> VolumeSummary | null
volume.range(minPrice, maxPrice, offset?) -> VolumeRange | null
volume.rangeMany(requests, offset?) -> Array<VolumeRange | null>POC and Value Area Helpers
volume.poc(offset?) -> VolumePoc | null
volume.poc(opts, offset?) -> VolumePoc | null
volume.valueArea() -> VolumeValueArea | null
volume.valueArea(percent, offset?) -> VolumeValueArea | null
volume.valueArea(opts, offset?) -> VolumeValueArea | null
volume.valueArea(percent, opts, offset?) -> VolumeValueArea | nullRebucketing
volume.rebucket(opts, offset?) -> VolumeBuckets | nullParameters:
offset?: optional bar offset on the VOLUME subscription clocklevel: zero-based level indexminPrice,maxPrice: inclusive price range bounds
Guard Native Helper Results
summary(), range(), rangeMany(), poc(), valueArea(), and rebucket() can return null. For example, volume.poc() returns null when the current slot is missing. Always check the return value before reading fields like .price, .lowPrice, or .totals.
dataView() / data()
// VolumeDataView
{
unix: number,
binSize: number,
buys: Float64Array,
sells: Float64Array,
prices: Float64Array
}data() is an alias of dataView().
For out-of-range offsets, dataView(offset?) returns:
{
unix: NaN,
binSize: NaN,
buys: new Float64Array(0),
sells: new Float64Array(0),
prices: new Float64Array(0)
}summary()
volume.summary(offset?) -> VolumeSummary | null{
unix: number,
binSize: number,
levels: number,
minPrice: number,
maxPrice: number,
buy: number,
sell: number,
total: number,
delta: number,
ratio: number
}range() and rangeMany()
volume.range(minPrice, maxPrice, offset?) -> VolumeRange | null
volume.rangeMany(requests, offset?) -> Array<VolumeRange | null>// requests[i]
{
minPrice: number,
maxPrice: number
}
// VolumeRange
{
unix: number,
binSize: number,
levels: number,
fromPrice: number,
toPrice: number,
buy: number,
sell: number,
total: number,
delta: number,
ratio: number
}range() and rangeMany() include levels where minPrice <= price <= maxPrice.
poc()
volume.poc(offset?) -> VolumePoc | null
volume.poc(opts, offset?) -> VolumePoc | null// opts
{
minPrice?: number,
maxPrice?: number,
basis?: "total" | "buy" | "sell" | "deltaAbs"
}
// VolumePoc
{
unix: number,
price: number,
index: number,
buy: number,
sell: number,
total: number,
delta: number,
ratio: number
}valueArea()
volume.valueArea() -> VolumeValueArea | null
volume.valueArea(percent, offset?) -> VolumeValueArea | null
volume.valueArea(opts, offset?) -> VolumeValueArea | null
volume.valueArea(percent, opts, offset?) -> VolumeValueArea | null// opts
{
minPrice?: number,
maxPrice?: number,
basis?: "total" | "buy" | "sell" | "deltaAbs"
}
// VolumeValueArea
{
unix: number,
pocPrice: number,
lowPrice: number,
highPrice: number,
levels: number,
buy: number,
sell: number,
total: number,
delta: number,
ratio: number
}Notes:
percentdefaults to70- expansion starts from the POC
- ties break toward the lower price for deterministic output
rebucket()
volume.rebucket(opts, offset?) -> VolumeBuckets | null// choose exactly one
{ bucketCount: number, minPrice?: number, maxPrice?: number }
{ levelsPerBucket: number, minPrice?: number, maxPrice?: number }
// VolumeBuckets
{
unix: number,
sourceBinSize: number,
prices: Float64Array,
buys: Float64Array,
sells: Float64Array,
totals: Float64Array,
deltas: Float64Array
}rebucket() groups contiguous source levels by index rather than interpolating arbitrary price widths.
Example
//@version=2
indicator("Volume Profile Levels", false)
const volume = subscribe(data.VOLUME)
function onBar(index) {
const summary = volume.summary()
const poc = volume.poc()
const valueArea = volume.valueArea()
if (!summary || !poc || !valueArea) return
plotHistogram("Profile Delta", summary.delta, {
color: summary.delta >= 0 ? color.teal : color.orange
})
plot("POC", poc.price, { color: color.white, forceOverlay: true })
plot("VA Low", valueArea.lowPrice, {
color: color.green,
forceOverlay: true
})
plot("VA High", valueArea.highPrice, {
color: color.red,
forceOverlay: true
})
}Dynamic rangeMany() Example
//@version=2
indicator("Volume Windows Around POC", false)
const volume = subscribe(data.VOLUME)
function onBar(index) {
const summary = volume.summary()
const poc = volume.poc()
const step = volume.binSize()
if (!summary || !poc || !(step > 0)) return
const lowerMin = Math.max(summary.minPrice, poc.price - step * 10)
const lowerMax = poc.price - step
const upperMin = poc.price + step
const upperMax = Math.min(summary.maxPrice, poc.price + step * 10)
if (lowerMin > lowerMax || upperMin > upperMax) return
const bands = volume.rangeMany([
{ minPrice: lowerMin, maxPrice: lowerMax },
{ minPrice: upperMin, maxPrice: upperMax }
])
if (!bands[0] || !bands[1]) return
plotHistogram("Below POC Delta", bands[0].delta, { color: color.teal })
plotHistogram("Above POC Delta", bands[1].delta, { color: color.orange })
}