Skip to main content

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​

MemberWhat it doesSee
setSymbol(symbol, exchangeName?, options?)Changes the symbol, and optionally the exchange, keeping the interval and periodChanging the symbol
createDataFeed(feedType, exchangeName, symbol, interval, isDefault, period?)Changes symbol and interval in one step. With isDefault: true, it replaces what the chart showsSymbol and interval together
changeInterval(interval, period?)Reloads the current symbol at another candle intervalChanging the interval
setPeriod(period)Shows another period of time, fetching any older candles it needsPeriods
currentPeriodThe period on screen, or null for none
dataFeedsThe chart's data feeds. The default one has the current exchangeName, 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:

EventRaised when
dataLoadStartedA symbol or interval change starts loading. Not raised while older candles load in the background as the user pans back
dataRenderCompleteThe new data has loaded and been drawn. args.type says why: "init", "symbol-change", "interval-change", "historical" or "stale-recovery"

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​

  1. Changing the symbol: setSymbol, where the data comes from, and createDataFeed.
  2. Changing the interval: changeInterval and keeping the user's span with carryPeriodToInterval.
  3. Periods: setPeriod, the period values, and how they fetch data.
  4. 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 IntervalSelector that calls changeInterval, keeping about the same span on screen with carryPeriodToInterval.
  • A PeriodSelector that calls setPeriod.

The code for this example is found below.

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.

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",
});