实时数据与回放
接入实时数据流,把 tick 聚合成K线,并以可控的速度回放历史数据。
内置适配器
全部免费,无需 API key——连接方式完全相同:
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 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
} 约 20 行代码接入任意数据源
继承 WebSocketAdapter(实时数据 + REST 历史数据)或 PollingAdapter (仅 REST 的数据源)。基类负责连接生命周期、断线重连、解码和事件派发——
你只需提供一个 URL 和一个解析函数。
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 聚合
按周期把原始 tick 汇总成 OHLC K线:
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 多个品种的报价
带有 subscribeQuotes 的数据源会同时推送多个品种的报价(最新价、当日涨跌、最高价、最低价、
成交量、买价和卖价),直到你停止订阅。BinanceAdapter 先发送 24 小时快照,再接上它的 mini-ticker 流; MockAdapter 会生成模拟报价。组件的自选列表就用它来填充各行。
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 Tick 图
Tick 周期——'100T'——每 100 笔成交画一根K线。它由数据源的成交构建:历史部分用最近的成交
(fetchTrades),之后接入实时成交(subscribeTrades)。BinanceAdapter 推送归集成交
(aggregate trades)。Tick 图没有倒计时,也不会向前分页加载更早的历史;不提供成交的数据源会拒绝 tick 周期。
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 }] 市场状态与新闻
marketStatus(info, now) 根据品种在其交易所时区内的交易时段(包括夏令时切换),判断某一时刻市场是否开放,
以及何时会发生变化。交易时段可以指定一周中开放的日子。数据源的 fetchNews 为组件的品种信息面板提供新闻标题; readNews 只保留带标题和时间的条目,并且只保留指向网页的链接。
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) 断线重连
ReconnectManager 负责带上限的指数退避,并在最终失败时放弃重连。
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 回放模式
以可控的速度向前推进一段历史 DataSeries。
它与 Chart 解耦,因此既能驱动界面上的回放,也能用于无界面的回测。
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)
在组件的回放模式中,点击任意已显示的K线,回放光标即跳到该处。
更一般地,图表现在会在普通的左键单击(按下并松开、中间没有拖动)时发出 click 和 barClick 事件:
chart.on('barClick', (e) => {
const { bar, barIndex, point } = e.payload
}) 在图表上按更细的步长回放
chart.replayStart() 回放图表自身的序列。把更小周期的K线作为 steps 传入(例如小时图下的 5 分钟K线),每一步都会用它们让正在形成的K线逐渐长成,
就像它当初在市场中形成时那样;已收盘的K线则按序列中的原样显示。 startIndex 和 replaySeekToBar 按图表的K线计数。
在 ChartWidget 中,回放栏的步长菜单会列出数据源提供的更小周期
(或由你加载的K线能够合成的周期)。
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 在回放中模拟交易
带有 setMarkPrice(price, time) 的执行适配器(如 PaperExecutionAdapter)可以在回放中交易:回放期间,图表会把每个回放出的价格和时间交给它,
因此订单和止损会在回放经过时成交,成交也会落在回放的K线上。每一步的最低价和最高价都会计入,
向前跳转会经过途中的每一步。它只会向前推进:向后跳转后,它会等到回放越过它见过的最远位置。
这期间实时价格不会影响它;回放结束后,它会回到实时价格,成交时间也回到实际时钟。
价格提醒在整个过程中始终监控实时行情;基于指标线的提醒则会等到回放结束。
chart.connectExecution(new PaperExecutionAdapter())
chart.replayStart({ startIndex: 300, paused: true })
// place orders from the chart or the order ticket, then play API
| 方法 | 用途 |
|---|---|
start() | 从当前索引开始推送。 |
pause() / resume() | 暂停 / 继续计时器。 |
step(n) | 不经过计时器,同步推送 N 根K线。 |
seek(index) | 直接跳转,不推送中间的K线。 |
setSpeed(bps) | 每秒推送的K线数(最小为 0.01)。 |
destroy() | 清除计时器和监听器。 |
如何将回放与回测器配合使用,请参见 分析。