Open-source chart for trading apps

A live trading chart for any website.

One <trade-chart> tag gives you smooth real-time prices, candles, indicators, drawing tools and markers for your users' positions. Plain HTML, React, Vue, Angular or Blazor. Configure almost everything. 38 KB compressed, no dependencies.

Get started Read the docs npm i tickline

Live demo

Practice positions (demo of the markers API, no money)

Live prices from Binance's public market data (BTC, ETH, SOL). Drag to look back in time, scroll or pinch to zoom, use the drawing tools on the chart. Hover the chart for zoom, image download and full screen (or press F). Not investment advice.

Feels live, stays simple.

Smooth live prices

The price glides between updates, the live point pulses, the last digits are large, and a countdown shows when the candle closes.

Everything in the box

Candles, bars, Heikin-Ashi, line and area; SMA, EMA, Bollinger Bands, RSI, MACD and volume; trend lines, rectangles, Fibonacci and a measure tool; price alerts. No plugins to write.

Show your users' positions

Markers, entry lines, shaded zones and expiry lines with countdowns. Your app keeps its own trading logic.

Works with any stack

A standard web component: plain HTML, React, Vue, Angular, Svelte or Blazor. Feed it from WebSocket, REST or SignalR.

Any screen, any size

Responsive from small phones to wall screens, with full screen on every device (iPhone included) and one-click image download. 38 KB compressed, no dependencies.

Configure almost everything

Sizes, fonts, axes, crosshair, legend, where the live price sits on screen, zoom limits, gestures, formats, every colour and every word, through one documented options object.

Get started in three steps.

  1. Add Tickline

    From npm, or straight from a CDN with a script tag.

    npm i tickline
    
    // in your app
    import "tickline";
    <!-- or, without a build step -->
    <script src="https://unpkg.com/tickline@0.1.0/dist/tickline.umd.js"></script>
  2. Place the chart

    Give it a height. Attributes set the market name, timeframe, chart type, theme and indicators.

    <trade-chart id="chart" symbol="BTC/USDT" timeframe="1m"
                 type="candles" theme="dark" indicators="sma:20, volume"
                 style="height: 480px"></trade-chart>
  3. Feed it prices

    Load history once, then pass each live trade or quote. Times are milliseconds (UTC).

    const chart = document.getElementById("chart");
    
    // history: [{ time, open, high, low, close, volume }, ...]
    chart.setData(await fetch("/api/candles?tf=1m").then((r) => r.json()));
    
    // live: ticks are grouped into candles for you
    socket.onmessage = (e) => {
      const { time, price, volume } = JSON.parse(e.data);
      chart.tick({ time, price, volume });
    };
    
    // more history when the user scrolls back
    chart.addEventListener("tl-requesthistory", async (e) => {
      const older = await fetch(`/api/candles?tf=1m&before=${e.detail.before}`).then((r) => r.json());
      chart.prependData(older);
    });

Show a position

const now = Date.now(), entry = 68123.45, expiry = now + 60_000;

chart.addMarker({ time: now, price: entry, side: "buy", text: "$10" });
chart.addPriceLine({ price: entry, from: now, to: expiry, color: "#22c38e", label: "Entry" });
chart.addZone({ from: "top", to: entry, start: now, end: expiry, color: "rgba(34,195,142,.08)" });
const line = chart.addTimeLine({ time: expiry, countdown: true, label: "Expiry" });

chart.removeOverlay(line); // every add… returns an id

Use it with your framework.

It's a standard custom element, so every framework can render it. Full examples are in examples/.

import { useEffect, useRef } from "react";
import "tickline";

export function PriceChart({ candles, lastTick }) {
  const ref = useRef(null);
  useEffect(() => { ref.current?.setData(candles); }, [candles]);
  useEffect(() => { if (lastTick) ref.current?.tick(lastTick); }, [lastTick]);
  return <trade-chart ref={ref} symbol="BTC/USDT" timeframe="1m" style={{ height: 480 }} />;
}

Using an AI assistant?

The tickline-mcp server lets Claude, Cursor or VS Code read the docs, look up any setting, check your settings and write the integration code for your framework. Add it once:

claude mcp add tickline -- npx -y tickline-mcp

Setup for Claude Desktop, Cursor and VS Code: mcp/README.md.

Configure almost everything.

One options object controls the chart: sizes, fonts, grid, axes, crosshair, legend, the live price, zoom limits, gestures, animation, formats, colours and every piece of text. Change something below and copy the code.

Show
Allow
Your settings

Every setting, its default and more examples (custom number and date formats, a sparkline, saving a user's chart) are in the configuration guide.

Reference

The most used parts. Everything else, with examples, is in the documentation and the API reference.

Attributes

typecandles, hollow, bars, heikin-ashi, line, area
timeframe5s, 1m, 15m, 1h, 4h, 1d, 1w, 1M …
symbolName in the legend
themedark (default) or light
indicatorssma:20, ema:50, bb:20:2, rsi:14, macd:12:26:9, volume
precisionPrice decimals (default: from the data)
price-lineshort (default), full or none
countdownfalse hides the candle timer
timezonelocal (default) or minutes from UTC, e.g. 420
localede-DE, fr-FR, ja-JP … for numbers and dates
font-sizeBase font size in px (default 11)
crosshairsnap (default), free or hidden
gridboth, horizontal, vertical or none
legendfalse hides the legend
min-visible-candlesFewest candles you can zoom in to
drawing-toolsfalse, or a list: trend, horizontal, fib
controlsnone hides all built-in buttons
live-positioncenter, or x and y such as 0.8 0.5
watermarkFaint text behind the candles: {symbol}
optionsAny settings as JSON

Methods

setData(candles)Replace the history
prependData(candles)Add older candles
tick({ time, price, volume })A live trade or quote
update(candle)A whole live candle (kline streams)
addMarker / addPriceLine / addTimeLine / addZoneOverlays; return an id
updateOverlay(id, patch) / removeOverlay(id)Change or remove one
setOptions(options) / optionsChange any setting; read them all
addIndicator(id, params, style) / removeIndicator(key)Indicators in code, with colours, width, levels
drawings / setDrawings(list)Save and restore drawings
setDrawingTool(tool)line, trend, horizontal, vertical, rect, fib, measure
zoomIn() / zoomOut() / goLive() / fitContent()View
setVisibleRange({ from, to }) / scrollToTime(t)Show a time range
addAlert({ price, label })Price alert; fires tl-alert
downloadImage() / toBlob()The chart as a PNG
toggleFullscreen()Full screen (also the F key)
setLoading(true)Loading placeholder
getState() / setState(s)Save and restore a user's chart

Events

tl-requesthistory{ before }: load older candles
tl-crosshair{ time, price, candle } or null
tl-clickA click on the chart
tl-rangechangeVisible time range
tl-followchangeFollowing the live edge or not
tl-drawingschangeAll drawings, to save
tl-indicatorschangeThe user closed an indicator
tl-zoomlimitZoomed in as far as allowed
tl-alert{ price, direction }: an alert was crossed
tl-fullscreenchange{ fullscreen }

Styling

Every colour is a CSS variable on the element:

trade-chart {
  --tl-background: #0b0f17;
  --tl-up: #22c38e;
  --tl-down: #f0506e;
  --tl-accent: #4c9aff;   /* live price, buttons */
  --tl-line: #4c9aff;     /* line and area */
  --tl-text: #7d8799;
  --tl-grid: rgba(148, 163, 184, .07);
}

Keyboard: ← → pan, + − zoom, End back to live, Home fit all, Esc cancel drawing, Delete removes the selected drawing, F full screen.