Getting started
Install
tidal-ts needs Node 22 or later and React 18 or 19. The pond-ts packages are peer dependencies: your app installs them once, on one version, so there is only ever one copy of pond-ts in the bundle. Two copies break silently, because a series made by one copy is not recognised by the other.
npm install --save-exact @tidal-ts/core @tidal-ts/chart @pond-ts/process@0.73.0
npm install pond-ts@~0.73.0 @pond-ts/financial@~0.73.0 @pond-ts/charts@~0.73.0 @pond-ts/react@~0.73.0
The pond versions must be the ones tidal-ts was built against, which is why
they are named: a plain npm install pond-ts takes the newest release, and
npm refuses it when tidal-ts asks for an older one. Each tidal-ts release
names its pond version in its peer dependencies
(npm view @tidal-ts/chart peerDependencies). Add @tidal-ts/terminal (with
xstate and @xstate/react) only if you want its state machine.
A first chart
Candles, a 20-bar moving average over them, and a 14-bar RSI in a panel of its
own. The data is the practice series that ships with @tidal-ts/core, a seeded
random walk, so it draws the same picture every time.
import { defaultTheme, type ChartTheme } from '@pond-ts/charts';
import { DEMO_INSTRUMENTS, deriveId, generatePriceSeries, type DeriveSpec } from '@tidal-ts/core';
import {
prepareChart,
TimeSeriesChart,
type ChartSeries,
type SeriesConfig,
} from '@tidal-ts/chart';
// 1. Data: a pond TimeSeries of daily bars. Here a seeded practice walk; in an
// app, your adapter turns your API's response into the same shape.
const price = generatePriceSeries(DEMO_INSTRUMENTS[0]!, { bars: 200 }) as unknown as ChartSeries;
// 2. Studies are specs: an op, its inputs, its settings. `deriveId` names the
// column the study's values land in.
const sma: DeriveSpec = { op: 'sma', inputs: ['close'], params: { period: 20 } };
const rsi: DeriveSpec = { op: 'rsi', inputs: ['close'], params: { period: 14 } };
// 3. Configs say what to draw, in which colour, on which axis. Colours here are
// plain CSS; a host with a palette passes its own keys and a `resolveColor`.
const base = { axis: 'L', visible: true, value: null, unit: '', source: 'price' } as const;
const candles: SeriesConfig = {
...base,
id: 'price',
column: 'close',
label: 'Price',
color: '#8b93a8',
style: 'candle',
colorMode: 'split',
riseColor: '#3fb68b',
fallColor: '#e5534b',
};
const smaLine: SeriesConfig = {
...base,
id: 'sma',
column: deriveId(sma),
derive: sma,
label: 'SMA 20',
color: '#f0a93f',
style: 'line',
};
const rsiLine: SeriesConfig = {
...base,
id: 'rsi',
column: deriveId(rsi),
derive: rsi,
label: 'RSI 14',
color: '#a99cf5',
style: 'line',
};
// 4. The prepare step computes the studies and seats each config on its row.
const { rows, sources } = prepareChart({ price: { series: price } }, [
{ id: 'main', configs: [candles, smaLine] },
{ id: 'rsi', configs: [rsiLine] },
]);
// 5. The theme is a prop too: the chart reads no CSS and no provider.
const themeFor = (dark: boolean): ChartTheme => ({
...defaultTheme,
background: undefined,
axis: {
...defaultTheme.axis,
label: dark ? '#868fa6' : '#55607a',
grid: dark ? 'rgba(233,237,246,0.08)' : 'rgba(17,24,39,0.10)',
},
});
export default function FirstChart({ dark = true }: { dark?: boolean }) {
return (
<TimeSeriesChart
rows={rows.map((r) => ({ ...r, height: r.id === 'main' ? 280 : 140 }))}
sources={sources}
ohlcSources={['price']}
theme={themeFor(dark)}
colorScheme={dark ? 'dark' : 'light'}
/>
);
}
What to notice:
- A study is data, not code.
{ op: 'rsi', inputs: ['close'], params: { period: 14 } }is the whole description. The prepare step computes it, andderiveIdgives the name of the column its values land in. - The chart decides nothing about looks. Colours sit in the configs and the
theme is a prop. Pass palette names instead of CSS colours and give the chart
a
resolveColorto map them. - Guide lines come with the study. The RSI's 30 and 70 lines are drawn because the study declares them, not because the example asked.
Next
- Browse the study catalog for every
op, its settings and its outputs. - Read the chart package for rows, axes and live updates.