Skip to main content
The TradingView Advanced Charts library (the charting_library package, not the open-source Lightweight Charts) renders price by calling a datafeed object you implement. This guide wires Struct into that datafeed: historical bars from the candlestick API in getBars, and live bars from the trades WebSocket room fed into the realtime callback. Each Polymarket outcome is an ERC-1155 token identified by a numeric position ID. That position ID is the symbol you chart. A binary market has a Yes token and a No token, each with its own price series, so you chart one outcome at a time.

When to use this

  • A candlestick chart of a single market outcome (Yes/No price over time) inside your own app.
  • A live trading view that backfills history on mount and extends the last bar on every fill.
  • Replacing a polling chart with a pushed one, no reconnect bookkeeping.
If you are charting the crypto spot price behind Up/Down markets instead, use getAssetCandlestick, not the market candlestick endpoints below.

The candlestick endpoints

getPositionCandlestick returns OHLCV for a single outcome token; getCandlestick returns it for a market by condition ID. Both return the same bar shape.
Each bar is { o, h, l, c, v, t, tc }:
Request bounds (from / to) are in Unix seconds, but each returned bar’s t is in Unix milliseconds. TradingView’s Bar.time wants milliseconds for intraday resolutions, so t maps straight across with no conversion.

Step 1: getBars

TradingView calls getBars on first load and again as the user pans into older data. periodParams gives the window (from, to in Unix seconds), the bar count (countBack), and whether this is the first request. Map the response into the library’s Bar type and sort ascending; out-of-order bars are rejected. Page older history with the cursor, not the window. Send from / to (or just count_back) on the first request to anchor the visible range, then follow the pagination_key from each response on every subsequent call. The pagination.has_more flag — not the returned row count — tells you when the series is exhausted, so keep a small state object between calls to carry the cursor and the more-data flag.

Step 2: live bars from the trades room

subscribeBars should only register the chart’s realtime callback. Feed updates from a separate handleRealtimeTrade method driven by the polymarket_trades room, so one socket serves the chart, a trade tape, and anything else. Each trade_stream_update carries price (01), shares_amount, side, and confirmed_at (Unix seconds). Bucket each trade into its bar, opening a new bar from the previous bar’s close so the series stays continuous.
The three branches cover every case: extend the current bar, roll into a new one (open at the last close), or start cold. TradingView merges realtime bars by time, so the first trade after load lands on the same timestamp as the last historical bar and updates it in place.
By default the trades room sends confirmed on-chain fills. Pass status: "all" to also receive mempool trades, which arrive before confirmation and carry received_at (Unix milliseconds) instead of confirmed_at. Use them for a faster visual tick and reconcile against confirmed data.

Step 3: assemble the datafeed and mount

onReady advertises supported resolutions. resolveSymbol describes the instrument: prices are 01, so pricescale: 10000 gives four decimals. Then connect the socket, subscribe to the trades room, and pipe each event into handleRealtimeTrade.
For a browser chart, authenticate with a pk_jwt_ public key plus the signed-in user’s JWT, as above. The pk_jwt_ key is safe in a frontend bundle because it is useless without a valid JWT from your configured auth provider. On a server, use your sk_ secret key and drop the jwt. See JWT auth.

Common combinations

Follow-on

Last modified on June 8, 2026