Skip to main content
Skip to main content

Data model

The chart does not read your database directly. It expects data in a few simple shapes. If your API returns these fields, everything else tends to work.

Loading chart…
Each bar on this chart is one Candle object — six numbers and a timestamp.

The four building blocks

ConceptOne-line meaning
CandleOne bar of history (open, high, low, close)
TickOne live price update
IntervalHow long each candle lasts (1h, 1d, …)
InstrumentSymbol info (name, decimals, available timeframes)

You use candles + interval for history. Ticks for live updates. Instrument for labels and formatting.


Candle — one bar on the chart

A candle is a single time slice — like “what happened during this hour”:

type Candle = {
stamp: number; // when the bar opens (UTC, milliseconds)
o: number; // open
h: number; // high
l: number; // low
c: number; // close
v?: number; // volume (optional — use 0 if missing)
};

Example:

const candle = {
stamp: 1715472000000,
o: 101.2,
h: 103.1,
l: 100.9,
c: 102.8,
v: 3200,
};

Load many candles at once:

await chart.setMainSeriesData([candle, /* … */], interval);

Tip for your backend: return JSON in exactly this shape. Your frontend can pass it straight through.


Tick — one live price

When prices stream in (WebSocket, polling), you usually send ticks, not full candles:

type Tick = {
stamp: number;
price?: number; // simple last price
c?: number; // same thing, alternate field name
v?: number;
o?: number;
h?: number;
l?: number;
};
chart.appendTick({
stamp: Date.now(),
price: 102.45,
v: 120,
});

The chart merges ticks into the current candle or starts a new one based on stamp and your interval.

SituationUse
Initial page loadCandles → setMainSeriesData
Price just movedTick → appendTick
Bar fully closedCandle → appendMainSeriesData

Tutorial: Live data stream.


Interval — candle length

Tells the chart how wide each bar is in time:

const interval = {
symbol: "1h", // label for UI ("1 hour")
milis: 60 * 60 * 1000, // length in milliseconds
};

Pass it with your data:

await chart.setMainSeriesData(candles, interval);

When the user switches from 1h to 1d, fetch new candles and call setMainSeriesData again with the new interval.

Common values:

UI labelsymbolmilis
5 minutes"5m"5 * 60 * 1000
1 hour"1h"60 * 60 * 1000
1 day"1d"24 * 60 * 60 * 1000

Instrument — symbol metadata

Describes what you are charting — not the prices themselves:

const instrument = {
symbol: "BTCUSD",
currency: "USD",
precision: 2,
availableIntervals: [
{ symbol: "5m", milis: 5 * 60 * 1000 },
{ symbol: "1h", milis: 60 * 60 * 1000 },
],
};

Set at create time or later:

const chart = createChart({ container, instrument });
// or
chart.setInstrument(instrument);

precision controls decimal places on the price axis. availableIntervals can populate your timeframe dropdown.


Multiple symbols on one chart

Compare two assets (BTC vs ETH) on the same dates:

  • First symbol = main series (usually candles).
  • Others = overlays (usually lines).

Each symbol has its own id in getSeriesManager(). Style overlays with getChartInstrumentSettings() / applyChartInstrumentSettings().

Tutorial: Multi-instrument overlay.
Reference: Multi-instrument charts.


Scripts and series (when you add indicators)

Indicators and strategies read from series — computed lines derived from price. You do not manage those arrays by hand at first:

chart.addScript("EMA");
chart.addScript("RSI");

Under the hood, getScripts() lists available recipes and getSeriesManager() holds the data. Explore when you customize indicators: Customize a built-in indicator.


Data model cheat sheet

flowchart LR
API["Your API"]
Candles["Candle[]"]
Ticks["Tick"]
Chart["Chart runtime"]

API -->|"history"| Candles -->|"setMainSeriesData"| Chart
API -->|"live"| Ticks -->|"appendTick"| Chart

What is next?