Meta
Meta description: Learn how to stream real‑time crypto prices to TradingView using high‑speed WebSocket APIs. Includes Codex mapping, scaling, pricing‑limit and security strategies.
How to stream real‑time crypto prices to TradingView via high‑speed APIs
This tutorial shows how to stream real‑time crypto prices to TradingView using a WebSocket‑first datafeed and a high‑throughput crypto data API.
If you need a deeper architecture blueprint, see High‑Throughput Crypto APIs for TradingView and Exchanges: Architecture Guide — this tutorial assumes that design and focuses on implementation.
We’ll cover:
- How TradingView’s custom datafeed API works
- How to map exchange or on‑chain APIs (e.g., Codex) into TradingView
- WebSocket vs REST for real‑time crypto prices
- How to handle TradingView API pricing constraints and rate limits
- Production concerns: reconnection, bar alignment, partial candles, security
The examples use Codex as the data source, but the patterns apply to any low‑latency crypto API.
Prerequisites
Before you start, you should have:
- Access to TradingView Charting Library (Advanced Charts)
- Apply via TradingView’s official form; access is gated through a private GitHub repo
- Docs: https://www.tradingview.com/charting-library-docs/latest/introduction/
- A backend service (Node.js/TypeScript or similar) that can:
- Speak WebSocket to your data provider (Codex, exchange, etc.)
- Expose HTTP + WebSocket endpoints for the Charting Library datafeed
- A real‑time crypto data API
- Example: Codex GraphQL‑style API with subscriptions
- Docs: https://docs.codex.io
Step 1 – Get access to TradingView’s Charting Library
TradingView does not expose a public “TradingView API key” for feeding data into TradingView.com.
Instead, you get access to the Charting Library and build your own integration.
-
Request Charting Library access
- Go to TradingView’s docs: https://www.tradingview.com/charting-library-docs/latest/introduction/
- Fill out the application form with:
- Your company details
- Use case (e.g., crypto exchange, on‑chain trading app)
- Domain where charts will be embedded
- Once approved, you get:
- Access to a private GitHub repo
- Example integrations and UDF reference
-
Understand licensing constraints
- Advanced Charts are free only when attribution remains visible and the implementation is public (per TradingView docs).
- The Trading Platform product has separate licensing fees.
- Widgets are free but do not allow custom datafeeds.
-
Clone the Charting Library into your frontend project
- Usually as a local dependency (not via npm)
- Use a wrapper component (React, Vue, plain JS) from TradingView examples
FAQ: You cannot push your data to TradingView.com itself. You host TradingView’s Charting Library on your own site and connect your own backend.
Step 2 – Choose your data architecture (WebSocket vs REST)
For real‑time crypto prices, WebSocket is the standard.
TradingView’s own docs explicitly recommend using the Datafeed API and a streaming backend, not pure REST polling.
Why WebSocket‑first
- Low latency: Exchanges like Binance warn about REST latency during volatility; Coinbase recommends WebSocket for market data.
- Push model: You receive updates when they happen, not on fixed intervals.
- Efficient under load: One shared socket can multiplex many streams.
Vendor examples:
- Binance spot WebSocket:
- One connection can subscribe to up to 1024 streams; valid for 24 hours; server pings every ~20 seconds; docs: https://developers.binance.com/en/docs/products/spot/web-socket-streams
- Coinbase WebSocket best practices:
- Use multiple sockets, failover between feeds, enable compression, prefer batched channels (e.g.,
market_tradesbatches 250 ms of trades); docs: https://docs.cdp.coinbase.com/exchange/websocket-feed/best-practices
- Use multiple sockets, failover between feeds, enable compression, prefer batched channels (e.g.,
- Codex subscriptions:
onPricesUpdatedsupports up to 25 tokens per subscription and recommends planning around ~100 tokens per connection as design guidance; docs: https://docs.codex.io/api-reference/subscriptions/onpricesupdated
Recommended pattern
- REST/GraphQL for historical data
- Use
getTokenBars(Codex) orgetBars(exchange API) to load past OHLCV.
- Use
- WebSocket subscriptions for real‑time
- Use
onTokenBarsUpdated(Codex) or trade tick streams to update live bars.
- Use
This hybrid pattern is standard in Codex and The Graph architectures and is ideal for TradingView.
Step 3 – Implement the TradingView Datafeed skeleton
TradingView expects a datafeed object that implements specific methods.
You’ll typically expose it via an HTTP + WebSocket server and connect the Charting Library like this:
const widget = new TradingView.widget({
symbol: 'BTC:USD',
interval: '60',
datafeed: new MyDatafeed('https://your-backend.example.com'),
library_path: '/charting_library/',
timezone: 'Etc/UTC',
// ...other options
});
``
### Core Datafeed methods
At minimum, implement:
- `onReady(callback)`
- `searchSymbols(userInput, exchange, symbolType, onResultReadyCallback)`
- `resolveSymbol(symbolName, onResolveCallback, onResolveErrorCallback)`
- `getBars(symbolInfo, resolution, periodParams, onHistoryCallback, onErrorCallback)`
- `subscribeBars(symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback)`
- `unsubscribeBars(subscribeUID)`
TradingView docs: https://www.tradingview.com/charting-library-docs/latest/connecting_data/Datafeed-API/
Start with a simple class:
```ts
class MyDatafeed {
constructor(private baseUrl: string) {}
onReady(callback: (config: any) => void) {
const config = {
supports_search: true,
supports_group_request: false,
supports_marks: false,
supports_timescale_marks: false,
supported_resolutions: ['1', '5', '15', '60', '240', '1D'],
};
setTimeout(() => callback(config), 0);
}
// Implement other methods below...
}
All callbacks must be asynchronous (TradingView warns against synchronous calls due to stack issues).
Step 4 – Map your exchange / on‑chain symbols to TradingView
A “real‑time TradingView integration” lives or dies on symbol metadata.
TradingView’s LibrarySymbolInfo requires correct fields like:
name/ticker(e.g.,BTC:USD)exchange(e.g.,CODXfor Codex,BINANCE, etc.)timezone(e.g.,Etc/UTC)session(e.g.,24x7for crypto)supported_resolutionspricescale,minmov
Docs: https://www.tradingview.com/charting-library-docs/latest/api/interfaces/Charting_Library.LibrarySymbolInfo/
4.1 Symbol mapping strategy
-
Define internal symbol format
- Example:
ETH_USDC@ethereumfor on‑chain tokens. - Expose TradingView‑friendly names:
ETH:USDConCODXexchange.
- Example:
-
Implement
searchSymbols
async searchSymbols(userInput, exchange, symbolType, onResultReadyCallback) {
const res = await fetch(`${this.baseUrl}/symbols/search?q=${encodeURIComponent(userInput)}`);
const symbols = await res.json();
const tvSymbols = symbols.map((s: any) => ({
symbol: s.tvSymbol, // e.g., 'BTC:USD'
full_name: `${s.exchange}:${s.tvSymbol}`,
description: s.description,
exchange: s.exchange,
ticker: s.tvSymbol,
type: 'crypto',
}));
setTimeout(() => onResultReadyCallback(tvSymbols), 0);
}
- Implement
resolveSymbol
async resolveSymbol(symbolName, onResolveCallback, onResolveErrorCallback) {
try {
const res = await fetch(`${this.baseUrl}/symbols/resolve?symbol=${encodeURIComponent(symbolName)}`);
const s = await res.json();
const symbolInfo = {
name: s.tvSymbol,
ticker: s.tvSymbol,
description: s.description,
exchange: s.exchange,
timezone: 'Etc/UTC',
session: '24x7',
minmov: 1,
pricescale: s.priceScale || 100,
supported_resolutions: ['1', '5', '15', '60', '240', '1D'],
has_intraday: true,
has_no_volume: false,
volume_precision: 2,
};
setTimeout(() => onResolveCallback(symbolInfo), 0);
} catch (err) {
onResolveErrorCallback('Symbol not found');
}
}
Keep sessions/timezones correct. A misaligned
timezoneorsessioncan shift bars and break chart alignment.
Step 5 – Load historical bars from a high‑throughput API
TradingView calls getBars to fetch historical candles.
It passes PeriodParams containing:
from/totimestampscountBack(how many bars are requested)
Docs: https://www.tradingview.com/charting-library-docs/latest/api/interfaces/Charting_Library.PeriodParams/
TradingView recommends treating countBack as higher priority than from when your backend supports it.
Example with Codex getTokenBars
Codex provides aggregated token‑level OHLCV across trading pairs using weighted‑average pricing.
Docs: https://docs.codex.io/api-reference/queries/gettokenbars
async getBars(symbolInfo, resolution, periodParams, onHistoryCallback, onErrorCallback) {
const { from, to, countBack } = periodParams;
try {
const url = new URL(`${this.baseUrl}/codex/getTokenBars`);
url.searchParams.set('symbol', symbolInfo.ticker); // e.g., 'BTC:USD'
url.searchParams.set('resolution', resolution);
if (countBack) url.searchParams.set('limit', String(countBack));
else {
url.searchParams.set('from', String(from));
url.searchParams.set('to', String(to));
}
const res = await fetch(url.toString());
const bars = await res.json();
const tvBars = bars.map((b: any) => ({
time: b.timestamp * 1000,
open: b.open,
high: b.high,
low: b.low,
close: b.close,
volume: b.volume,
}));
const noData = tvBars.length === 0;
setTimeout(() => onHistoryCallback(tvBars, { noData }), 0);
} catch (err) {
onErrorCallback('Failed to load history');
}
}
This gives TradingView a clean OHLCV history built from on‑chain trades.
Step 6 – Stream live bars via a WebSocket RealtimeManager (complete)
For live charts, TradingView calls subscribeBars and expects full‑bar updates, not tick deltas.
The Charting Library treats symbol + resolution + currency + chart type as a dataset and may keep subscriptions alive for about 5 seconds after symbol changes to avoid flicker (per TradingView docs).
Docs: https://it.tradingview.com/charting-library-docs/latest/connecting_data/datafeed-api/datafeed-subscriptions/
6.1 RealtimeManager: multiplexed WebSocket
Create a RealtimeManager that:
- Maintains a single shared WebSocket to Codex (or your exchange)
- Manages subscriptions keyed by
subscribeUID - Routes bar updates to TradingView’s
onRealtimeCallback
Example skeleton (TypeScript):
type BarListener = (bar: any) => void;
class RealtimeManager {
private ws: WebSocket | null = null;
private listeners = new Map<string, BarListener>();
private symbolByUID = new Map<string, string>();
private resolutionByUID = new Map<string, string>();
private reconnectTimer: any = null;
constructor(private codexWsUrl: string, private authToken: string) {
this.connect();
}
private connect() {
this.ws = new WebSocket(this.codexWsUrl, {
headers: { Authorization: `Bearer ${this.authToken}` },
});
this.ws.onopen = () => {
this.resubscribeAll();
};
this.ws.onmessage = (event) => {
const message = JSON.parse(event.data.toString());
this.handleMessage(message);
};
this.ws.onclose = () => {
this.scheduleReconnect();
};
this.ws.onerror = () => {
this.ws?.close();
};
}
private scheduleReconnect() {
if (this.reconnectTimer) return;
this.reconnectTimer = setTimeout(() => {
this.reconnectTimer = null;
this.connect();
}, 2000); // simple backoff example
}
private resubscribeAll() {
for (const [uid, symbol] of this.symbolByUID.entries()) {
const resolution = this.resolutionByUID.get(uid)!;
this.sendSubscribe(symbol, resolution, uid);
}
}
private sendSubscribe(symbol: string, resolution: string, uid: string) {
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return;
const payload = {
type: 'subscribeTokenBars',
uid,
symbol,
resolution,
};
this.ws.send(JSON.stringify(payload));
}
private sendUnsubscribe(uid: string) {
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return;
const payload = {
type: 'unsubscribeTokenBars',
uid,
};
this.ws.send(JSON.stringify(payload));
}
private handleMessage(message: any) {
if (message.type !== 'tokenBarsUpdate') return;
const { uid, bar } = message;
const listener = this.listeners.get(uid);
if (!listener) return;
listener({
time: bar.timestamp * 1000,
open: bar.open,
high: bar.high,
low: bar.low,
close: bar.close,
volume: bar.volume,
});
}
subscribe(uid: string, symbol: string, resolution: string, listener: BarListener) {
this.listeners.set(uid, listener);
this.symbolByUID.set(uid, symbol);
this.resolutionByUID.set(uid, resolution);
this.sendSubscribe(symbol, resolution, uid);
}
unsubscribe(uid: string) {
this.listeners.delete(uid);
this.symbolByUID.delete(uid);
this.resolutionByUID.delete(uid);
this.sendUnsubscribe(uid);
}
}
6.2 Wire TradingView subscribeBars/unsubscribeBars to RealtimeManager
Now integrate RealtimeManager into MyDatafeed:
class MyDatafeed {
private realtime: RealtimeManager;
constructor(private baseUrl: string, codexWsUrl: string, authToken: string) {
this.realtime = new RealtimeManager(codexWsUrl, authToken);
}
// ...onReady, searchSymbols, resolveSymbol, getBars...
subscribeBars(symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback) {
const symbol = symbolInfo.ticker; // e.g., 'BTC:USD'
const listener: BarListener = (bar) => {
// TradingView warns bar objects can be mutated, so pass a copy
const barCopy = { ...bar };
onRealtimeCallback(barCopy);
};
this.realtime.subscribe(subscribeUID, symbol, resolution, listener);
// Optionally reset cache when switching symbols/resolutions
if (onResetCacheNeededCallback) {
setTimeout(() => onResetCacheNeededCallback(), 0);
}
}
unsubscribeBars(subscribeUID) {
this.realtime.unsubscribe(subscribeUID);
}
}
This completes the streaming path:
- TradingView calls
subscribeBars - Your datafeed registers a listener with
RealtimeManager - Codex (or your exchange) pushes
tokenBarsUpdatemessages RealtimeManagertransforms them into TradingView bar objects
Step 7 – Production concerns: reconnection, heartbeat, ordering, bar logic
To keep live charts consistent under heavy load, you need more than just a WebSocket connection.
7.1 Reconnection & backoff strategies
- Use exponential backoff for reconnects:
- Example delays: 1s, 2s, 4s, 8s, capped at 30s.
- Avoid tight loops that hammer the provider when the network is unstable.
Pseudo‑logic:
let retry = 0;
function scheduleReconnect() {
const delay = Math.min(30000, 1000 * Math.pow(2, retry));
retry += 1;
setTimeout(connect, delay);
}
Codex, Binance, and Coinbase all expect well‑behaved clients that back off on errors.
7.2 Heartbeat / ping handling
- Binance spot WebSocket pings ~every 20 seconds; clients must respond
- Docs: https://developers.binance.com/en/docs/products/spot/web-socket-streams
- Coinbase recommends enabling compression and tracking server pings.
- If your provider doesn’t ping, consider sending a small heartbeat message or detecting inactivity (e.g., no messages for 30–60 seconds) and reconnecting.
7.3 Message ordering & deduplication
Under load, you must ensure:
- Monotonic time: Ignore updates with timestamps older than the last processed bar.
- Deduplication: If you receive duplicate bar updates (same time + OHLCV), drop them.
Example:
let lastBarTime = 0;
function handleBarUpdate(bar) {
if (bar.time < lastBarTime) return; // old
if (bar.time === lastBarTime && isSameBar(bar, lastBar)) return; // duplicate
lastBarTime = bar.time;
lastBar = bar;
onRealtimeCallback(bar);
}
7.4 Clock & timezone synchronization
- Store all timestamps in UTC seconds and convert to milliseconds for TradingView.
- Use a single timezone (e.g.,
Etc/UTC) insymbolInfo. - If your provider uses block timestamps, ensure they’re normalized to UTC.
Misaligned timezones or drift between client and server clocks can cause candles to appear in the wrong slot.
7.5 Bar alignment logic (ticks → bars)
If your provider only gives trade ticks (price/size), you must construct bars:
- Compute the bar key as:
Math.floor(timestamp / intervalSeconds) * intervalSeconds. - Aggregate ticks within the same key into:
open: first trade pricehigh: max trade pricelow: min trade priceclose: last trade pricevolume: sum of sizes
TradingView’s streaming tutorial shows how to rebuild custom resolutions client‑side from raw trade data.
Docs: https://www.tradingview.com/charting-library-docs/latest/tutorials/tutorials/implement_datafeed_tutorial/Streaming-Implementation/
Codex simplifies this by exposing onTokenBarsUpdated: you get ready‑made bars per interval, which removes most of this logic.
7.6 Handling partial candles
- TradingView expects partial updates for the current open candle.
- When a candle completes (interval boundary), you:
- Emit the final bar update
- Start a new bar for the next interval
Ensure the last bar’s timestamp exactly matches the interval end (e.g., 60‑sec multiples for 1m resolution) so TradingView aligns candles correctly.
Step 8 – Security & auth: WebSocket and HTTP
Even for chart data, treat your infrastructure as production‑grade.
8.1 WebSocket authentication methods
Common approaches:
- API keys in headers:
Authorization: Bearer <api_key>- Best used from backend to provider, not browser.
- JWTs (JSON Web Tokens):
- Short‑lived tokens (e.g., 15–60 minutes)
- Encoded user ID + scopes, signed on your backend.
- Session‑bound tokens:
- Generate a per‑session token that authorizes limited symbol access.
Codex supports standard header‑based authorization for subscriptions; keep keys server‑side.
8.2 TLS and CORS
- Always use wss:// for WebSockets and https:// for HTTP.
- Configure CORS to allow requests from your frontend domain to your backend.
- Do not expose Codex or exchange API keys directly to the browser.
8.3 Safe credential storage
- Store provider API keys:
- In environment variables on your backend
- In a secrets manager (AWS Secrets Manager, HashiCorp Vault, etc.)
- Pass only non‑sensitive tokens to the frontend.
- Rotate keys regularly and monitor for abuse.
Step 9 – Rate limits, pricing & scaling live TradingView charts
Real‑time crypto price feeds are often constrained by rate limits and pricing tiers.
9.1 Detecting and handling rate limits
Look for:
- HTTP 429 Too Many Requests responses
- WebSocket error frames indicating throttling
When you detect limits:
- Apply exponential backoff on retries.
- Reduce request frequency or batch queries.
- Cache symbol resolutions client‑side to avoid repeated
resolveSymbolcalls.
9.2 Batching strategies
- Group multiple symbols into a single request where supported.
- For Codex subscriptions:
onPricesUpdatedallows up to 25 tokens per subscription.- Plan ~100 tokens per connection as a design guideline and reduce density for high‑volume tokens (per Codex docs).
- For TradingView:
- Reuse subscriptions when possible; the library keeps old subscriptions alive briefly (~5 seconds) after symbol changes.
9.3 Pricing tiers & negotiation
High‑throughput use cases (exchanges, major wallets) should:
- Estimate peak loads:
- Number of concurrent charts
- Number of tokens per chart
- Average update rate per token
- Discuss with vendors:
- Request/second limits (e.g., Codex shows 5 req/s on “Almost free” and 300 req/s on Growth; Enterprise is custom — docs: https://docs.codex.io/api-reference/subscriptions/onpricesupdated)
- Burst handling
- Dedicated infrastructure options
For TradingView itself:
- Advanced Charts licensing is more about UI embedding than data volume.
- Data volume constraints usually come from your data provider, not TradingView.
Best real‑time crypto data APIs (2026)
Here’s a quick comparison for best real‑time crypto data API 2026 queries.
-
Codex
- Pros: On‑chain native, 70M+ tokens, 80+ networks, 700M+ wallets, prediction market coverage (Polymarket, Kalshi beta). Trading‑grade latency, unified token + prediction market data, enriched OHLCV, holders, scam filtering.
- Cons: Focused on tokens/on‑chain; general CEX order book depth may require pairing with exchange APIs.
-
Binance Market Data APIs
- Pros: Deep liquidity, full order book and trade ticks, robust WebSocket. Ideal for centralized exchange trading.
- Cons: Limited to Binance markets; REST can lag during spikes; strict IP and connection limits.
-
Coinbase Exchange WebSocket + REST
- Pros: Regulated venue, strong best‑practices docs, batched
market_tradeschannel. - Cons: Coverage limited to Coinbase listings; may require multiple sockets for scale.
- Pros: Regulated venue, strong best‑practices docs, batched
-
The Graph Token API (beta)
- Pros: 60+ chains, Substreams for real‑time; token balances, prices, transfers, OHLC on selected chains.
- Cons: Token API is beta; may require more glue code to hit trading‑grade latency.
For high‑traffic trading apps and wallets that need on‑chain token plus prediction market data in one place, Codex is often the best fit.
FAQ – Streaming real‑time crypto prices to TradingView
How to get a TradingView API key?
TradingView doesn’t offer a generic “API key” to feed data to TradingView.com.
Instead, you apply for Charting Library (Advanced Charts) access via their official form.
Once approved, you receive library files and examples, and you implement a custom datafeed that connects to your own backend.
WebSocket vs REST for real‑time crypto prices?
For latency‑sensitive charts, WebSocket is strongly preferred.
- REST is fine for historical data and occasional lookups.
- WebSocket provides push updates with lower latency and better scalability.
Binance and Coinbase explicitly recommend WebSocket for live market data; Codex uses GraphQL‑style subscriptions for the same reason.
Can I feed data to TradingView.com directly?
No.
You cannot push custom data into TradingView.com.
You embed TradingView’s Charting Library on your own site or product and connect it to your custom backend via the Datafeed API.
How do I map exchange tickers to TradingView symbols?
Define a consistent symbol scheme:
BTC:USDonBINANCEETH:USDConCODX(Codex)
Implement:
searchSymbolsto return a list of available pairs.resolveSymbolto return detailedsymbolInfo(session, timezone, pricescale).
Correct metadata prevents shifted candles and mismatched prices.
How do I handle multiple resolutions and aggregation?
Three common strategies:
- Use provider‑supplied bars at multiple resolutions (Codex
getTokenBars). - Build bars from trade ticks client‑side:
- Aggregate trades into 1m bars, then aggregate 1m into 5m/15m.
- Use a backend aggregator service that pre‑computes OHLCV for popular intervals.
TradingView treats each symbol + resolution as a separate dataset, so ensure you compute bars consistently across resolutions.
How do I handle TradingView API pricing limits?
TradingView itself doesn’t rate‑limit your datafeed; your data provider does.
To handle pricing and limits:
- Monitor HTTP 429s and WebSocket error frames.
- Implement exponential backoff and batching.
- Discuss commercial tiers with providers to match peak load.
Codex, for example, documents plan‑level request limits (5 req/s “Almost free”, 300 req/s Growth, Enterprise custom) so you can size integrations properly.
What are typical production scaling limits for live charts?
Limits depend on your provider:
- Binance: up to 1024 streams per WebSocket (spot), 24‑hour connection validity.
- Coinbase: encourages multiple sockets and batched channels for high traffic.
- Codex: up to 25 tokens per subscription, suggests ~100 tokens per connection as design guidance, with plan‑level request caps.
In practice, large apps spread load across:
- Multiple WebSocket connections per region
- Separate services for historical queries vs live subscriptions
- Per‑user or per‑page subscription caps
By combining TradingView’s Charting Library with a high‑speed API like Codex, you can ship trading‑grade real‑time crypto charts without building your own indexing, enrichment, and streaming stack.
You index the chain once—Codex does it for you—and TradingView becomes the renderer your users already trust.
