Realtime Bars
Realtime subscriptions keep the active symbol and interval live once historical bars have loaded. Three behaviors define a correct subscription: the last candle ticks in place, a new candle appears when the interval rolls over, and a correction reloads without leaving a stale bar behind.
Who owns what
- The chart calls
subscribeRealTimeBars(subscription, callback)once per active symbol/interval and later calls the returnedUnsubscribefunction when the symbol, interval, or chart goes away. - Your feed owns the transport (WebSocket, SSE, polling) and pushes complete
Barobjects throughcallback. - The SDK decides update-vs-append purely from
bar.time— there is no separate "update" API.
Minimal working path
const datafeed: MarketDataFeed = {
async loadBars(symbol, interval, request) {
return fetchBars(symbol, interval, request);
},
subscribeRealTimeBars(subscription, callback) {
const socket = connectBarStream(
subscription.symbol.ticker,
subscription.interval,
);
socket.onBar((bar) => callback(bar)); // complete Bar, ms timestamp
return () => socket.close(); // Unsubscribe
},
};
Advertise the capability with supportsRealTime: true from onReady().
Checkpoint: with the feed connected to a live source, the last candle's close/high/low/volume change in place between interval boundaries, and exactly one new candle appears at each boundary.
Update vs. append, with concrete values
Suppose the last chart bar is the 1m bar for 13:30:00Z:
{ time: Date.parse('2026-07-09T13:30:00Z'),
open: 187.2, high: 187.4, low: 187.1, close: 187.3, volume: 1200 }
Same timestamp → update in place. A trade prints inside the same minute;
emit the whole bar again with the same time:
callback({ time: Date.parse('2026-07-09T13:30:00Z'),
open: 187.2, high: 187.5, low: 187.1, close: 187.5, volume: 1450 });
| Field | Before | After |
|---|---|---|
high | 187.4 | 187.5 |
close | 187.3 | 187.5 |
volume | 1200 | 1450 |
| Bar count | n | n (unchanged) |
Newer timestamp → append. The minute rolls over; emit the next bar:
callback({ time: Date.parse('2026-07-09T13:31:00Z'),
open: 187.5, high: 187.6, low: 187.4, close: 187.6, volume: 300 });
Bar count becomes n + 1. If the user is at the right edge, the viewport stays locked to the latest bar; if they have scrolled back, the viewport does not jump.
Older timestamp → not a realtime update. A bar older than the last chart
bar is an out-of-order correction. Do not emit it through callback; call
subscription.onResetCacheNeeded?.() and let the SDK clear cached bars and
refetch visible history.
Subscription lifecycle
On unsubscribe, stop emitting immediately: callbacks after unsubscribe are a
bug in the feed. On reconnect, if the stream may have dropped ticks, prefer
onResetCacheNeeded over guessing — the SDK refetches through loadBars, so
the repaired history comes from your source of truth.
Corrections and cache reset
Use same-timestamp realtime bars for edits to the currently open bar. Use
onResetCacheNeeded for corrections to older bars, vendor reconnect repairs,
split adjustments, or any event where the visible history may no longer match
the feed's source of truth.
onResetCacheNeeded clears SDK-held cache entries for the subscribed
symbol/interval and asks the chart to reload. If the feed owns additional
history caches, implement resetCache(request) as well so host calls such as
chart.resetCache() clear both SDK and feed-side state.
Full contract
RealTimeBarSubscription and callback types
export interface RealTimeBarSubscription {
id: string;
symbol: SymbolInfo;
interval: ChartInterval;
transport?: RealTimeTransportOptions;
metadata?: Record<string, unknown>;
onResetCacheNeeded?: () => void;
}
export type RealTimeBarCallback = (bar: Bar) => void;
export type Unsubscribe = () => void;
id is a stable subscription identifier assigned by the chart; use it to key
feed-side subscription state. Bar.time is Unix milliseconds, matching
historical bars.
Next steps
- Session Filtering — drop bars outside included session states before they reach the chart.
- Order Flow — depth and tape streams for microstructure views.