Skip to main content

@tidal-ts/chart

A multi-row time-series chart built on @pond-ts/charts. Rows stack top to bottom on one shared time axis; each row holds any number of series on a left and a right axis. Peers: React 18 or 19, pond-ts, @pond-ts/charts, @pond-ts/react and @pond-ts/financial.

The chart reads no CSS, no context provider and no storage. Its theme, colours and settings all arrive as props, so it takes on whatever design system the host app uses. Getting started has a complete example.

Describing a series: SeriesConfig​

Each line, candle series or study is one config:

FieldMeaning
idStable identity: hover readouts and dimmed refer to it.
sourceWhich entry of sources to read ('price', 'vol', or your own keys).
columnThe column to draw. For a study, deriveId(spec).
deriveThe study spec, when this config is a study.
styleline, area, bar, candle, band (a shaded channel) or lines (several outputs).
axis'L' or 'R'.
axisGroupGive a series its own axis on that side instead of the shared one.
colorA CSS colour, or a key your resolveColor understands.
label, unitWhat the readout and axis say.
visibleHide without removing.
valueThe latest value, for a legend. Pass null; prepareChart fills it in.

Candles also take colorMode: 'split' with riseColor and fallColor.

Preparing the data: prepareChart​

const { rows, sources } = prepareChart({ price: { series } }, [
{ id: 'main', configs: [candles, sma] },
{ id: 'rsi', configs: [rsi] },
]);

It computes every study onto its source, leaves out plain series whose column holds no data, gives each config its latest value (for a legend or readout), and returns rows and sources ready for the chart. Add a pixel height to each row before drawing. facts reports which columns each source ended up carrying, which is how a host can tell that a study produced no values.

prepareChart is three steps in one call: foldSources (the expensive one: computing studies), sourceFacts and assembleRows. A host that recolours or reorders often can call them separately and memoise the first.

A source coarser than the axis​

A daily curve on a one-minute chart: pass it at its own grain, with hold.

prepareChart(
{
price: { series: minuteBars },
vol: {
series: dailyVol,
compare: dailyVolOfOther,
hold: {
grid: minuteBars.keyColumn().begin.subarray(0, minuteBars.length),
grainMs: 86_400_000,
},
},
},
rows,
);

Studies and the comparison join run on the daily rows, so a 20-bar average is 20 days. The result is then held across the grid: each row holds from its key for grainMs, and a day with no row stays a gap. Name the same source in coarseSources so the chart does not break the held line at every session.

  • Pass enough daily history for the longest study to warm up before the grid starts. Rows before the grid cost nothing in the result.
  • The comparison joins on the daily keys, so key both series the same way. A day the source has no row for is a gap in the comparison too.
  • A day that arrives twice counts once: the later row replaces the earlier one before any study reads it.

Drawing: TimeSeriesChart​

The props most hosts use:

PropPurpose
rows, sourcesFrom prepareChart, with heights added.
themeA ChartTheme from @pond-ts/charts: write it out, or build it from CSS variables with cssVarTheme.
colorScheme'dark' or 'light': which way a hovered axis brightens.
resolveColorMaps palette keys in configs to real colours. Leave it out for CSS colours.
ohlcSourcesSources that carry open/high/low/close, so candle can draw.
onTrackerHover readout: the time under the cursor and every series' value there.
dimmedSeries ids to fade, to emphasise the rest.
viewRange, onViewRangeChangeControl the visible time window (pan and zoom).
axisOptionsPer-axis fixed bounds, decimals, log scale, title and tick count.
onBarSeriesThe series each bar is drawn from (the roll-up), to measure a bar axis on what it shows.
annotationsDate markers, such as earnings or expiries, drawn across every row.
coarseSourcesSources held across a finer axis (see hold above), so they are not broken at each session.
pricePillA live last-price tag on the axis; ticks repaint only the tag.
collapseWeekends, calendarDays, timeZoneHow the time axis treats closed markets and which zone it reads in.

Settings​

ChartSettings (with DEFAULT_CHART_SETTINGS and mergeChartSettings) holds app-wide presentation defaults: line weights and dashes per kind of series, and the default rise and fall colours.