Skip to content

Financial

The full shell

The whole terminal chart: symbol box, resolutions, series types, indicator and drawing menus, screenshot and full screen.

The full shell@ortex-charts/ui
Loading the full shell
The whole terminal chart: symbol box, resolutions, series types, indicator and drawing menus, screenshot and full screen.
chart-shell.ts
import type { Datafeed, SymbolInfo } from "@ortex-charts/financial";
import { aggregateBars, barSeriesFromRows, barSeriesToRows, parseResolution, ticksToBars, type Bar, type Tick } from "@ortex-charts/math";
import { createChartShell } from "@ortex-charts/ui";

const INFO: SymbolInfo = {
    symbol: SYMBOL,
    name: "International Business Machines",
    exchange: EXCHANGE,
    timeZone: TIME_ZONE,
    session: "0400-2000",
    currency: "USD",
    priceFormat: { type: "price", precision: 2, minMove: 0.01 },
};

/**
 * A datafeed over one history. `getBars` is the only required method: the
 * shell asks for a window of bars and asks again, with an earlier `to`, when
 * the user scrolls off the left edge. Here every resolution is aggregated
 * from the daily bars or folded from the intraday prints on first use.
 */
function sampleFeed(daily: Bar[], prints: Tick[]): Datafeed {
    const cache = new Map<string, Bar[]>();
    const barsFor = (resolution: string): Bar[] => {
        let bars = cache.get(resolution);
        if (!bars) {
            const res = parseResolution(resolution);
            bars = res.isIntraday
                ? ticksToBars(prints, res, TIME_ZONE)
                : barSeriesToRows(aggregateBars(barSeriesFromRows(daily), res, TIME_ZONE));
            cache.set(resolution, bars);
        }
        return bars;
    };

    return {
        async resolveSymbol() {
            return INFO;
        },
        async searchSymbols() {
            return [INFO];
        },
        async getBars(request) {
            const all = barsFor(request.resolution);
            const upTo = all.filter((b) => b.time < request.to);
            const window = upTo.slice(Math.max(0, upTo.length - Math.max(request.countBack, 60)));
            return { bars: window, noMoreData: window.length === 0 || window[0].time === all[0].time };
        },
    };
}

const shell = createChartShell(el, {
    theme,
    timeZone: TIME_ZONE,
    symbol: SYMBOL,
    resolution: "1D",
    resolutions: ["5", "15", "30", "60", "1D", "1W", "1M"],
    datafeed: sampleFeed(daily, prints),
    watermark: { text: SYMBOL, visible: true },
    // Everything is on by default except the CSV download, which is opt-in.
    toolbar: { download: true },
    onResolutionChange: (resolution) => status(`${SYMBOL} at ${resolution}, aggregated from the sample history.`),
    onSymbolChange: (symbol, info) => status(`${symbol} — ${info?.name ?? "unknown symbol"}`),
});