Timeframes & tick charts
OpenAlgo Charts handles the full range of timeframes - from seconds and ticks up to weeks - because the time axis is a logical index, not a fixed grid.
Time labels default to Asia/Kolkata, the Indian-market default, and nothing more:
pass an IANA name to relabel for another market, at construction or at runtime.
createChart(el, { timezone: 'America/New_York' }) and chart.setTimezone('Europe/London')
both drive the time-axis ticks and the crosshair pill. See Timezones.
A timeFormatter (UTC seconds -> string) is still there for a host that wants to format
labels itself, and it outranks the zone.
There are two sources of bars:
- Historical bars come from your data feed at a chosen interval (
5s,1m,1h,D,W, …). The chart just draws them. - Tick, volume, and sub-minute bars are aggregated live from a trade/quote stream
using
TickBarAggregatororCandleBuilder- OHLCV history alone cannot produce them.
History intervals
The OpenAlgo REST adapter passes the interval through verbatim, so any interval your broker supports works. Fetch the exact list at runtime instead of hard-coding it:
// OpenAlgo exposes the supported intervals per broker:
// seconds: 5s, 10s, 15s, 30s, 45s, 60s ...
// minutes: 1m, 3m, 5m, 10m, 15m, 30m ...
// hours: 1h, 2h, 4h ...
// days+: D, W, M
const bars = await feed.getBars({
symbol: 'RELIANCE', exchange: 'NSE', interval: '5s',
from: dayStartUtcSeconds, to: nowUtcSeconds,
});
series.setData(bars);The time axis automatically switches to HH:MM:SS labels when the visible bars are less than a minute apart, and the crosshair tag shows seconds on sub-minute bars - so a 5-second chart reads correctly without any configuration.
An interval code resolves through a registry, and an unrecognised code throws rather
than quietly meaning one minute. The built-in grammar covers s, m, h, d and w and
is case-insensitive, so a bare M is a minute: register a calendar interval if your
broker’s M means a month, and register 1Q, T500 or V10K before you use them. See
Custom Intervals.
To branch on the timeframe (does this need a session reset, does the axis need seconds), ask
the registry rather than matching on the string. intervalParts('120m') and
intervalParts('2h') both answer 2 hours, and isIntradayInterval, isDailyInterval,
isSecondsInterval and isTickInterval answer the yes-or-no questions directly, for any
registered code and not only for the built-in tokens. See
Reading a code back.
Second timeframes (live)
CandleBuilder buckets a tick stream into interval OHLC. intervalSec can be any number of
seconds - here, 5-second candles. Pass a sessionAnchorSec so buckets align to the session
open (09:15) rather than an arbitrary epoch floor.
View example code
const chart = lib.createChart(el);
const series = chart.addSeries('candlestick');
// Build 5-second candles from a simulated tick stream.
const builder = new lib.CandleBuilder({ intervalSec: 5, volumeMode: 'ltq-sum' });
const bars = [];
let t = 1700000000, p = 100, seed = 99;
for (let i = 0; i < 3000; i++) {
seed = (seed * 1103515245 + 12345) & 2147483647;
p = Math.max(1, p + (seed / 2147483647 - 0.5) * 0.4);
t += 1; // one tick per second
const u = builder.onTick({ time: t, price: p, ltq: 10 });
if (u) { if (u.isNew) bars.push(u.bar); else bars[bars.length - 1] = u.bar; }
}
series.setData(bars);
chart.timeScale.fitContent(bars.length);
return chart;Tick bars
TickBarAggregator makes bars from trade ticks by clock interval, calendar period,
tick count, or traded volume:
import { TickBarAggregator } from 'openalgo-charts';
const agg = new TickBarAggregator({ mode: 'ticks', count: 100 }); // 100-tick bars
// or { mode: 'volume', perBar: 5000 } - constant-volume bars
// or { mode: 'interval', seconds: 30 } - 30-second bars
// or { mode: 'calendar', unit: 'month' } - months, quarters and years, which have no
// fixed length; pass { timezone } so the boundary is local midnight where it should be
ws.onTrade((t) => {
const u = agg.onTick({ time: t.timeSec, price: t.price, qty: t.qty });
if (u.isNew) series.setData([...bars, u.bar]); // append
else series.update(u.bar); // mutate the forming bar
});Here is a 250-tick chart built from a simulated trade stream:
View example code
const chart = lib.createChart(el);
const series = chart.addSeries('candlestick');
const agg = new lib.TickBarAggregator({ mode: 'ticks', count: 250 });
const bars = [];
let t = 1700000000, p = 100, seed = 3;
for (let i = 0; i < 12000; i++) {
seed = (seed * 1103515245 + 12345) & 2147483647;
p = Math.max(1, p + (seed / 2147483647 - 0.5) * 0.6);
t += 1;
const u = agg.onTick({ time: t, price: p, qty: 1 });
if (u.isNew) bars.push(u.bar); else bars[bars.length - 1] = u.bar;
}
series.setData(bars);
chart.timeScale.fitContent(bars.length);
return chart;Tick-count and volume bars require real trade ticks. A 1-minute OHLCV history cannot be re-bucketed into them - you need a tick feed (or a tick-recording backend). Bid/ask classification for footprint / order flow needs the same.