MMTMMT Docs
Data Sources

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?) -> number

Per-Level Accessors

volume.price(level, offset?) -> number
volume.buyVol(level, offset?) -> number
volume.sellVol(level, offset?) -> number

Structured Snapshot Access

volume.dataView(offset?) -> VolumeDataView
volume.data(offset?) -> VolumeDataView

Summary 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 | null

Rebucketing

volume.rebucket(opts, offset?) -> VolumeBuckets | null

Parameters:

  • offset?: optional bar offset on the VOLUME subscription clock
  • level: zero-based level index
  • minPrice, 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:

  • percent defaults to 70
  • 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 })
}

On this page