Streaming implementation
Add live updates with either subscribeTicks / unsubscribeTicks or subscribeBars / unsubscribeBars (not both).
- Ticks path: push trade ticks; the SDK aggregates them into the active candle.
- Bars path: push complete OHLCV bars for the chart resolution; the SDK applies them directly (no tick aggregation).
If both are implemented on the datafeed, the SDK prefers ticks and ignores bars.
Labs:
phase6-subscribeBars-lab.html— mock bar streamphase6-searchSymbolsPaginated-lab.html— paginated searchphase6-onReady-udf-lab.html—onReady/DatafeedConfiguration+UDFCompatibleDatafeed
How it fits together (ticks)
- History loads via
getBars(previous step). - After the symbol is ready, the chart calls
subscribeTicks(...). - For each trade, call
onRealtimeCallback(tradeMessage). - On symbol change / destroy, the chart calls
unsubscribeTicks(subscriberUID).
Your WebSocket / bus → subscribeTicks → onRealtimeCallback(tick)
↓
SDK aggregates into live barsHow it fits together (bars)
- History loads via
getBars. - The chart calls
subscribeBars(...)with the active chart resolution. - For each bar update, call
onRealtimeCallback({ time, open, high, low, close, volume }). - On symbol change / destroy, the chart calls
unsubscribeBars(subscriberUID).
Your WebSocket / bus → subscribeBars → onRealtimeCallback(bar)
↓
SDK applies host OHLC (no tick aggregation)Trade message shape
{
type: "trade",
productId: "BYBIT:FUTURE:BTCUSDT",
symbol: "BTCUSDT",
exchange: "BYBIT",
segment: "FUTURE",
timeStamp: new Date(), // Date object
tradeID: "abc123",
price: 45123.45,
quantity: 0.123,
amount: 5555.67, // price * quantity
side: "BUY", // or "SELL" (uppercase)
}Implement subscribeTicks / unsubscribeTicks
const datafeed = {
subscriptions: new Map(), // subscriberUID → cleanup
// … resolveSymbol + getBars from the previous page …
subscribeTicks(
symbolInfo,
resolution,
onRealtimeCallback,
subscriberUID,
onResetCacheNeededCallback,
) {
const productId =
symbolInfo.full_name ||
`${symbolInfo.exchange}:${symbolInfo.segment}:${symbolInfo.symbol}`;
const ws = new WebSocket("wss://stream.example.com/trades");
ws.onopen = () => {
ws.send(
JSON.stringify({
op: "subscribe",
symbol: productId,
}),
);
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
const trades = Array.isArray(msg.data) ? msg.data : [msg];
for (const t of trades) {
onRealtimeCallback({
type: "trade",
productId,
symbol: symbolInfo.symbol || symbolInfo.ticker,
exchange: symbolInfo.exchange,
segment: symbolInfo.segment,
timeStamp: new Date(t.time ?? t.T ?? Date.now()),
tradeID: String(t.id ?? t.i ?? `${t.time}-${t.price}`),
price: Number(t.price ?? t.p),
quantity: Number(t.size ?? t.v ?? 0),
amount: Number(t.price ?? t.p) * Number(t.size ?? t.v ?? 0),
side: String(t.side ?? t.S ?? "BUY").toUpperCase(),
});
}
};
this.subscriptions.set(subscriberUID, () => {
try {
ws.close();
} catch (_) {}
});
},
unsubscribeTicks(subscriberUID) {
const cleanup = this.subscriptions.get(subscriberUID);
if (cleanup) {
cleanup();
this.subscriptions.delete(subscriberUID);
}
},
};Checklist
-
subscribeTicksstores cleanup keyed bysubscriberUIDor you usesubscribeBarsinstead (not both) - Each trade calls
onRealtimeCallbackwithtype: "trade"and numericprice(ticks path) -
unsubscribeTicks/unsubscribeBarscloses the socket / cancels the listener - You implement only one realtime path: ticks or bars
Related
- Datafeed API — full contracts including
subscribeBars/searchSymbolsPaginated - Datafeed implementation
- Demo WebSocket API
Last updated on