# Chart example

> Draw a live candlestick and volume chart for any Robinhood Chain token with the Crius candles endpoint and TradingView Lightweight Charts, with full source code.

Source: https://crius.sh/docs/examples/chart/

A live candlestick chart with volume for any Robinhood Chain token (here Tesla's tokenized stock, TSLA), built on [`/candles`](https://crius.sh/docs/reference/trades/#ohlcv-candles) and [TradingView Lightweight Charts](https://github.com/tradingview/lightweight-charts). Paste any token address or pick an interval; it refreshes every 15 seconds.

*(Live chart: open https://crius.sh/docs/examples/chart/ in a browser.)*

## The code

The candles endpoint returns **columnar** arrays (`t`, `o`, `h`, `l`, `c`, `v`), which map straight onto chart series:

```html
<div id="chart" style="height: 420px"></div>
<script type="module">
  import { createChart, CandlestickSeries, HistogramSeries } from "https://unpkg.com/lightweight-charts@5.2.1/dist/lightweight-charts.standalone.production.mjs";

  const token = "0x322f0929c4625ed5bad873c95208d54e1c003b2d"; // TSLA, Tesla tokenized stock
  const res = await fetch(`https://api.crius.sh/v1/robinhood/token/${token}/candles?interval=15m&limit=300&fill=true`);
  const { data } = await res.json();

  const chart = createChart(document.getElementById("chart"), { autoSize: true });
  const candles = chart.addSeries(CandlestickSeries);
  const volume = chart.addSeries(HistogramSeries, { priceScaleId: "", priceFormat: { type: "volume" } });
  volume.priceScale().applyOptions({ scaleMargins: { top: 0.8, bottom: 0 } });

  candles.setData(data.t.map((t, i) => ({
    time: t / 1000, // the API uses unix milliseconds; the chart wants seconds
    open: data.o[i], high: data.h[i], low: data.l[i], close: data.c[i],
  })));
  volume.setData(data.t.map((t, i) => ({ time: t / 1000, value: data.v[i] })));
  chart.timeScale().fitContent();
</script>
```

## Make it real-time

Polling works, but the [WebSocket stream](https://crius.sh/docs/reference/stream/) pushes the live candle as trades happen. Subscribe to `candles:<token>:<interval>` and update the last bar:

```js
// Run this where your key is safe (your backend, a desktop app), never in a public page.
const ws = new WebSocket(`wss://api.crius.sh/v1/robinhood/stream?api_key=${KEY}`);
ws.onopen = () => ws.send(JSON.stringify({ op: "subscribe", channels: [`candles:${token}:15m`] }));
ws.onmessage = (e) => {
  const m = JSON.parse(e.data);
  if (!m.ch.startsWith("candles:")) return;
  const c = m.data;
  candles.update({ time: c.t / 1000, open: c.o, high: c.h, low: c.l, close: c.c });
  volume.update({ time: c.t / 1000, value: c.v });
};
```

> **Tip:**
> Meme tokens trade at tiny prices. Set the series' `priceFormat.precision` from the last close (for example 10
> decimals for $0.0000057) so the axis stays readable. Use `currency=quote` to chart in the pool's quote token (ETH)
> instead of USD.
