tickwick
v1.1.0
Published
Framework-agnostic stock charting library with candlesticks, technical indicators, and LLM-friendly declarative API
Maintainers
Readme
Website · Documentation · Live demo · Playground · Features · Pricing · npm · GitHub
Framework-agnostic charting for financial OHLCV data. The UI is built with Svelte 4 and D3; you embed it from React, Vue, Svelte or vanilla JavaScript without adopting Svelte in your own app. MIT-licensed and production-ready on its own.

Everything above is in this package: candlesticks, EMA overlays, volume, RSI
and MACD subpanes, the crosshair readout and the range selector, on the built-in
onyx theme. Synthetic data.
Why Tickwick
- Drop-in widget —
<TickwickChart data={...} />in React or Vue, or mount imperatively withTickwickChart.create({ container, data })anywhere else. - No heavyweight dependencies — four granular d3 modules and nothing else. The scales, the gesture recogniser and the whole indicator library are local.
- Declarative configs — describe panes, indicators and layout as plain JSON, which suits LLM "prompt-to-chart" flows.
- Extensible — register custom themes, indicators, drawing tools and chart types at runtime through the plugin API. No fork required.
What's in this package
tickwick is the free tier and is fully usable in production under MIT. Counts
come from FEATURES.md
in the source repository, the source of truth for every published claim.
| Area | Included |
|------|----------|
| Chart styles | Candlestick, line, area |
| Indicators | The 14 classics — SMA, EMA, WMA, MACD, RSI, Stochastic, CCI, Williams %R, ROC, Bollinger Bands, ATR, ADX, OBV, Volume |
| Drawing tools | Line, horizontal line, text |
| Themes | All 10 — onyx, carbon, aurora, midnight, dracula, nord, graphite (dark); daylight, parchment, solarized (light) — plus unlimited custom themes |
| Interaction | Pan, zoom, pinch, wheel, crosshair, OHLCV tooltip |
| Layout | Main pane + indicator subpanes; comparison overlays (percent change) |
| i18n | English. setMessages() supplies your own strings; the other nine languages are a Pro feature |
| Watermark | "Powered by Tickwick", shown by default. A plain option, not a licence gate — showWatermark: false hides it |
Theming is not a paywall. Both tiers get all 10 bundled themes, all 37 theme
tokens and registerTheme().

Install
npm install tickwickStyles are needed once, in your app entry:
import 'tickwick/style.css';Peer dependencies. react and vue are both optional peers, needed only if
you import the matching wrapper (tickwick/react / tickwick/vue). Vanilla and
Svelte users install neither.
Supported browsers: Chrome 87+, Edge 88+, Firefox 78+, Safari 14+ (also
declared in browserslist). Node 18.18+ is required to build from source.
Quick start
React
import { TickwickChart } from 'tickwick/react';
import 'tickwick/style.css';
export default function App({ data }) {
return <TickwickChart data={data} theme="onyx" height={480} />;
}Mounting, prop syncing and teardown are handled for you. A ref gives you the
live instance (updateData, setTheme, setLocale, setOptions, destroy).
Vue 3
<script setup>
import { TickwickChart } from 'tickwick/vue';
import 'tickwick/style.css';
defineProps(['data']);
</script>
<template>
<TickwickChart :data="data" theme="onyx" :height="480" />
</template>Vanilla JavaScript
import { TickwickChart, sampleBtcData } from 'tickwick';
import 'tickwick/style.css';
const chart = TickwickChart.create({
container: document.getElementById('chart'),
data: sampleBtcData,
theme: 'onyx',
height: 480,
});
// You own the lifecycle here — the wrappers do this for you.
chart.destroy();destroy() tears down the widget and restores the container's inline styles, so
the element is reusable afterwards.
Svelte
The widget is a Svelte 4 component internally, but the public API is the same
imperative one — use TickwickChart.create() in onMount and return
chart.destroy for cleanup.
Indicators and panes
Add indicators as overlays on the price pane or as their own subpane:
TickwickChart.create({
container: '#chart',
data,
theme: 'daylight',
panes: [
{
type: 'candles',
indicators: [
{ type: 'EMA', period: 21 },
{ type: 'BollingerBands', period: 20, stdDev: 2 },
{ type: 'Volume' },
],
},
{ type: 'indicator', config: { type: 'RSI', period: 14 }, height: 110 },
],
});
Data format
Each bar is an OHLCV tuple:
[timestamp, open, high, low, close, volume]- timestamp — Unix time in milliseconds. Second-resolution values are detected per row and normalised, so mixed input is fine.
- open, high, low, close — prices.
- volume — shares, contracts or normalised units.
const data = [
[1609459200000, 29000, 29500, 28800, 29300, 1_000_000],
[1609545600000, 29300, 30000, 29200, 29800, 1_200_000],
];Rows must be time-ascending. normalizeOHLCV(rows) is exported if you want
to coerce input once and reuse the result; the widget runs it on whatever you
pass as data, so you rarely need it directly.
Demo data
import {
generateRandomData,
generateRealisticData,
generateAlignedCompareData,
} from 'tickwick';
const random = generateRandomData(500, 150, 0.02); // points, start, volatility
const bullish = generateRealisticData(500, 150, 'bullish'); // 'bullish' | 'bearish' | 'sideways'API overview
const chart = TickwickChart.create(config);| Method | Purpose |
|---|---|
| updateData(rows) | Replace the dataset in place |
| setTheme(name \| theme) | Switch theme live; a partial theme object is fine |
| setLocale(code) | Switch this chart's locale (async — locales are lazy chunks) |
| setMessages(messages) | Supply custom strings for this chart |
| setOptions(partial) | Merge widget options live |
| setEvents / addEvent / clearEvents | Event markers (rendered when the Pro renderer is present) |
| destroy() | Tear down and restore the container |
| Static | Purpose |
|---|---|
| TickwickChart.create(config) | Primary constructor |
| TickwickChart.createFromConfig(container, config) | Config-first form |
| TickwickChart.getThemes() / getTheme(name) | Bundled palettes |
Locale is per chart. A chart follows the app-wide setLocale() until you
give it one of its own via the locale option or chart.setLocale(), so several
charts on one page can run in different languages.
Themes
import { registerTheme } from 'tickwick/plugin';
registerTheme('midnightBlue', {
backgroundColor: '#0b1220',
candleColorUp: '#22c55e',
candleColorDown: '#ef4444',
// …only the tokens you care about; the rest fall back to the default theme
});
chart.setTheme('midnightBlue');A registered theme is available to every chart instance immediately. The full
Theme contract (37 tokens) is exported from tickwick/theme.
Use the canonical token names. An unrecognised key is silently ignored rather
than rejected, so a plausible-looking guess (upColor, panelBackground,
yAxisGridColor) leaves that part of the chart on the default theme with no
warning. Import the type and let TypeScript check the object:
import type { Theme } from 'tickwick/theme';
const brand: Partial<Theme> = { candleColorUp: '#22c55e' };Plugin system
Register extensions without touching library source. Four registries back it — drawing tools, indicators, chart types and themes:
import { registerPlugin } from 'tickwick/plugin';
registerPlugin({
name: 'my-plugin',
themes: [{ name: 'myTheme', theme: { /* Theme */ } }],
indicators: [
{
id: 'VWAP',
label: 'VWAP',
paneType: 'overlay', // or 'separate' for its own subpane
defaultConfig: { color: '#FF9800' },
calculate(indicator, rows) { // annotate each row in place
for (const row of rows) row[indicator.uniqueId] = row[4];
},
// draw(indicator, indicatorRenderer, renderer) — the third arg is the
// pane's ChartRenderer, needed only by `drawPaneSeries`.
draw(indicator, indicatorRenderer) {
indicatorRenderer.drawOverlaySeries(indicator, [{ key: null, color: indicator.color }]);
},
},
],
drawingTools: [{ id: 'my-arrow', ctor: MyArrowDrawer }],
});Granular entry points are also exported: registerTheme, registerIndicator,
registerDrawingTool, registerChartType.
LLM / prompt-to-chart
ChartConfig is JSON-serialisable, so a model can emit one directly:
TickwickChart.createFromConfig('#chart', {
data,
theme: 'aurora',
panes: [
{ type: 'candles', indicators: [{ type: 'SMA', period: 50 }, { type: 'RSI', period: 14 }] },
],
});Use getAvailableThemes() and getSupportedIndicators() to build the tool
schema you hand the model, so it can only name things this build actually has.
Script tag (UMD)
<link rel="stylesheet" href="https://unpkg.com/tickwick/dist/tickwick-widget.css" />
<script src="https://unpkg.com/tickwick/dist/tickwick-widget.umd.cjs"></script>
<script>
// The UMD build exposes the module namespace as the global `TickwickChart`,
// so the class itself is `TickwickChart.TickwickChart`.
const chart = TickwickChart.TickwickChart.create({
container: '#chart',
data: TickwickChart.generateRandomData(500),
theme: 'onyx',
height: 600,
});
</script>The script-tag build ships English only — a UMD bundle cannot code-split, so
the locale chunks are ES-build only. setMessages() still works.
Entry points
| Import | Purpose |
|--------|---------|
| tickwick | TickwickChart, data helpers, types |
| tickwick/style.css | Widget styles |
| tickwick/plugin | registerPlugin and the granular register* functions |
| tickwick/react | React component |
| tickwick/vue | Vue 3 component |
| tickwick/theme | The Theme contract and the 10 bundled palettes |
Source subpaths
Beyond those, the package exposes internals — tickwick/ta,
tickwick/data/DataHandler, tickwick/drawing/tools/BaseTool,
tickwick/terminal/Terminal.svelte and friends — as raw .ts / .svelte
source. They exist so plugins (including tickwick-pro) can build against the
same types the library uses internally. Importing one requires a build setup
that compiles TypeScript and Svelte from node_modules — Vite and SvelteKit do
this out of the box; plain Node, Jest without a transform, or a bare webpack
config will not. Treat them as a plugin-author surface, not part of the stable
public API.
Documentation and links
| Where | What you'll find | |---|---| | docs.tickwick.co | Full documentation — guides, API reference, options, theming, plugin authoring | | tickwick.co | Project website | | tickwick.co/demo | Live interactive demo | | tickwick.co/playground | Build a config in the browser and copy the code | | tickwick.co/features | Feature-by-feature tour, free and Pro | | tickwick.co/components | The Pro terminal component library, live | | tickwick.co/ai | Prompt-to-chart / LLM integration | | tickwick.co/pricing | Tiers and licensing | | GitHub · Issues | Source, bug reports, feature requests | | npm | Published package and release history |
Contributing
npm install
npm run build # ES + UMD bundles → dist/
npm run check # svelte-check + tsc
npm run test:unit # vitestSee CONTRIBUTING.md for the layout, the conventions worth knowing before you start, and what a reviewable change looks like. Security issues go through SECURITY.md — please don't open a public issue for those.
Pro edition (optional)
tickwick-pro is a commercial, licence-gated
plugin that layers on 7 more chart types (10 in total), 115 more indicators
(129 in total, including 23 candlestick patterns), 31 more drawing tools (34 in
total), auto-analysis, event markers, backtesting, replay, export, workspaces
and 9 more languages (10 in total), and removes the watermark. It also ships a
terminal component library — 52 components (Watchlist, OrderBook,
OrderTicket, OptionsChain, CandleChart, Backtest, …) — as a tree-shakeable
bonus entry.
It peer-depends on tickwick and plugs in only after a valid licence verifies;
with no licence it behaves exactly like the free widget. The OSS library is
complete without it.
See the feature comparison, the component gallery or the Pro docs.
License
MIT © Tickwick
