Realtime & replay
Stream live data, aggregate ticks into bars, and replay historical data at controlled speed.
Built-in adapters
All free, no API key — connect any of them the same way:
import { BinanceAdapter, CoinbaseAdapter, BybitAdapter, KrakenAdapter } from '@tradecanvas/chart'
chart.connect({ adapter: new BinanceAdapter(), symbol: 'BTCUSDT', timeframe: '1m' })
chart.connect({ adapter: new BybitAdapter(), symbol: 'BTCUSDT', timeframe: '1m' })
chart.connect({ adapter: new KrakenAdapter(), symbol: 'BTC/USD', timeframe: '5m' })
chart.connect({ adapter: new CoinbaseAdapter(), symbol: 'BTC-USD', timeframe: '15m' }) DataAdapter interface
interface DataAdapter {
name: string
connect(config): void
disconnect(): void
getConnectionState(): ConnectionState
fetchHistory(symbol, timeframe, limit?): Promise<OHLCBar[]>
on(event, listener): void // 'bar' | 'tick' | 'snapshot' | 'connectionChange' | 'error'
off(event, listener): void
dispose(): void
} Any feed in ~20 lines
Extend WebSocketAdapter (live + REST history) or PollingAdapter (REST-only feeds). The base handles the connection lifecycle, reconnect, decoding, and
event emission — you supply a URL and a parse function.
import { WebSocketAdapter } from '@tradecanvas/chart'
const myAdapter = new WebSocketAdapter({
name: 'myexchange',
wsUrl: (c) => 'wss://api.myexchange.com/ws/' + c.symbol + '@kline_' + c.timeframe,
fetchHistory: (symbol, tf, limit) => fetch('/candles?...').then((r) => r.json()),
parseMessage: (raw) => ({ bar: toBar(raw), closed: raw.k.x }),
}) Tick aggregation
Roll raw ticks into OHLC bars per timeframe:
import { TickAggregator } from '@tradecanvas/chart'
const agg = new TickAggregator('1m')
agg.processTick({ time, price, volume })
const current = agg.getCurrentBar() // forming bar
const closed = agg.flushClosedBars() // bars that have rolled over Reconnect
ReconnectManager handles exponential backoff with a cap and a final give-up.
import { ReconnectManager } from '@tradecanvas/chart'
const rm = new ReconnectManager({ maxRetries: 6, baseDelay: 500, maxDelay: 30_000 })
rm.start()
rm.schedule(() => connectWebsocket()) // call on disconnect; backs off automatically
rm.onConnected() // call on a successful connect to reset Replay mode
Drive a historical DataSeries forward at controlled speed.
Decoupled from Chart so it can power both UI replay and headless
backtests.
import { ReplayController } from '@tradecanvas/chart'
const replay = new ReplayController({
data: historicalBars,
speed: 10, // bars per second
startIndex: 0,
})
// Seed the chart with everything before startIndex
chart.setData(replay.getPrefix())
// Wire each emitted bar into the chart
replay.on('bar', ({ bar }) => chart.appendBar(bar))
replay.on('finished', () => console.log('done'))
replay.start()
// replay.pause(); replay.resume(); replay.step(5); replay.seek(200); replay.setSpeed(20)
In the widget's replay mode, click any revealed bar to jump the replay
cursor there. More generally, the chart now emits click and barClick events for plain left-clicks (press and release
without dragging):
chart.on('barClick', (e) => {
const { bar, barIndex, point } = e.payload
}) API
| Method | Purpose |
|---|---|
start() | Begin emitting from current index. |
pause() / resume() | Pause/continue timer. |
step(n) | Emit N bars synchronously without the timer. |
seek(index) | Jump without emitting in-between bars. |
setSpeed(bps) | Bars per second (clamped to >= 0.01). |
destroy() | Clear timer + listeners. |
See Analytics for using replay alongside the backtester.