Appearance
Data Access
Prerequisite: Load the ChartSpire UI stylesheet once (
import '@chartspire/ui/style.css'). See Getting Started — Stylesheet.
ChartSpire loads all market data through a DataFeed. Use a built-in feed for evaluation, or implement a custom feed for production.
Types: Type Reference. Constructor options: Widget API.
Optional imports (not bundled unless used): @chartspire/ui/datafeeds/default, @chartspire/ui/datafeeds/binance, @chartspire/ui/datafeeds/common. See Getting Started.
Which Feed
| Feed | Use for |
|---|---|
BinanceDataFeed | Crypto demos / evaluation (not production trading) |
DefaultDataFeed | Local evaluation against a compatible HTTP/WS backend |
Custom DataFeed | Production (your provider / infrastructure) |
ChartSpire does not supply market data. You own provider licensing and entitlements.
Method Map
| Feature | Methods |
|---|---|
| Symbol search | searchSymbols |
| Chart history + live | getHistoricalTimeSeries, subscribeSymbol, unsubscribeSymbol |
| Watchlist (WebSocket) | subscribeSymbol |
| Watchlist (HTTP) | getPrice |
| Order book | subscribeOrderBookData / unsubscribeOrderBookData (optional) |
| Trades | subscribeTradeData / unsubscribeTradeData (optional) |
| Teardown | unsubscribeAllForChart, then closeWebsocket when idle |
DefaultDataFeed
Reference adapter for ChartSpire's HTTP/WebSocket contract (auth, reconnect, shared channels). Evaluation only — not a managed data service.
Config and wire format: DefaultDataFeed, Connect Your Backend.
BinanceDataFeed
Public Binance spot REST + WebSocket. No API key.
typescript
import { ChartSpire, SYMBOL_TYPE } from '@chartspire/ui'
import BinanceDataFeed from '@chartspire/ui/datafeeds/binance'
const chartspire = new ChartSpire({
container: document.getElementById('chart-container')!,
enabledSymbolTypes: [SYMBOL_TYPE.CRYPTO],
symbol: { symbol: 'BTCUSDT', type: SYMBOL_TYPE.CRYPTO, exchange: 'binance' },
interval: { multiplier: 1, timespan: 'day', text: 'D' },
dataFeed: new BinanceDataFeed(),
})Limits
- Crypto spot only; demo/evaluation, not trading-grade
- Search is exact symbol lookup (not full-text)
- History returns up to the latest 1000 bars and ignores
from/to— no scroll pagination - Public API rate limits apply
- Instances share one WebSocket controller — create once, reuse
typescript
const dataFeed = new BinanceDataFeed({
rateLimit: {
maxMessages: 4, // per rolling window
windowMs: 1000,
maxQueueSize: 1000,
reconcileDelayMs: 40,
},
onError: (error) => console.error(error),
})rateLimit is applied on first controller creation only.
DataFeed registry
Register a feed class once and pass its name as dataFeed in ChartOptions:
typescript
import { getDataFeedRegistry, ChartSpire } from '@chartspire/ui'
import { MyDataFeed } from './MyDataFeed'
getDataFeedRegistry().registerDataFeed('my-feed', MyDataFeed)
new ChartSpire({
dataFeed: 'my-feed',
// ...
})The registry is process-global (shared across embeds on the page). Prefer passing a DataFeed instance when each embed needs its own feed configuration.
Custom DataFeed
Import DataFeed from @chartspire/ui and implement the required methods. Prefer the exported type over copy-pasting the interface.
Important: shared subscriptions
Charts, watchlists, order book, and trades can all subscribe to the same symbol (and interval) independently. Your feed must track each local subscriber ID, share one backend channel per symbol/exchange/interval/data type, and only unsubscribe from the provider when the last local subscriber is removed. Unsubscribing too early drops data for other components.
Required
searchSymbols(search?, type?)→Symbol[](typeomitted or'all'= no filter)getHistoricalTimeSeries(symbol, period, from, to, type?)→ candles for that interval and ms windowgetPrice(symbol, type?)→number | null(HTTP watchlist)subscribeSymbol/unsubscribeSymbol— live candles for onesubscriberUIDunsubscribeAllForChart(chartId)— drop that chart's handlers onlycloseWebsocket()— stop transport + reconnect timersclearAllListeners()— clear callbacks / subscription stategetActiveSubscriptions()→ active live channel count (0when idle)
Transport is your choice (WebSocket, SSE, polling). Non-WS feeds: implement lifecycle methods as no-ops.
Optional
- Order book:
subscribeOrderBookData/unsubscribeOrderBookData - Trades:
subscribeTradeData/unsubscribeTradeData debugChannels
Disable order book / trades UI if unimplemented. Payloads: Market data.
Contract Rules
Interval-native. History and live must use the requested period. ChartSpire does not aggregate.
Windows. from / to are Unix ms. Return only bars in range, ascending by timestamp. Empty → []. Initial window size: dataFeedInitialHistoricalBars (default 500). Ignoring from/to breaks pagination.
Candles. Millisecond bar-open timestamp; finite open/high/low/close; optional finite volume/turnover. In-progress bar: same open timestamp until the next interval starts.
Live callback. Call callback(candle, symbol). The symbol argument is required for WebSocket watchlists.
subscriberUID. ChartSpire always passes a stable ID (param is optional for compatibility). Key handlers by that ID.
Shared channels. Key by data type + symbol + exchange + interval (+ type when needed). Map subscriberUID → callback. First subscriber opens the backend channel; last removes it. Same ID on re-subscribe replaces the callback. See the Important note above.
Errors. Empty search/history → []. Missing price → null. Subscription methods have no error return — handle failures internally. On reconnect: restore desired subscriptions, avoid duplicates, stop timers in closeWebsocket().
Rate-Limit Helper
Optional outbound control-frame pacing:
typescript
import { RateLimitedWebSocketQueue } from '@chartspire/ui/datafeeds/common'
const outbound = new RateLimitedWebSocketQueue({
maxMessages: 5,
windowMs: 1000,
maxQueueSize: 1000,
onOverflow: (error) => console.error(error),
})
outbound.setSend((frame) => socket.send(frame))
outbound.setReady(true) // after open
const accepted = outbound.enqueue(JSON.stringify(controlFrame))Handle enqueue overflow; setReady(false) on close; rebind after reconnect; destroy() on teardown. Queue does not dedupe or reconcile subscriptions.
Wire It Up
typescript
import { ChartSpire, SYMBOL_TYPE, type DataFeed } from '@chartspire/ui'
import { CustomDataFeed } from './CustomDataFeed'
const dataFeed: DataFeed = new CustomDataFeed()
const chartspire = new ChartSpire({
container: document.getElementById('chart-container')!,
enabledSymbolTypes: [SYMBOL_TYPE.STOCKS],
symbol: { symbol: 'CUSTOM_SYMBOL', type: SYMBOL_TYPE.STOCKS },
interval: { multiplier: 1, timespan: 'day', text: 'D' },
dataFeed,
})
// On unmount:
chartspire.destroy()