Tiempo real y repetición

Transmite datos en vivo, agrega ticks en barras y repite datos históricos a una velocidad controlada.

Adaptadores integrados

Todos gratuitos y sin clave de API; se conectan todos de la misma forma:

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' })

Interfaz DataAdapter

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

  // Optional
  fetchHistoryBefore?(symbol, timeframe, before, limit): Promise<OHLCBar[]>
  searchSymbols?(query, options?): Promise<SymbolInfo[]>
  resolveSymbol?(symbol): Promise<SymbolInfo | null>
  subscribeQuotes?(symbols, onQuotes): () => void      // a watchlist's rows
  fetchNews?(symbol, limit?): Promise<NewsItem[]>       // the symbol info panel
  fetchTrades?(symbol, limit?): Promise<Trade[]>        // tick charts, with
  subscribeTrades?(symbol, onTrades): () => void        // subscribeTrades
}

Cualquier fuente de datos en ~20 líneas

Extiende WebSocketAdapter (en vivo + historial por REST) o PollingAdapter (fuentes solo REST). La clase base se encarga del ciclo de vida de la conexión, la reconexión, la decodificación y la emisión de eventos; tú solo aportas una URL y una función de análisis.

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 }),
})

Agregación de ticks

Agrupa los ticks sin procesar en barras OHLC para cada temporalidad:

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

Cotizaciones de muchos símbolos

Una fuente con subscribeQuotes envía cotizaciones (último precio, variación del día, máximo, mínimo, volumen, compra y venta) de muchos símbolos a la vez hasta que la detienes. BinanceAdapter envía una instantánea de 24 h y luego su flujo mini-ticker; MockAdapter se inventa las cotizaciones. La lista de seguimiento de un widget llena sus filas con ellas.

const stop = new BinanceAdapter().subscribeQuotes(['BTCUSDT', 'ETHUSDT'], (quotes) => {
  for (const q of quotes) console.log(q.symbol, q.last, q.changePercent)
})
stop()

readQuote({ symbol: 'AAPL', last: 190, prevClose: 188 })   // → change 2, changePercent 1.06

Gráficos de ticks

Una temporalidad de ticks — '100T' — dibuja una barra cada 100 operaciones. Se construye con las operaciones de la fuente: las recientes para el historial (fetchTrades) y después las que llegan en vivo (subscribeTrades). BinanceAdapter transmite operaciones agregadas. Un gráfico de ticks no tiene cuenta atrás ni carga historial más antiguo; una fuente sin operaciones rechaza las temporalidades de ticks.

chart.connect({ adapter: new BinanceAdapter(), symbol: 'BTCUSDT', timeframe: '100T' })
await chart.setTimeframe('500T')

// Your own trades into tick bars
const builder = new TickBarBuilder(100)
builder.push([{ time, price, volume }])   // → [{ bar, closed }]

Estado del mercado y noticias

marketStatus(info, now) indica si el mercado de un símbolo está abierto en un momento dado, a partir de su horario en la zona de su bolsa (con los cambios de hora incluidos), y cuándo cambia eso. Las sesiones pueden indicar los días de la semana en que abren. El fetchNews de una fuente da titulares para el panel de información del símbolo del widget; readNews solo conserva los elementos con título y hora, y solo los enlaces a páginas web.

const info = {
  symbol: 'AAPL',
  timezone: 'America/New_York',
  sessions: [{ start: '09:30', end: '16:00', days: [1, 2, 3, 4, 5] }],
}
marketStatus(info, Date.now())   // { state: 'closed', next: <next open, ms> } · 'open' · 'always' (24/7)

Reconexión

ReconnectManager gestiona un retroceso exponencial con un límite y una renuncia final.

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

Modo de repetición

Hace avanzar una DataSeries histórica a una velocidad controlada. Está desacoplado de Chart, así que sirve tanto para la repetición en la interfaz como para backtests sin interfaz.

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)

En el modo de repetición del widget, haz clic en cualquier barra ya mostrada para llevar ahí el cursor de la repetición. De forma más general, el gráfico emite ahora los eventos click y barClick con los clics izquierdos simples (pulsar y soltar sin arrastrar):

chart.on('barClick', (e) => {
  const { bar, barIndex, point } = e.payload
})

Repetición en el gráfico, en pasos más finos

chart.replayStart() repite la propia serie del gráfico. Pásale barras más finas como steps (barras de 5 minutos bajo un gráfico horario) y cada paso hace crecer con ellas la barra en formación, tal como creció en el mercado; las barras cerradas se muestran tal como están en la serie. startIndex y replaySeekToBar cuentan las barras del gráfico. En ChartWidget, el menú Paso de la barra de repetición ofrece los intervalos más finos que tiene la fuente (o que se pueden construir con las barras que cargaste).

const steps = await adapter.fetchHistory('BTCUSDT', '5m', 2000)
chart.replayStart({ steps, startIndex: 120, paused: true, speed: 5 })
chart.replayResume()
chart.getReplayBarIndex()      // the chart bar forming now
chart.replaySeekToBar(150)     // to the end of bar 150
chart.replaySeekToTime(t)      // to the bars that opened before t
chart.on('replayStep', (e) => e.payload)    // { barIndex, time, until }
chart.on('replayState', (e) => e.payload)   // { state: 'playing' | 'paused' | 'stopped' }
chart.replayStop()             // back to the live series

Trading simulado en una repetición

Un adaptador de ejecución con setMarkPrice(price, time) (como PaperExecutionAdapter) opera sobre la repetición: durante una repetición, el gráfico le pasa cada precio y hora repetidos, así que las órdenes y los stops se ejecutan cuando la repetición pasa por ellos y las ejecuciones quedan sobre las barras repetidas. Cuentan el mínimo y el máximo de cada paso, y un salto hacia delante pasa por todos los pasos intermedios. Solo avanza: tras un salto hacia atrás, espera a que la repetición supere el punto más lejano que ha visto. Mientras tanto, el precio en vivo no lo mueve; cuando termina la repetición vuelve al precio en vivo, y las ejecuciones, a la hora real. Las alertas de precio siguen vigilando el mercado en vivo todo el tiempo; las alertas sobre líneas de indicador esperan a que termine la repetición.

chart.connectExecution(new PaperExecutionAdapter())
chart.replayStart({ startIndex: 300, paused: true })
// place orders from the chart or the order ticket, then play

API

MétodoFunción
start()Empieza a emitir desde el índice actual.
pause() / resume()Pausa/reanuda el temporizador.
step(n)Emite N barras de forma síncrona, sin el temporizador.
seek(index)Salta sin emitir las barras intermedias.
setSpeed(bps)Barras por segundo (con un mínimo de 0.01).
destroy()Elimina el temporizador y los listeners.

Consulta Análisis para usar la repetición junto con el backtester.