JSON Data: Load OHLCV Data from JSON or a JavaScript Object
Candles often come as JSON: from your own REST API, a file, or a JavaScript array. This page shows how to chart them in a SciTrader chart.
The SDK doesn't yet have an exchange that takes JavaScript objects directly. Until it does, turn the candles into CSV text for CSVExchange, as below: a few lines of code, and you keep all of CSVExchange's features, such as every coarser interval and dates moved to now. For live data, write an exchange of your own instead; see Building a Custom Exchange.
Loading JSON Candles in Three Steps
1. Get the candles, from a file, your API or anywhere else. Any shape works, as long as each candle has a time, prices and volume:
// One candle as your JSON has it. Here: time in milliseconds, prices and volume as numbers
type TJsonCandle = { time: number; open: number; high: number; low: number; close: number; volume: number };
const candles: TJsonCandle[] = await (await fetch("https://example.com/api/candles?symbol=BTCUSDT&interval=1d")).json();
2. Turn them into an exchange. Write them as CSV rows, and give CSVExchange the symbol, the interval and how time is written:
// CSVExchange reads CSV text, so write the candles as CSV rows: a header, then one row per candle.
// The header names are the ones CSVExchange looks for; use the `columns` option for other names
function candlesToCsv(candles: TJsonCandle[]): string {
const rows = candles.map((c) => `${c.time},${c.open},${c.high},${c.low},${c.close},${c.volume}`);
return ["time,open,high,low,close,volume", ...rows].join("\n");
}
const exchange = new CSVExchange(
{ csv: candlesToCsv(candles), symbol: "BTCUSDT", interval: CandleInterval.ONE_DAY },
{ name: "MyData", timeUnit: "ms" } // "s" for seconds, "iso" for date strings
);
3. Chart it, with createCSVServices for one chart, or registerCSVExchange(defaultExchangeProvider, exchange) for every chart:
const { services } = createCSVServices(exchange);
await SciFinanceChartPanel.create(container, {
exchangeName: exchange.name,
symbol: "BTCUSDT",
interval: CandleInterval.ONE_DAY,
period: "1Y",
services,
studies: [new OHLCStudy(), new VolumeStudy()],
});
JSON Shapes and Times
| Your JSON has | Do this |
|---|---|
| Times in milliseconds | time |
| Times in seconds (Unix time) | time |
ISO date strings, e.g. "2026- | time. Dates without a timezone are read as UTC |
| Prices as strings | Write them as they are: the CSV is text |
Other field names, e.g. { | Read them in candles, e.g. ${c. |
| Several symbols | One { source per symbol, in an array: new |
| Several intervals of one symbol | One source per interval: each interval is then served from the best match |
Arrays instead of objects, e.g. [time, | rows. |
The data is moved to end now, like any CSV data; pass alignToNow: false if it is already current. See CSV Data.
TypeScript Example: A Candlestick Chart from JSON Data
Four years of BTCUSDT daily candles, fetched as JSON, turned into an exchange and charted with Volume and MACD. The buttons change the interval with changeInterval: from daily candles, the exchange also makes 3-day and weekly ones.
The code for this example is found below.
- TS
import "scichart-scitrader/scitrader.css";
import {
CandleInterval,
createCSVServices,
CSVExchange,
MACDStudy,
OHLCStudy,
SciFinanceChartPanel,
VolumeStudy,
} from "scichart-scitrader";
// This example expects this HTML:
// <div style="display: flex; flex-direction: column; height: 100%">
// <div id="toolbar"></div>
// <div id="chart" style="flex: 1; min-height: 0"></div>
// </div>
// The sample price history: real Binance candles for BTCUSDT, ETHUSDT and SOLUSDT, served by jsDelivr
const SAMPLE_DATA = "https://cdn.jsdelivr.net/gh/ABTSoftware/SciChart.JS.Docs@0c19782c/docusaurus/static/financial-charts/data";
// One candle as your JSON has it. Here: time in milliseconds, prices and volume as numbers
type TJsonCandle = { time: number; open: number; high: number; low: number; close: number; volume: number };
// CSVExchange reads CSV text, so write the candles as CSV rows: a header, then one row per candle.
// The header names are the ones CSVExchange looks for; use the `columns` option for other names
function candlesToCsv(candles: TJsonCandle[]): string {
const rows = candles.map((c) => `${c.time},${c.open},${c.high},${c.low},${c.close},${c.volume}`);
return ["time,open,high,low,close,volume", ...rows].join("\n");
}
async function createChart() {
const toolbar = document.getElementById("toolbar");
Object.assign(toolbar.style, toolbarStyle);
// 1. Get the candles: here from a JSON file, but any array of candles works, e.g. from your own API
const candles: TJsonCandle[] = await (await fetch(`${SAMPLE_DATA}/btcusdt-1d.json`)).json();
// 2. Turn them into an exchange: one symbol, one interval. timeUnit "ms" says how `time` is
// written ("s" for seconds, "iso" for date strings). From daily candles, CSVExchange also
// serves 3d and 1w
const exchange = new CSVExchange(
{ csv: candlesToCsv(candles), symbol: "BTCUSDT", interval: CandleInterval.ONE_DAY },
{ name: "MyData", timeUnit: "ms" }
);
// 3. Chart it, with chart services for this exchange alone
const { services } = createCSVServices(exchange);
const financeChartPanel = await SciFinanceChartPanel.create(document.getElementById("chart"), {
exchangeName: exchange.name,
symbol: "BTCUSDT",
interval: CandleInterval.ONE_DAY,
period: "1Y",
services,
studies: [new OHLCStudy(), new VolumeStudy(), new MACDStudy()],
});
const chart = financeChartPanel.financeApi;
// 4. The intervals the candles can make: 1d, 3d and 1w. getSupportedIntervals() also lists 1M,
// which charts can't show yet, so leave it out. changeInterval picks a period that suits the interval
const intervals = exchange.getSupportedIntervals().filter((i) => i !== CandleInterval.ONE_MONTH);
toolbar.append(
buttonGroup(intervals, (i) => i, CandleInterval.ONE_DAY, (interval) =>
chart.changeInterval(interval)
)
);
// When the page goes away: financeChartPanel.cleanup();
return financeChartPanel;
}
// A row of toggle buttons: one per value, the selected one highlighted
function buttonGroup<T>(values: readonly T[], label: (v: T) => string, selected: T, onSelect: (v: T) => void) {
const group = document.createElement("div");
Object.assign(group.style, { display: "flex", gap: "4px" });
const render = (current: T) =>
group.replaceChildren(
...values.map((value) => {
const b = document.createElement("button");
b.textContent = label(value);
Object.assign(b.style, buttonStyle(value === current));
b.onclick = () => {
render(value);
onSelect(value);
};
return b;
})
);
render(selected);
return group;
}
// The toolbar uses SciTrader's UI colours: its --st-ui-* CSS variables, with the stylesheet's defaults
const toolbarStyle: Partial<CSSStyleDeclaration> = {
display: "flex",
flexWrap: "wrap",
alignItems: "center",
gap: "8px 16px",
padding: "8px",
background: "var(--st-ui-background, #2b2839)",
borderBottom: "1px solid var(--st-ui-divider, rgba(255,255,255,0.1))",
color: "var(--st-ui-text-muted, #9da2bc)",
fontSize: "13px",
};
const buttonStyle = (active = false): Partial<CSSStyleDeclaration> => ({
padding: "4px 10px",
border: "1px solid var(--st-ui-divider, rgba(255,255,255,0.1))",
borderRadius: "6px",
background: active ? "var(--st-ui-selection, #6c63ff)" : "var(--st-ui-surface, #373447)",
color: "var(--st-ui-text, #ffffff)",
font: "inherit",
fontSize: "13px",
cursor: "pointer",
});
createChart();
React Example: A Candlestick Chart from JSON Data
The same chart in React: the candles are fetched in an effect, and the chart renders once they are in.
The code for this example is found below.
- React
import "scichart-scitrader/scitrader.css";
import * as React from "react";
import {
CandleInterval,
createCSVServices,
CSVExchange,
ICSVServicesHandle,
ISciFinanceChartPanelApi,
ISciFinanceChartPanelConfig,
MACDStudy,
OHLCStudy,
VolumeStudy,
} from "scichart-scitrader";
import { SciFinanceChartView } from "scichart-scitrader-react";
// The sample price history: real Binance candles for BTCUSDT, ETHUSDT and SOLUSDT, served by jsDelivr
const SAMPLE_DATA = "https://cdn.jsdelivr.net/gh/ABTSoftware/SciChart.JS.Docs@0c19782c/docusaurus/static/financial-charts/data";
// One candle as your JSON has it. Here: time in milliseconds, prices and volume as numbers
type TJsonCandle = { time: number; open: number; high: number; low: number; close: number; volume: number };
// CSVExchange reads CSV text, so write the candles as CSV rows: a header, then one row per candle.
// The header names are the ones CSVExchange looks for; use the `columns` option for other names
function candlesToCsv(candles: TJsonCandle[]): string {
const rows = candles.map((c) => `${c.time},${c.open},${c.high},${c.low},${c.close},${c.volume}`);
return ["time,open,high,low,close,volume", ...rows].join("\n");
}
// Turn candles into chart services: an exchange with one symbol at one interval. timeUnit "ms" says
// how `time` is written ("s" for seconds, "iso" for date strings)
function servicesFor(candles: TJsonCandle[]): ICSVServicesHandle {
const exchange = new CSVExchange(
{ csv: candlesToCsv(candles), symbol: "BTCUSDT", interval: CandleInterval.ONE_DAY },
{ name: "MyData", timeUnit: "ms" }
);
return createCSVServices(exchange);
}
export function JsonDataChart() {
// Get the candles: here from a JSON file, but any array of candles works, e.g. from your own API
const [handle, setHandle] = React.useState<ICSVServicesHandle>();
React.useEffect(() => {
fetch(`${SAMPLE_DATA}/btcusdt-1d.json`)
.then((response) => response.json())
.then((candles: TJsonCandle[]) => setHandle(servicesFor(candles)));
}, []);
// Fills its parent, so give the parent a height
return handle ? <JsonChart handle={handle} /> : <div style={toolbarStyle}>Loading the candles…</div>;
}
function JsonChart({ handle }: { handle: ICSVServicesHandle }) {
const chartRef = React.useRef<ISciFinanceChartPanelApi>(null);
const [interval, setInterval] = React.useState(CandleInterval.ONE_DAY);
// Create the config once per mounted chart: studies are live objects bound to one chart
const config = React.useMemo<ISciFinanceChartPanelConfig>(
() => ({
exchangeName: handle.exchange.name,
symbol: "BTCUSDT",
interval: CandleInterval.ONE_DAY,
period: "1Y",
services: handle.services,
studies: [new OHLCStudy(), new VolumeStudy(), new MACDStudy()],
}),
[handle]
);
// financeApi throws until the chart has initialised
const chart = () => (chartRef.current?.isInitialized ? chartRef.current.financeApi : undefined);
return (
<div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
<div style={toolbarStyle}>
{/* The intervals the candles can make: 1d, 3d and 1w. getSupportedIntervals() also lists 1M,
which charts can't show yet. changeInterval picks a period that suits the interval */}
<ButtonGroup
values={handle.exchange.getSupportedIntervals().filter((i) => i !== CandleInterval.ONE_MONTH)}
selected={interval}
onSelect={(i) => (setInterval(i), chart()?.changeInterval(i))}
/>
</div>
<div style={{ flex: 1, minHeight: 0 }}>
<SciFinanceChartView ref={chartRef} config={config} />
</div>
</div>
);
}
// A row of toggle buttons: one per value, the selected one highlighted
function ButtonGroup<T extends string>(props: { values: readonly T[]; selected: T; onSelect: (v: T) => void }) {
return (
<div style={{ display: "flex", gap: 4 }}>
{props.values.map((value) => (
<button key={value} style={buttonStyle(value === props.selected)} onClick={() => props.onSelect(value)}>
{value}
</button>
))}
</div>
);
}
// The toolbar uses SciTrader's UI colours: its --st-ui-* CSS variables, with the stylesheet's defaults
const toolbarStyle: React.CSSProperties = {
display: "flex",
flexWrap: "wrap",
alignItems: "center",
gap: "8px 16px",
padding: 8,
background: "var(--st-ui-background, #2b2839)",
borderBottom: "1px solid var(--st-ui-divider, rgba(255,255,255,0.1))",
color: "var(--st-ui-text-muted, #9da2bc)",
fontSize: 13,
};
const buttonStyle = (active = false): React.CSSProperties => ({
padding: "4px 10px",
border: "1px solid var(--st-ui-divider, rgba(255,255,255,0.1))",
borderRadius: 6,
background: active ? "var(--st-ui-selection, #6c63ff)" : "var(--st-ui-surface, #373447)",
color: "var(--st-ui-text, #ffffff)",
font: "inherit",
fontSize: 13,
cursor: "pointer",
});
Where to read next
- CSV Data: every
CSVExchangeoption. - Building a Custom Exchange: your API as a live exchange.
- Data Sources: every data source.