Watchlists
Track symbols in the right sidebar. Click a symbol to load it on the chart. Add via + button, remove via X, reorder by drag and drop. Multiple watchlists with configurable names.
Configuration
new ChartSpire({
watchListEnabled: true,
watchListAmount: 5,
watchListLimit: 50,
watchListHttp: false,
watchListHttpInterval: 5000,
watchListHttpBatchSize: 10,
watchListHttpRetryEnabled: true,
watchListHttpMaxRetries: 3,
watchListSubscriptionDelayMs: 0,
watchListUseExternalStorage: false,
enabledSymbolTypes: [SYMBOL_TYPE.STOCKS, SYMBOL_TYPE.CRYPTO],
// ...
})| Option | Type | Default | Description |
|---|---|---|---|
watchListEnabled | boolean | false | Enable watchlist panel |
watchListAmount | number | 5 | Number of watchlists |
watchListLimit | number | 50 | Max symbols per watchlist |
watchListHttp | boolean | false | Use HTTP polling instead of WebSocket for prices |
watchListHttpInterval | number | 5000 | Poll interval (ms, min: 1000) |
watchListHttpBatchSize | number | 10 | Symbols per batch when polling |
watchListHttpRetryEnabled | boolean | true | Retry on failure |
watchListHttpMaxRetries | number | 3 | Max retries |
watchListSubscriptionDelayMs | number | 0 | Delay (ms) between each symbol when bulk-subscribing to the data feed. 0 subscribes all symbols immediately. Unsubscribe and panel cleanup always run immediately. Use only if your backend needs client-side pacing; prefer server rate limiting when possible. |
watchListUseExternalStorage | boolean | false | Use callbacks instead of localStorage |
Price Data
WebSocket (default): Uses subscribeSymbol/unsubscribeSymbol for real-time prices. Watchlist symbols use a stable subscriber namespace (watchlist_{symbol}_{exchange}) so reopening the panel reuses the same logical subscription per symbol and shares backend channels with chart subscribers when the symbol and interval match.
HTTP polling: Set watchListHttp: true. DataFeed must implement getPrice(symbol, type) returning Promise<number | null>. Polls at watchListHttpInterval (min 1000ms).
Bulk subscribe pacing: watchListSubscriptionDelayMs staggers only bulk subscribe operations (opening a watchlist or switching watchlists). The first symbol subscribes immediately; each additional symbol waits index × watchListSubscriptionDelayMs milliseconds. Closing the watchlist cancels any pending subscribe timers and unsubscribes synchronously.
Symbol Type Filtering
enabledSymbolTypes restricts which symbol types appear in watchlists and search. Omit or use [] for all types.
enabledSymbolTypes: [SYMBOL_TYPE.STOCKS, SYMBOL_TYPE.CRYPTO]External storage warning: With enabledSymbolTypes and external storage, the frontend only loads and sends enabled types. If the backend overwrites the full watchlist on save, symbols of other types will be lost. Backend should merge by watchlist name instead of full replace.
External Storage
External storage persists watchlist data to your backend instead of localStorage. Set callbacks before creating the chart:
import { ChartSpire, setWatchListChangeCallback, setGetWatchListsCallback } from 'chartspire'
setWatchListChangeCallback((watchlist) => {
fetch('/api/watchlist', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(watchlist)
})
})
setGetWatchListsCallback(async () => {
const res = await fetch('/api/watchlist')
return res.ok ? await res.json() : null
})
new ChartSpire({
watchListEnabled: true,
watchListUseExternalStorage: true,
// ...
})Data Structure
SymbolInfoMap = Record<string, Symbol[]> — watchlist name → array of symbols.
{
"WatchList 1": [
{ symbol: "AAPL", type: "stocks", name: "Apple Inc", exchange: "NASDAQ" },
{ symbol: "MSFT", type: "stocks", name: "Microsoft", exchange: "NASDAQ" }
],
"WatchList 2": [
{ symbol: "BTCUSDT", type: "crypto", name: "Bitcoin/USDT", exchange: "binance" }
]
}Symbol type uses SYMBOL_TYPE values: 'stocks', 'crypto', 'forex', 'futures', etc.
Limits
- Max symbols per watchlist:
watchListLimit(default 50) - No duplicate symbols in the same watchlist
- localStorage: ~5MB per domain (when not using external storage)