Skip to content
EliteChart

How it works

From your data to a painted candle in five steps — datafeed, normalisation, indicator pipeline, scene graph, renderer.

ChartForge moves data through five stages on its way from your backend to a painted candle. Understanding the pipeline makes it obvious where to plug a custom datafeed, where indicators run, and which layer owns redraws.

Quick example

code
'use client';
import { EliteChart } from '@elitechart/elitechart';
import { myDatafeed } from '@/lib/datafeed';
import '@elitechart/elitechart/styles.css';

export default function Page() {
  // 1. Datafeed lives in your app
  // 2. EliteChart calls datafeed.getBars + datafeed.subscribe
  // 3. Bars are normalised into branded `Bar` records
  // 4. Indicators run pure functions over the bar array
  // 5. The renderer paints the resulting scene graph
  return (
    <div style={{ width: '100%', height: '100vh' }}>
      <EliteChart datafeed={myDatafeed} symbol="BTCUSD" timeframe="1h" />
    </div>
  );
}

How it works

Step 1 — Datafeed. Your app implements the Datafeed interface — two required methods (getBars, subscribe), two optional (searchSymbols, resolveSymbol). EliteChart never assumes a transport; you can back it with REST, WebSocket, gRPC, or a static fixture.

Step 2 — Normalisation. Every bar that crosses the contract is re-stamped with branded primitives (Price, TimestampMs, Volume). This is what stops a 12-second-vs-12000-millisecond bug from compiling. The normaliser also enforces ascending time order and collapses duplicate timestamps.

Step 3 — Indicator pipeline. Active indicators are pure functions over ReadonlyArray<Bar>. They run in topological order on the worker side of the chart and produce additional series (overlay or pane). See indicators for the compute model and how to write your own.

Step 4 — Scene graph. The renderer doesn't paint bars directly. It builds a scene graph — series, overlays, axis ticks, crosshair, drawings — and diffs against the last frame to figure out the smallest invalidation rect. This is what holds the 16ms-per-frame budget at 10,000 candles.

Step 5 — Renderer. Canvas 2D today, optional WebGL fallback later. The renderer scales for devicePixelRatio, batches strokes by style, and short-circuits when the visible bar window hasn't moved.

Variations

Headless engine

If you don't want EliteChart's chrome, drop down to @elitechart/core and call createChart() directly. The same five-stage pipeline runs — you just skip the toolbar, sidebars, and modals.

code
import { createChart } from '@elitechart/core';
const chart = createChart(container, { autosize: true });
chart.setBars(bars);

Bring your own indicators

code
import { rsi } from '@elitechart/indicators/rsi';
chart.addIndicator(rsi({ period: 14 }));

API

StageOwnerPublic surface
DatafeedYour appDatafeed
Normalisation@elitechart/coreasPrice, asTimestampMs, asVolume
Indicators@elitechart/indicatorschart.addIndicator(...)
Scene graph@elitechart/coreinternal — invalidates on data + viewport changes
Renderer@elitechart/coreinternal — Canvas 2D today