Skip to main content

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

MethodDescription
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.

ShortFormProvider

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

KeyCoin
'btc'Bitcoin
'eth'Ethereum
'sol'Solana
'xrp'XRP
'doge'Dogecoin
'hype'Hype
'bnb'BNB

Supported Intervals

KeyWindow
'5m'5 minutes
'15m'15 minutes
'1h'1 hour

ShortFormMarket

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)
})