DocumentationVolume Profile

Volume Profile

A volume profile shows how much volume traded at each price rather than over time - a horizontal histogram that reveals high-volume nodes (acceptance) and low-volume gaps (rejection). Like Market Profile it comes in two pieces: computeVolumeProfileSessions (analytics, profile tier) and the VolumeProfile primitive that draws it.

import { computeVolumeProfileSessions, VolumeProfile } from 'openalgo-charts/profile';
 
const result = computeVolumeProfileSessions(bars, { tickSize: 0.05, session: 'composite' });
chart.addPrimitive(new VolumeProfile(result));

Variants

  • Visible-range - pass the currently visible slice of bars with session: 'composite'. One profile spanning the view.
  • Session - session: 'day' | 'week' | 'month' builds one profile per period (grouped by the IST calendar), each drawn under its own bars with its own POC and value area.

Every session reports a POC (highest-volume price), a Value Area (the band holding valueAreaPercent of volume), and - optionally - a buy/sell split.

Total volume

The default total mode draws one bar per price, anchored at the session’s right edge:

const chart = lib.createChart(el);
const bars = lib.generateBars(1700000000, 120, 1800);
chart.addSeries('candlestick').setData(bars);

const vp = lib.computeVolumeProfileSessions(bars, { tickSize: 1, session: 'composite' });
chart.addPrimitive(new lib.VolumeProfile(vp));

chart.timeScale.fitContent(bars.length);
return chart;
live
Rendering live chart…
Visible-range volume profile: POC (gold), value area highlighted, rows outside it dimmed.

Buy vs sell, and delta

displayMode: 'buySell' splits each row into buy and sell; 'delta' draws the net, colored by sign. Both use the direction-based split (below).

const chart = lib.createChart(el);
const bars = lib.generateBars(1700000000, 120, 1800);
chart.addSeries('candlestick').setData(bars);

const vp = lib.computeVolumeProfileSessions(bars, { tickSize: 1, session: 'composite' });
chart.addPrimitive(new lib.VolumeProfile(vp, { displayMode: 'buySell', width: 100 }));

chart.timeScale.fitContent(bars.length);
return chart;
live
Rendering live chart…
buySell mode: buy (teal) and sell (red) split per price.
const chart = lib.createChart(el);
const bars = lib.generateBars(1700000000, 120, 1800);
chart.addSeries('candlestick').setData(bars);

const vp = lib.computeVolumeProfileSessions(bars, { tickSize: 1, session: 'composite' });
chart.addPrimitive(new lib.VolumeProfile(vp, { displayMode: 'delta' }));

chart.timeScale.fitContent(bars.length);
return chart;
live
Rendering live chart…
delta mode: net buy-minus-sell per price, colored by sign.
⚠️

The buy/sell split is an honest approximation from OHLCV: a bar’s whole volume is counted as buying when it closed up (close >= open) and selling when it closed down. It is not true bid/ask delta - for that you need classified trades, see the Footprint. Set deltaFromBarDirection: false to keep volume un-split.

Session profiles

const chart = lib.createChart(el);
const bars = lib.generateBars(1700000000, 160, 1800);
chart.addSeries('candlestick').setData(bars);

const vp = lib.computeVolumeProfileSessions(bars, { tickSize: 1, session: 'day' });
chart.addPrimitive(new lib.VolumeProfile(vp, { side: 'right', width: 70 }));

chart.timeScale.fitContent(bars.length);
return chart;
live
Rendering live chart…
A separate volume profile per IST day, each with its own POC and value area.

computeVolumeProfileSessions options

computeVolumeProfileSessions(bars, options): VolumeProfileFamilyResult
OptionDefaultDescription
tickSize0.05price bucket size
session'composite''composite' / 'day' / 'week' / 'month'
valueAreaPercent0.7fraction of volume in the value area (0..1)
deltaFromBarDirectiontruesplit volume into buy/sell by bar direction

VolumeProfile primitive options

Constructor new VolumeProfile(result, options) or live profile.setOptions({ ... }).

OptionDefaultDescription
displayModetotaltotal / buySell / delta
siderightanchor bars at the session’s left or right edge
width90maximum bar length, px
barColorslatebar color in total mode
buyColor / sellColorteal / redbuySell and delta colors
opacity0.85bar opacity
showPoc / pocColor / showPocLabeltrue / gold / truePoint of Control line + label
showValueArea / vahColor / valColor / showValueAreaLabelstrueVAH & VAL lines + labels
highlightValueArea / valueAreaFillColor / valueAreaFillOpacitytrueshade the value-area band
valueAreaOpacityDim0.4opacity multiplier for rows outside the value area
labelSiderightwhich edge the POC/VA labels sit on
zOrderbottomdraw behind (bottom) or over (top) the series

Data model

interface VolumeProfileFamilyResult {
  sessions: VolumeProfileSessionResult[];
  options: VolumeProfileFamilyOptions;
}
 
interface VolumeProfileSessionResult {
  startTime: number; endTime: number;      // UTC seconds
  levels: { price: number; volume: number; buyVolume: number; sellVolume: number; delta: number }[]; // high -> low
  poc: number; vah: number; val: number;
  totalVolume: number; buyVolume: number; sellVolume: number; delta: number;
}

Troubleshooting

SymptomCauseFix
Nothing rendersNo price series (time axis has no bars)Add a series before the profile
Bars cover the candlesProfile anchored over the price actionLower width, set side: 'left', or zOrder: 'top' with lower opacity
buySell / delta look emptydeltaFromBarDirection: falseEnable it (default) so volume is split
One profile for many dayssession: 'composite'Use session: 'day' (or week / month)
Value area looks offvalueAreaPercent passed as a percentUse a fraction (0.7), not 70