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.
Live Streaming
This guide covers building a real-time crypto price chart with WebSocket streaming, live mode, and short-form market overlays.
Basic Live Chart
Connect a WebSocket feed to a line series with live mode enabled:
import { createChart } from 'polynode-charts'
const chart = createChart('#chart', {
layout: { background: '#0c1220', textColor: '#556' },
grid: {
horzLines: { color: 'rgba(100, 120, 150, 0.06)' },
vertLines: { visible: false },
},
})
const series = chart.addLineSeries({
color: '#f7931a',
lineWidth: 2,
smooth: true,
showDot: true,
dotColor: '#f7931a',
})
// Live mode: smooth phantom point + auto-scroll
series.setLive(true)
series.setMaxLength(600) // ~10 min at 1/sec
chart.timeScale().goLive()
// Connect to price feed
const ws = new WebSocket('wss://ws.polynode.dev/ws?key=pn_...')
ws.onopen = () => {
ws.send(JSON.stringify({ action: 'subscribe', type: 'chainlink' }))
}
ws.onmessage = (e) => {
const msg = JSON.parse(e.data)
if (msg.type === 'price_feed' && msg.feed === 'BTC/USD') {
series.update({ time: Date.now(), value: msg.data.price })
}
}
How Live Mode Works
When setLive(true) is called:
-
Phantom point — a virtual leading data point is appended at
Date.now() that smoothly lerps toward the latest real value. This creates fluid animation even if ticks arrive only once per second.
-
Pulsing dot — a glowing dot marks the current price at the phantom point, pulsing with a subtle sine-wave animation.
-
Auto-scroll —
goLive() on the time scale keeps the visible range pinned to the latest data. If the user pans away, the chart returns to live after 4 seconds of inactivity.
-
Continuous redraw — the animation frame loop redraws the data layer every frame (for lerp + pulse), but background and overlay layers only redraw when dirty.
Price-to-Beat Overlay
Overlay a horizontal dashed line showing the opening price for a short-form market window:
import { ShortFormProvider } from 'polynode-charts'
const sf = new ShortFormProvider()
const stop = sf.startRotation('btc', '15m', (event) => {
const m = event.market
// Draw dashed price line
if (m.priceToBeat !== null) {
series.setPriceLine(m.priceToBeat, {
color: '#3b82f6',
label: 'PRICE TO BEAT',
})
}
// Display odds
const upPct = (m.upOdds * 100).toFixed(0)
const downPct = (m.downOdds * 100).toFixed(0)
document.getElementById('odds').textContent =
`${upPct}% up · ${downPct}% down · ${event.timeRemaining}s`
}, { pollMs: 1000 })
The price line automatically stays visible. The Y-axis expands to include the price-to-beat value even if it’s outside the current data range.
What Happens at Window Boundaries
When a short-form window expires (e.g., the 15-minute window closes):
startRotation waits a buffer period (default 3 seconds)
- Discovers the next window’s market via the gamma proxy
- Fetches the new price-to-beat from the crypto-price endpoint
- Calls your
onRotation callback with the new market
- Resumes polling odds every
pollMs for the new window
No manual intervention needed. The rotation handles the full lifecycle.
Multiple Coins
Run independent charts for multiple coins, each with their own series and short-form rotation:
const coins = [
{ coin: 'btc', feed: 'BTC/USD', color: '#f7931a' },
{ coin: 'eth', feed: 'ETH/USD', color: '#627eea' },
{ coin: 'sol', feed: 'SOL/USD', color: '#14f195' },
]
for (const { coin, feed, color } of coins) {
const chart = createChart(`#chart-${coin}`, { /* ... */ })
const series = chart.addLineSeries({ color, smooth: true, showDot: true, dotColor: color })
series.setLive(true)
series.setMaxLength(600)
chart.timeScale().goLive()
// Price updates from WebSocket
ws.onmessage = (e) => {
const msg = JSON.parse(e.data)
if (msg.type === 'price_feed' && msg.feed === feed) {
series.update({ time: Date.now(), value: msg.data.price })
}
}
// Independent short-form rotation per coin
const sf = new ShortFormProvider()
sf.startRotation(coin, '15m', (event) => {
if (event.market.priceToBeat !== null) {
series.setPriceLine(event.market.priceToBeat, {
color: '#3b82f6',
label: 'PRICE TO BEAT',
})
}
})
}
Orderbook + Chart Side-by-Side
Combine a candle chart with a live orderbook:
import { createChart, createOrderbook, PolynodeProvider, PolynodeOBProvider } from 'polynode-charts'
const provider = new PolynodeProvider({ apiKey: 'pn_...' })
// Chart
const chart = createChart('#chart')
const series = chart.addCandleSeries()
const candles = await provider.getCandles(tokenId, '1h')
series.setData(candles)
// Orderbook
const ob = createOrderbook('#orderbook', {
colorBid: '#22c55e',
colorAsk: '#ef4444',
})
const obProvider = new PolynodeOBProvider()
obProvider.subscribe(tokenId, (book) => ob.update(book))
Reconnection
Both the WebSocket feed and the OB provider handle reconnection automatically with exponential backoff (1s up to 30s). No special handling is needed in your code.
For the ShortFormProvider, discovery retries 3 times with a 2-second delay between attempts before giving up on a window. The rotation timer then retries at the next buffer interval.