Skip to content

Order flow

Volume profile and market profile

Visible-range, fixed-range and per-session profiles with point of control and value area, plus a TPO letter profile.

Volume profile and market profile@ortex-charts/financial
Loading volume profile and market profile
Visible-range, fixed-range and per-session profiles with point of control and value area, plus a TPO letter profile.
volume-profile.ts
import { createFinancialChart, footprintFromTicks, type ProfileKind, type ProfileMode } from "@ortex-charts/financial";
import { parseResolution, ticksToBars, type Bar, type Tick } from "@ortex-charts/math";

const RESOLUTION = parseResolution("15");
const TICK = 0.05;
const bars = ticksToBars(prints, RESOLUTION, TIME_ZONE);
// The aggressor split is derived for this demonstration; a feed that reports
// it makes both the profile and its buy/sell halves exact.
const flow = footprintFromTicks(prints, RESOLUTION, TICK, TIME_ZONE);

const chart = createFinancialChart(box, {
    theme,
    timeZone: TIME_ZONE,
    resolution: "15",
    data: bars,
    volume: false,
    seriesOptions: { priceFormat: { type: "price", precision: 2, minMove: 0.01 } },
});

const profile = chart.addVolumeProfile({
    mode: "visible",
    tickSize: TICK,
    splitDelta: true,
    showPoc: true,
    showValueArea: true,
    valueArea: 0.7,
    width: 0.32,
});

// Attaching the order flow is what turns an estimated profile into an exact
// one: every trade lands in the row that holds its price, and the buy and
// sell halves of each row are counted rather than inferred from the close.
profile.setFlow(flow);

/** Profiles are computed while drawing, so read them after the frame has painted. */
function report(): void {
    const first = profile.profiles()[0];
    if (!first || first.poc < 0) return status("No bars in range.");
    const poc = first.rows[first.poc];
    const va = `${first.rows[first.vaLow].lo.toFixed(2)} to ${first.rows[first.vaHigh].hi.toFixed(2)}`;
    const count = profile.profiles().length;
    status(
        `${count} profile${count === 1 ? "" : "s"}, ${first.rows.length} rows   Point of control ${poc.lo.toFixed(2)}   Value area ${va}   ${first.exact ? "exact" : "estimated"}`,
    );
}