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
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.
Bring your own indicators
API
| Stage | Owner | Public surface |
|---|---|---|
| Datafeed | Your app | Datafeed |
| Normalisation | @elitechart/core | asPrice, asTimestampMs, asVolume |
| Indicators | @elitechart/indicators | chart.addIndicator(...) |
| Scene graph | @elitechart/core | internal — invalidates on data + viewport changes |
| Renderer | @elitechart/core | internal — Canvas 2D today |