> ## Documentation Index
> Fetch the complete documentation index at: https://docs.polynode.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Data Providers

> Built-in providers for polynode REST API, orderbook streaming, and short-form market discovery

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

```typescript theme={null}
import { PolynodeProvider } from 'polynode-charts'

const provider = new PolynodeProvider({
  apiKey: 'pn_live_...',
  baseUrl: 'https://api.polynode.dev',  // default
})
```

### Top Markets

```typescript theme={null}
const markets = await provider.markets(10)
// Returns MarketInfo[] sorted by 24h volume
```

**Response:**

```json theme={null}
[
  {
    "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

```typescript theme={null}
const results = await provider.search('bitcoin', 5)
// Returns MarketInfo[] matching query, sorted by volume
```

### Fetch Candles

```typescript theme={null}
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:**

```typescript theme={null}
// Fetch more history (default: 30 days)
const candles = await provider.candles(tokenId, '1h', { days: 90 })
```

**Response shape (`OhlcData[]`):**

```json theme={null}
[
  { "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):

```typescript theme={null}
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'`

<Note>
  `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.
</Note>

### Get Event (Multi-Outcome)

```typescript theme={null}
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:**

```json theme={null}
{
  "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:

```typescript theme={null}
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:

```typescript theme={null}
const candleMap = await provider.outcomeCandles(event.outcomes, '4h', { days: 30, maxOutcomes: 5 })
```

### Orderbook Snapshot

```typescript theme={null}
const book = await provider.book(tokenId)
// Returns { bids: PriceLevel[], asks: PriceLevel[] }
```

### Poll for Live Updates

```typescript theme={null}
const stop = provider.pollPrices(tokenId, (point) => {
  series.update(point)  // { time, value }
}, { intervalMs: 5000 })

// Stop polling
stop()
```

For multi-outcome polling:

```typescript theme={null}
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

```typescript theme={null}
provider.clearCache()  // clears trade cache for all markets
```

### MarketInfo

```typescript theme={null}
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).

```typescript theme={null}
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.

***

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

```typescript theme={null}
import { ShortFormProvider } from 'polynode-charts'

const sf = new ShortFormProvider()
```

### One-Shot Discovery

```typescript theme={null}
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.

```typescript theme={null}
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     |

### ShortFormMarket

```typescript theme={null}
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

```typescript theme={null}
interface RotationEvent {
  interval: ShortFormInterval
  market: ShortFormMarket
  windowStart: number      // unix seconds
  windowEnd: number        // unix seconds
  timeRemaining: number    // seconds until window closes
}
```

### Options

```typescript theme={null}
const sf = new ShortFormProvider({
  apiBaseUrl: 'https://api.polynode.dev',  // default
  rotationBuffer: 3,  // seconds after window end before re-discovering (default: 3)
})
```
