Skip to main content
Combine the REST candlestick endpoint with WebSocket venue_candle events to build a live chart.

Step 1: Fetch Initial Data

// GET /charts/candlesticks
const { data } = await client.getChartCandlesticks({
  marketId: "market-123",
  interval: "5m",
  startTs: Date.now() - 24 * 60 * 60 * 1000, // 24h ago
  endTs: Date.now(),
});

// data = [{ venue: "kalshi", candles: [{ t, o, h, l, c, v }, ...] }, ...]
// Flatten into a single array for your chart library
let candles = data.flatMap((d) => d.candles).sort((a, b) => a.t - b.t);

Step 2: Connect WebSocket

const ws = new WebSocket(`wss://ws.agg.market/ws?appId=${appId}`);

ws.onopen = () => {
  ws.send(JSON.stringify({
    action: "subscribe",
    marketIds: ["market-123"],
  }));
};

Step 3: Merge Live Candles

The WebSocket sends venue_candle events with this shape:
{
  "type": "venue_candle",
  "marketId": "market-123",
  "venue": "kalshi",
  "interval": "5m",
  "openTime": 1710705000000,
  "o": 0.55, "h": 0.58, "l": 0.54, "c": 0.57,
  "v": 150,
  "isFinal": false,
  "timestamp": 1710705123456
}
Merge logic:
ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);

  if (msg.type === "venue_candle" && msg.interval === "5m") {
    const lastCandle = candles[candles.length - 1];

    if (msg.isFinal) {
      // Candle is closed — finalize and prepare for next
      if (lastCandle && lastCandle.t === msg.openTime) {
        // Update the last candle with final values
        lastCandle.o = msg.o;
        lastCandle.h = msg.h;
        lastCandle.l = msg.l;
        lastCandle.c = msg.c;
        lastCandle.v = msg.v;
      } else {
        // Append as new finalized candle
        candles.push({ t: msg.openTime, o: msg.o, h: msg.h, l: msg.l, c: msg.c, v: msg.v });
      }
    } else {
      // Candle is still forming — update in-place
      if (lastCandle && lastCandle.t === msg.openTime) {
        lastCandle.h = Math.max(lastCandle.h, msg.h);
        lastCandle.l = Math.min(lastCandle.l, msg.l);
        lastCandle.c = msg.c;
        lastCandle.v = msg.v;
      } else {
        // New forming candle
        candles.push({ t: msg.openTime, o: msg.o, h: msg.h, l: msg.l, c: msg.c, v: msg.v });
      }
    }

    // Update your chart
    updateChart(candles);
  }
};

Liveline (Line Chart Mode)

For a simple line chart, use only the c (close) price:
const lineData = candles.map((c) => ({ time: c.t, value: c.c }));

TradingView (Candlestick Mode)

For TradingView, use the full OHLCV:
const tvCandles = candles.map((c) => ({
  time: c.t / 1000, // TradingView uses seconds
  open: c.o,
  high: c.h,
  low: c.l,
  close: c.c,
  volume: c.v,
}));