Symbols, Intervals and Periods
A trading chart shows one symbol (e.g. BTC-USD), at one candle interval (e.g. 6 hours), over a period of time (e.g. the last month). All three can change while the chart is running. The chart keeps its studies, panes and drawings when they do: every study recalculates on the new data.
Where SciFinanceChart Comes From
Every method on these pages is a member of SciFinanceChart, the chart itself. You reach it through the financeApi property of the ISciFinanceChartPanelApi that SciFinanceChartPanel.create returns. In React, <SciFinanceChartView> hands you the same object through ref and onInit.
import { SciFinanceChart, SciFinanceChartPanel } from "scichart-scitrader";
// financeChartPanel: ISciFinanceChartPanelApi, the chart and its layout
const financeChartPanel = await SciFinanceChartPanel.create(document.getElementById("chart"), config);
// chart: SciFinanceChart, with the symbol, interval and period methods
const chart: SciFinanceChart = financeChartPanel.financeApi;
await chart.setSymbol("ETHUSDT");
SciFinanceChart Symbol, Interval and Period Methods
| Member | What it does | See |
|---|---|---|
set | Changes the symbol, and optionally the exchange, keeping the interval and period | Changing the symbol |
create | Changes symbol and interval in one step. With is, it replaces what the chart shows | Symbol and interval together |
change | Reloads the current symbol at another candle interval | Changing the interval |
set | Shows another period of time, fetching any older candles it needs | Periods |
current | The period on screen, or null for none | |
data | The chart's data feeds. The default one has the current exchange, symbol and interval |
All four methods are async. await them before you read currentPeriod or dataFeeds.
The SciFinanceChart symbol, interval and period members, with their TSDoc
/**
* Switches the chart to another symbol, optionally on another exchange, keeping the current
* interval and period. Studies, panes and drawings stay; every study recalculates on the new
* data. Raises {@link dataLoadStarted}, then `dataRenderComplete({ type: "symbol-change" })`.
*
* Shorthand for `createDataFeed(EDataFeedType.OHLCVRealtime, exchangeName, symbol,
* <current interval>, true, <current period>)`.
*
* @param symbol The symbol in the exchange's own format (`BTCUSDT` on Binance, `BTC-USD` on
* Coinbase; `mapSymbol` converts between them).
* @param exchangeName The exchange to load from. Defaults to the current one.
* @param options.period The period to show once loaded, instead of the current one. `null`
* shows all loaded data with no period.
*/
setSymbol(symbol: string, exchangeName?: string, options?: {
period?: TPeriod | null;
}): Promise<IDataFeed>;
createDataFeed(feedType: EDataFeedType, exchangeName: string, symbol: string, interval: CandleInterval, isDefault: boolean, period?: TPeriod | null): Promise<IDataFeed>;
/**
* Reload the current symbol's candles at a new interval, landing on a period in the same step.
*
* `period` picks what the chart shows at the new interval:
* - a {@link TPeriod} — that period, applied at the new interval;
* - `null` — no period (free pan/zoom). The view lands on the interval's default window, but
* nothing caps the zoom afterwards;
* - omitted — {@link defaultPeriodForInterval}, even when no period was active before.
*
* Afterwards {@link currentPeriod} describes what is on screen, so there is no need to follow
* this with {@link setPeriod}. The fetch is sized for the target period, so a period change
* costs no second fetch. To keep the user's period across the switch instead of snapping to
* the default, pass `carryPeriodToInterval(chart.currentPeriod, interval)`.
*
* A {@link setPeriod} call made while this is loading wins: the period resolved here is then
* not applied.
*/
changeInterval(interval: CandleInterval, period?: TPeriod | null): Promise<void>;
/**
* Apply a preset period — single-shot fetch of exactly the right candle count.
*
* Replaces the old iterative `loadPreviousData` orchestration with a predictive
* flow:
* 1. Compute an `IFetchPlan` from `(currentInterval, period, now, bufferRatio)`.
* 2. Disable `xAxis.autoRange` and set the *target* visible range up-front,
* using the index space we know the new fetch will produce.
* 3. Configure the default feed to fetch exactly `plan.totalCandles` and
* reload via `feed.change(symbol, interval)`.
* 4. By the time data arrives the visible range is already correct — no
* auto-fit override, no flash, no second range adjustment.
*
* `"ALL"` (and degenerate plans) fall back to `applyFitAllRange` — an
* explicit `[0, n-1]` set, *not* SciChart's `zoomExtents`, since the chart
* is configured `EAutoRange.Never` everywhere. Cancellation: a counter
* token (`setPeriodToken`) discards stale results when the user picks a
* different period mid-flight.
*
* **Data-feed cancellation note:** `IExchangeClient.getCandles` does not
* accept an `AbortSignal` today, and `DataFeedManager` does not debounce
* overlapping calls. A superseded `setPeriod`'s REST request still
* completes and writes data; the cancellation token only prevents us from
* applying the *visible-range* update on a stale call. Adding abort
* support is a separate follow-up.
*/
setPeriod(period: TPeriod | null): Promise<void>;
/**
* The currently-selected preset period, set by the most recent successful
* {@link setPeriod} call. `null` means no period is active — the chart shows
* whatever the data feed's natural visible range is.
*/
currentPeriod: TPeriod | null;
get dataFeeds(): Map<string, IDataFeed>;
SciFinanceChart Loading Events
A symbol or interval change loads new candles, which takes a moment. The chart shows its own loading overlay while it does (the loading option of the chart config). Two events let your own UI follow along too, e.g. a status line or a toolbar that disables itself:
| Event | Raised when |
|---|---|
data | A symbol or interval change starts loading. Not raised while older candles load in the background as the user pans back |
data | The new data has loaded and been drawn. args. says why: "init", "symbol-, "interval-, "historical" or "stale- |
Both are SciChart EventHandlers. This example shows a status line in an element of your own page:
// Your own status element, e.g. <span id="status"></span> in your toolbar. It isn't part of SciTrader.
const status = document.getElementById("status");
// dataLoadStarted: raised when a symbol or interval change (setSymbol, changeInterval,
// createDataFeed) starts loading new candles
chart.dataLoadStarted.subscribe(() => {
status.textContent = "Loading…";
});
// dataRenderComplete: raised when the loaded candles have been drawn.
// args.type is the reason for the load: here, the symbol or interval change has finished
chart.dataRenderComplete.subscribe((args) => {
if (args.type === "symbol-change" || args.type === "interval-change") {
status.textContent = "";
}
});
The SciFinanceChart loading events, with their TSDoc
/**
* Fires when a FOREGROUND data load begins — full-chart dataset
* replacements (initial load via `createWithStudies`, symbol/interval
* swap via `changeInterval` / `createDataFeed`). These are paired
* with a `data-chart-loading` overlay in `SciFinanceChartView`.
*
* **Not raised for coordinator-driven background loads** (pan-back
* cascade, warmup-after-init, forward-edge fills). Earlier prototyping
* raised it from `handleLoadStart` and produced a "disappear for a
* few seconds then reappear" flash when the warmup fired right after
* init — see the comment at `handleLoadStart`. For background-load
* notification, subscribe to {@link historicalLoadStarted} /
* {@link historicalLoadComplete} instead.
*/
dataLoadStarted: EventHandler<void>;
/** Fires after a FOREGROUND data load has been loaded and fully rendered. */
dataRenderComplete: EventHandler<IDataRenderCompleteArgs>;
/** Arguments passed to the {@link SciFinanceChart.dataRenderComplete} event. */
interface IDataRenderCompleteArgs {
/**
* - "init" — first load and render after chart creation.
* - "historical" — scroll-left-triggered prefetch of older candles.
* - "interval-change" — user switched candle interval (e.g. 15m → 1H);
* the data feed was reloaded with new candles.
* - "stale-recovery" — wake-from-sleep catch-up finished: missed candles
* were back-filled to now and the live stream re-seeded.
*/
type: "init" | "historical" | "interval-change" | "symbol-change" | "stale-recovery";
}
Pages in this section
- Changing the symbol:
setSymbol, where the data comes from, andcreateDataFeed. - Changing the interval:
changeIntervaland keeping the user's span withcarryPeriodToInterval. - Periods:
setPeriod, the period values, and how they fetch data. - Toolbar controls: ready-made interval and period pickers, in plain TypeScript and React.
TypeScript Example: Changing the Symbol, Interval and Period
This example changes the symbol, interval and period of a live chart in plain TypeScript, with the three SciFinanceChart calls above. The chart starts on BTC-USD at 6-hour candles over one month, with live Coinbase data. Its toolbar has:
- Symbol buttons that call
setSymbol. - An
IntervalSelectorthat callschangeInterval, keeping about the same span on screen withcarryPeriodToInterval. - A
PeriodSelectorthat callssetPeriod.
The code for this example is found below.
- TS
import "scichart-scitrader/scitrader.css";
import {
CandleInterval,
carryPeriodToInterval,
CoinbaseExchange,
defaultExchangeProvider,
idbPriceStore,
IntervalSelector,
OHLCStudy,
PeriodSelector,
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>
// Register a data source, once, at app startup
defaultExchangeProvider.registerExchange(CoinbaseExchange, idbPriceStore);
const SYMBOLS = ["BTC-USD", "ETH-USD", "SOL-USD"]; // Coinbase's symbol format
// Coinbase offers 1m, 5m, 15m, 1h, 6h and 1d candles
const INTERVALS = [CandleInterval.FIFTEEN_MINUTES, CandleInterval.ONE_HOUR, CandleInterval.SIX_HOURS, CandleInterval.ONE_DAY];
async function createChart() {
const toolbar = document.getElementById("toolbar");
Object.assign(toolbar.style, toolbarStyle);
const financeChartPanel = await SciFinanceChartPanel.create(document.getElementById("chart"), {
exchangeName: CoinbaseExchange.name, // name="Coinbase" matches the built-in CoinbaseExchange
symbol: SYMBOLS[0],
interval: CandleInterval.SIX_HOURS,
period: "1M", // show the last month
studies: [new OHLCStudy(), new VolumeStudy()],
});
const chart = financeChartPanel.financeApi; // SciFinanceChart
// Symbol: plain buttons. setSymbol keeps the exchange, interval, period and studies
const symbolButtons = SYMBOLS.map((symbol) => {
const button = document.createElement("button");
button.textContent = symbol;
button.onclick = () => {
symbolButtons.forEach((b) => Object.assign(b.style, buttonStyle(b === button)));
chart.setSymbol(symbol);
};
Object.assign(button.style, buttonStyle(symbol === SYMBOLS[0]));
toolbar.appendChild(button);
return button;
});
// Interval: the SDK's IntervalSelector
const intervals = IntervalSelector.create(toolbar, {
value: CandleInterval.SIX_HOURS,
intervals: INTERVALS,
onChange: (interval) => {
// Keep about the same span on screen, adjusted to suit the new interval
const period = carryPeriodToInterval(periods.value, interval);
periods.update({ value: period, currentInterval: interval });
chart.changeInterval(interval, period);
},
});
// Period: the SDK's PeriodSelector. "Free", or clicking the selected period again, gives null
const periods = PeriodSelector.create(toolbar, {
value: "1M",
currentInterval: CandleInterval.SIX_HOURS, // greys out periods that don't suit the interval
onChange: (period) => chart.setPeriod(period),
});
// When the page goes away: intervals.destroy(); periods.destroy(); financeChartPanel.cleanup();
return { financeChartPanel, intervals, periods };
}
// 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",
padding: "8px",
background: "var(--st-ui-background, #2b2839)",
borderBottom: "1px solid var(--st-ui-divider, rgba(255,255,255,0.1))",
};
const buttonStyle = (active: boolean): Partial<CSSStyleDeclaration> => ({
padding: "6px 14px",
fontSize: "14px",
fontFamily: "var(--st-font-family, sans-serif)",
color: "var(--st-ui-text, #ffffff)",
background: active ? "var(--st-ui-accent, #7464ff)" : "var(--st-ui-surface, #373447)",
border: "1px solid var(--st-ui-divider, rgba(255,255,255,0.1))",
borderRadius: "4px",
cursor: "pointer",
});
createChart();
React Example: Changing the Symbol, Interval and Period
The same chart as a React component. It uses <SciFinanceChartView>, and the React IntervalSelector and PeriodSelector from scichart-scitrader-react, and keeps the symbol, interval and period in React state.
The code for this example is found below.
- React
import "scichart-scitrader/scitrader.css";
import * as React from "react";
import {
CandleInterval,
carryPeriodToInterval,
CoinbaseExchange,
defaultExchangeProvider,
idbPriceStore,
ISciFinanceChartPanelApi,
ISciFinanceChartPanelConfig,
OHLCStudy,
TPeriod,
VolumeStudy,
} from "scichart-scitrader";
import { IntervalSelector, PeriodSelector, SciFinanceChartView } from "scichart-scitrader-react";
// Register a data source, once, at app startup
defaultExchangeProvider.registerExchange(CoinbaseExchange, idbPriceStore);
const SYMBOLS = ["BTC-USD", "ETH-USD", "SOL-USD"]; // Coinbase's symbol format
// Coinbase offers 1m, 5m, 15m, 1h, 6h and 1d candles
const INTERVALS = [CandleInterval.FIFTEEN_MINUTES, CandleInterval.ONE_HOUR, CandleInterval.SIX_HOURS, CandleInterval.ONE_DAY];
export function SymbolIntervalPeriodChart() {
const chartRef = React.useRef<ISciFinanceChartPanelApi>(null);
const [symbol, setSymbol] = React.useState(SYMBOLS[0]);
const [interval, setInterval] = React.useState(CandleInterval.SIX_HOURS);
const [period, setPeriod] = React.useState<TPeriod | null>("1M");
// Read once, when the chart is created. Later changes go through financeApi
const config = React.useMemo<ISciFinanceChartPanelConfig>(
() => ({
exchangeName: CoinbaseExchange.name, // name="Coinbase" matches the built-in CoinbaseExchange
symbol,
interval,
period: period ?? undefined,
studies: [new OHLCStudy(), new VolumeStudy()],
}),
// eslint-disable-next-line react-hooks/exhaustive-deps
[]
);
// financeApi throws until the chart has initialised
const chart = () => (chartRef.current?.isInitialized ? chartRef.current.financeApi : undefined);
// Fills its parent, so give the parent a height
return (
<div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
<div style={toolbarStyle}>
{SYMBOLS.map((s) => (
<button
key={s}
style={buttonStyle(s === symbol)}
onClick={() => {
setSymbol(s);
chart()?.setSymbol(s);
}}
>
{s}
</button>
))}
<IntervalSelector
value={interval}
intervals={INTERVALS}
onChange={(next) => {
// Keep about the same span on screen, adjusted to suit the new interval
const carried = carryPeriodToInterval(period, next);
setInterval(next);
setPeriod(carried);
chart()?.changeInterval(next, carried);
}}
/>
<PeriodSelector
value={period}
currentInterval={interval}
onChange={(next) => {
setPeriod(next);
chart()?.setPeriod(next);
}}
/>
</div>
<div style={{ flex: 1, minHeight: 0 }}>
<SciFinanceChartView ref={chartRef} config={config} />
</div>
</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: 8,
padding: 8,
background: "var(--st-ui-background, #2b2839)",
borderBottom: "1px solid var(--st-ui-divider, rgba(255,255,255,0.1))",
};
const buttonStyle = (active: boolean): React.CSSProperties => ({
padding: "6px 14px",
fontSize: 14,
fontFamily: "var(--st-font-family, sans-serif)",
color: "var(--st-ui-text, #ffffff)",
background: active ? "var(--st-ui-accent, #7464ff)" : "var(--st-ui-surface, #373447)",
border: "1px solid var(--st-ui-divider, rgba(255,255,255,0.1))",
borderRadius: 4,
cursor: "pointer",
});