[Charting]
AXIS chart: ChartHost, PaneManager, series factory, drawings, crosshair sync, and trade markers.
Charting
Charting is the spatial surface for OHLCV, overlays, and annotations. Implementation is imperative under a Solid shell so lightweight-charts owns its DOM subtree.
Abstract
| Module | Role |
|---|---|
ChartHost.tsx | Solid mount; empty-state overlay; lifecycle |
pane-manager.ts | Multi-pane LWC charts, time sync |
series-factory.ts | Candle/volume/line series helpers + palette |
drawing-layer.ts | User + script drawings |
crosshair-sync.ts | Cross-pane crosshair |
pine-drawings.ts | Engine drawing objects → layer |
manager-access.ts | Process-wide manager/layer getters |
Conceptual model
Interface surface
Panes
store.panes: { id, type, height, order, visible, label }.
| type | Typical series |
|---|---|
price | Candles + overlay lines + markers + drawings |
volume | Histogram |
indicator | Non-overlay plots |
equity | Strategy equity curve |
Defaults: price + volume. Indicator/equity created on demand.
Empty / status overlay
When bars.length === 0, ChartHost shows contextual title/sub from store.status (loading, error, running, or “Load data to begin”).
Drawings toolbar
See operator guide Drawings. Tools: cursor, hline, trend, ray, rect, fib, measure, text.
Crosshair & time
syncTimeScales / syncCrosshair keep multi-pane navigation coherent. scrollToTime used from Results trade clicks.
Internals
Solid vs imperative boundary
// ChartHost — Solid owns outer shell
// PaneManager only mutates panesEl — never put Solid children inside panesEl
On cleanup: destroy drawing layer, dispose manager, clear accessors.
Data path
setDataToChart(bars) applies OHLCV; createEffect on store.bars re-applies if bars change outside load helper.
Run apply (chart side)
From runAndApply (indicators):
syncOverlayLines— update existing overlay series in place (avoids destroy→blank→add flash on live re-runs)- Markers from normalized events (set in place)
- Script drawings atomic replace via DrawingLayer (
setScriptDrawingswithout empty frame) - Equity series when strategy report warrants (silent live runs skip hide thrash)
History vs live bars
- Full loads:
loadBars→chartDataGen++→setDataToChart+ fitContent - Live:
multiplex→appendBar+manager.appendBaronly (no fitContent, no full setData)
series-factory
Centralizes series construction options and color palette so Results plot summary and chart stay chromatically related.
Invariants
- Solid reconciliation must not rewrite pane roots.
- Script drawings ephemeral per run; user drawings store-backed.
- Overlay default true unless
meta.overlay === false. - Manager may be null before mount—runner no-ops chart apply safely.
Failure modes
| Symptom | Cause |
|---|---|
| Blank panes after hot reload | Manager disposed; full remount |
| Overlays stack forever | Old path skipped removeOverlays |
| Fib/tools ignore clicks | No bars / time scale; wrong tool |
| Markers at t=0 | Event times not bar-aligned |
Worked example (dev)
import { getManager } from './chart/manager-access';
getManager()?.scrollToTime(barTime);