リアルタイムとリプレイ
ライブデータをストリーミングし、ティックをバーに集計し、過去のデータを速度を制御しながらリプレイします。
組み込みアダプター
すべて無料で、API キーは不要です。どれも同じ方法で接続できます:
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 }),
}) ティックの集計
生のティックを、時間足ごとの OHLC バーにまとめます:
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 時間のスナップショットを送ったあと、
ミニティッカーのストリームを流します。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 ティックチャート
ティックの時間足 — '100T' — は 100 約定ごとに 1 本のバーを描きます。フィードの約定から組み立て、
履歴には直近の約定(fetchTrades)、その後はライブの約定(subscribeTrades)を使います。 BinanceAdapter は集約約定(aggregate trades)をストリーミングします。ティックチャートにはカウントダウンがなく、
さらに古い履歴も読み込みません。約定を提供しないフィードはティックの時間足を受け付けません。
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 は
タイトルと時刻のある項目だけを残し、リンクも 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) 再接続
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 から切り離されているため、UI でのリプレイにもヘッドレスのバックテストにも使えます。
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)
ウィジェットのリプレイモードでは、表示済みのバーをクリックすると、リプレイのカーソルが
そこへ移動します。より一般的には、チャートは通常の左クリック(ドラッグせずに押して離す操作)に対して click と barClick イベントを発行するようになりました:
chart.on('barClick', (e) => {
const { bar, barIndex, point } = e.payload
}) チャート上のリプレイを細かいステップで
chart.replayStart() は、チャート自身の系列をリプレイします。下位足のバーを steps として渡すと(1 時間足のチャートに 5 分足のバーなど)、各ステップでそれらから形成中のバーが
育っていきます。実際の市場で形成されたときと同じです。確定済みのバーは系列にあるとおりに表示されます。 startIndex と replaySeekToBar はチャートのバーで数えます。
ChartWidget では、リプレイバーのステップメニューに、フィードが持つ下位の時間足
(または読み込んだバーから組み立てられる時間足)が並びます。
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 リプレイ中のペーパー取引
PaperExecutionAdapter のように setMarkPrice(price, time) を持つ実行アダプターは、
リプレイ上で取引します。リプレイ中、チャートはリプレイされる価格と時刻を順に渡すので、注文や損切りは
リプレイがその価格を通過したときに約定し、約定はリプレイ中のバーの上に記録されます。各ステップの安値と高値が
考慮され、先へジャンプすると途中のステップをすべて通過します。進むのは前方向だけで、後ろへシークした後は、
リプレイがそれまでに見た最も先の地点を越えるまで待ちます。
その間、ライブ価格の影響は受けません。リプレイが終わるとライブ価格に戻り、約定時刻も実際の時計に戻ります。
価格アラートは、その間もずっとライブの市場を監視し続けます。インジケーターのラインに対するアラートは、
リプレイが終わるまで待機します。
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 本のバーを同期的に発行します。 |
seek(index) | 間のバーを発行せずに移動します。 |
setSpeed(bps) | 1 秒あたりのバー数(>= 0.01 に制限)。 |
destroy() | タイマーとリスナーを解除します。 |
バックテスターとリプレイを組み合わせて使う方法は、分析を参照してください。