Data Providers
The Charts SDK includes three data providers that connect to polynode endpoints. All are optional. The chart itself works with any data source.
PolynodeProvider
Full-featured REST provider for market data, candles, search, events, and multi-outcome charts.
import { PolynodeProvider } from 'polynode-charts'
const provider = new PolynodeProvider({
apiKey: 'pn_live_...',
baseUrl: 'https://api.polynode.dev', // default
})
Top Markets
const markets = await provider.markets(10)
// Returns MarketInfo[] sorted by 24h volume
Response:
[
{
"token_id": "82855088893985825781350...",
"question": "US x Iran ceasefire by April 7?",
"slug": "us-x-iran-ceasefire-by-april-7",
"image": "https://polymarket-upload.s3...",
"last_price": 0.999,
"volume_24h": 19542289.32,
"outcomes": ["Yes", "No"],
"condition_id": "0x4c5701bc..."
}
]
Search Markets
const results = await provider.search('bitcoin', 5)
// Returns MarketInfo[] matching query, sorted by volume
Fetch Candles
const candles = await provider.candles(tokenId, '1h')
// Returns OhlcData[] — ready for series.setData()
const series = chart.addCandleSeries()
series.setData(candles)
The first call fetches trades and caches them locally. After that, switching resolution is instant — the SDK rebuilds candles client-side from the cached trades.
Supported resolutions: '1m', '5m', '15m', '1h', '4h', '1d'
Options:
// Fetch more history (default: 30 days)
const candles = await provider.candles(tokenId, '1h', { days: 90 })
Response shape (OhlcData[]):
[
{ "time": 1775826000000, "open": 0.54, "high": 0.55, "low": 0.52, "close": 0.54, "volume": 1200 }
]
Price History (Line/Area Charts)
For simple {time, value} points (faster than candles — one HTTP call, no pagination):
const history = await provider.priceHistory(tokenId, '7d')
// Returns LineData[]
const series = chart.addAreaSeries({ color: '#22c55e' })
series.setData(history)
Supported ranges: '1h', '6h', '1d', '7d', '30d', 'all'
candles() fetches trades and builds OHLCV locally. Best for candlestick charts where you need resolution switching.priceHistory() hits the CLOB prices-history endpoint directly. Best for line/area charts where you just need price points over time.
Get Event (Multi-Outcome)
const event = await provider.event('presidential election')
Returns EventInfo | null. The method searches your loaded markets, groups by shared question pattern, and returns all outcomes with prices and colors.
Response:
{
"question": "the 2028 US Presidential Election",
"slug": "presidential-election-winner-2028",
"condition_id": "0x...",
"image": "https://...",
"volume_24h": 2847291,
"outcomes": [
{ "name": "Gavin Newsom", "token_id": "98250...", "price": 0.159, "color": "#4378FF" },
{ "name": "Kamala Harris", "token_id": "70663...", "price": 0.032, "color": "#22c55e" },
{ "name": "Ron DeSantis", "token_id": "10448...", "price": 0.021, "color": "#FDC503" }
]
}
Colors are assigned automatically from OUTCOME_COLORS (a 20-color palette).
Multi-Outcome Price History (Batch)
Fetch price history for all outcomes in parallel:
const event = await provider.event('presidential election')
const priceMap = await provider.outcomePrices(event.outcomes, '7d', { maxOutcomes: 5 })
for (const outcome of event.outcomes) {
const data = priceMap.get(outcome.token_id)
if (!data) continue
const series = chart.addLineSeries({ color: outcome.color })
series.setData(data)
}
outcomePrices() is much faster than fetching candles per outcome — one HTTP call each, no trade pagination.
For candlestick data per outcome, use outcomeCandles() instead:
const candleMap = await provider.outcomeCandles(event.outcomes, '4h', { days: 30, maxOutcomes: 5 })
Orderbook Snapshot
const book = await provider.book(tokenId)
// Returns { bids: PriceLevel[], asks: PriceLevel[] }
Poll for Live Updates
const stop = provider.pollPrices(tokenId, (point) => {
series.update(point) // { time, value }
}, { intervalMs: 5000 })
// Stop polling
stop()
For multi-outcome polling:
const stop = provider.pollOutcomePrices(event.outcomes, (tokenId, point) => {
seriesMap.get(tokenId)?.update(point)
}, { intervalMs: 10000, maxOutcomes: 5 })
Market Resolution
All methods accept flexible market identifiers:
- token_id — direct lookup (fastest)
- slug — matched against loaded markets (e.g.
'bitcoin-above-64k')
- condition_id — hex string starting with
0x
Clear Cache
provider.clearCache() // clears trade cache for all markets
MarketInfo
interface MarketInfo {
token_id: string
question: string
slug: string
image: string
last_price: number // 0-1
volume_24h: number // USD
outcomes: string[] // ["Yes", "No"] or ["Up", "Down"]
condition_id?: string
}
PolynodeOBProvider
WebSocket-based orderbook streaming with automatic zlib decompression (uses the native DecompressionStream API, no dependencies).
import { PolynodeOBProvider } from 'polynode-charts'
const ob = new PolynodeOBProvider({
wsUrl: 'wss://ob.polynode.dev/ws', // default
})
ob.subscribe(tokenId, (book) => {
orderbook.update(book) // pass to Orderbook renderer
})
Methods
| Method | Description |
|---|
subscribe(tokenId, callback) | Subscribe to live book updates |
unsubscribe(tokenId) | Stop receiving updates for a token |
connect() | Manually connect (auto-connects on first subscribe) |
disconnect() | Close WebSocket and stop reconnecting |
The provider handles reconnection automatically with exponential backoff (1s to 30s).
Message Types
The provider processes three message types from the orderbook WebSocket:
snapshot_batch — initial full book for all subscribed tokens
book_snapshot — full book replacement for a single token
book_update — incremental update (add/remove/change levels)
All are normalized to BookData before calling your callback.
Discovers short-form crypto markets (5-minute, 15-minute, and hourly up/down markets) and provides live odds rotation. HTTP-only, no WebSocket required.
import { ShortFormProvider } from 'polynode-charts'
const sf = new ShortFormProvider()
One-Shot Discovery
const market = await sf.discover('btc', '15m')
if (market) {
console.log(market.priceToBeat) // 72822.50
console.log(market.upOdds) // 0.62
console.log(market.downOdds) // 0.38
console.log(market.windowEnd) // unix timestamp
}
Auto-Rotation with Live Odds
startRotation() discovers the current window, emits immediately, then polls for updated odds every second and re-discovers at each window boundary.
const stop = sf.startRotation('btc', '15m', (event) => {
// Called on discovery + every odds update
series.setPriceLine(event.market.priceToBeat!, {
color: '#3b82f6',
label: 'PRICE TO BEAT',
})
console.log(`${(event.market.upOdds * 100).toFixed(0)}% up`)
console.log(`${event.timeRemaining}s remaining`)
}, { pollMs: 1000 })
// Stop rotation and polling
stop()
Supported Coins
| Key | Coin |
|---|
'btc' | Bitcoin |
'eth' | Ethereum |
'sol' | Solana |
'xrp' | XRP |
'doge' | Dogecoin |
'hype' | Hype |
'bnb' | BNB |
Supported Intervals
| Key | Window |
|---|
'5m' | 5 minutes |
'15m' | 15 minutes |
'1h' | 1 hour |
interface ShortFormMarket {
coin: ShortFormCoin
slug: string
title: string
conditionId: string
windowStart: number // unix seconds
windowEnd: number // unix seconds
outcomes: string[]
outcomePrices: number[]
clobTokenIds: string[]
upOdds: number // 0-1
downOdds: number // 0-1
liquidity: number
volume24h: number
priceToBeat: number | null
}
RotationEvent
interface RotationEvent {
interval: ShortFormInterval
market: ShortFormMarket
windowStart: number // unix seconds
windowEnd: number // unix seconds
timeRemaining: number // seconds until window closes
}
Options
const sf = new ShortFormProvider({
apiBaseUrl: 'https://api.polynode.dev', // default
rotationBuffer: 3, // seconds after window end before re-discovering (default: 3)
})