rn-tradingview
v2.1.0
Published
Production-grade multi-exchange candlestick chart for React Native. Supports Binance, OKX, and Bybit. GPU-accelerated (Skia), Reanimated v3 gestures, technical indicators (MACD, RSI, Bollinger Bands), drawing tools, live WebSocket candles, order book dept
Maintainers
Keywords
Readme
rn-tradingview
Production-grade multi-exchange trading chart for React Native.
rn-tradingview is a free, open-source React Native trading chart engine that connects to Binance, OKX, Bybit, or any custom exchange out of the box. GPU-accelerated Skia rendering, native Reanimated v3 gestures, real-time WebSocket candles + order book, full-featured technical indicators, drawing tools, and depth charts — all in a single library.
Built for crypto trading apps, DeFi dashboards, portfolio trackers, and any React Native app that needs a professional financial chart.
Why rn-tradingview?
| | rn-tradingview | WebView-based libs | |---|---|---| | Rendering | GPU (Skia canvas) | Web / WebView | | Performance | 60 FPS on 10 000+ candles | Laggy on large datasets | | Gestures | Native Reanimated v3 | JS-bridge events | | Exchanges | Binance + OKX + Bybit + Custom | Manual wiring | | Offline | Yes (bring your own data) | Needs web bundle | | TypeScript | Full coverage | Partial |
Features
- Multi-exchange, zero config — plug in
exchange="binance","okx", or"bybit"and get live candles + order book automatically - Custom exchange adapters — wire any REST + WebSocket feed in ~20 lines with
createExchangeAdapter - GPU-accelerated rendering — all pixels drawn in a Skia
<Canvas>, never on the JS thread - Reanimated v3 gestures — inertial pan, pinch-zoom around focal point, long-press crosshair that snaps to nearest candle
- Technical indicators
- Main / overlay:
MA,EMA,BOLL(Bollinger Bands),SAR(Parabolic SAR),AVL(volume MA),SUPER(Supertrend) - Sub-pane:
MACD,RSI,KDJ,OBV,WR(Williams %R),StochRSI
- Main / overlay:
- Drawing tools — Trend line, Ray, Horizontal line, Fibonacci retracement, Channel, Measure; sidebar modeled after Binance's drawing toolbar
- Depth / order book chart — cumulative bid & ask visualization with live WebSocket updates, switchable between exchanges
- Infinite scroll history — scroll left to auto-paginate older candles
- Fullscreen & orientation — portrait ↔ landscape with optional
react-native-orientation-locker - Bring-your-own data — use any REST API or WebSocket feed with
CandlestickChart - Full TypeScript — every prop, candle shape, indicator config, and theme token is typed
Installation
npm install rn-tradingview
# or
yarn add rn-tradingviewPeer dependencies
npm install \
@shopify/react-native-skia \
react-native-gesture-handler \
react-native-reanimated \
react-native-safe-area-context \
react-native-svgcd ios && pod installAdd the Reanimated Babel plugin:
// babel.config.js
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: ['react-native-reanimated/plugin'],
};Quick Start
TradingChart — live chart, one line per exchange
TradingChart manages WebSocket subscriptions, candle state, ticker, order book, and drawing persistence internally.
Binance
import { TradingChart } from 'rn-tradingview';
<TradingChart exchange="binance" pair="BTCUSDT" interval="1m" height={500} />OKX
import { TradingChart } from 'rn-tradingview';
<TradingChart exchange="okx" pair="BTC-USDT" interval="1m" height={500} />Bybit
import { TradingChart } from 'rn-tradingview';
<TradingChart exchange="bybit" pair="BTCUSDT" interval="1m" height={500} />Full example:
import React from 'react';
import { SafeAreaView } from 'react-native';
import { TradingChart } from 'rn-tradingview';
export default function App() {
return (
<SafeAreaView style={{ flex: 1, backgroundColor: '#0B0F14' }}>
<TradingChart
exchange="binance" // 'binance' | 'okx' | 'bybit'
pair="BTCUSDT"
interval="1m"
height={500}
themeMode="dark"
/>
</SafeAreaView>
);
}CandlestickChart — bring your own data
Use this when you already have candle data from your own API or WebSocket.
import React from 'react';
import { SafeAreaView } from 'react-native';
import { CandlestickChart } from 'rn-tradingview';
import type { Candle } from 'rn-tradingview';
const candles: Candle[] = [
{ t: 1700000000000, o: 36000, h: 36500, l: 35800, c: 36200, v: 120.5 },
{ t: 1700003600000, o: 36200, h: 37000, l: 36100, c: 36800, v: 98.3 },
// oldest → newest
];
export default function App() {
return (
<SafeAreaView style={{ flex: 1, backgroundColor: '#0B0F14' }}>
<CandlestickChart
candles={candles}
symbol="BTCUSDT"
interval="1h"
height={450}
themeMode="dark"
onTimeframeChange={(tf) => console.log('new timeframe:', tf)}
/>
</SafeAreaView>
);
}Exchange Adapters
rn-tradingview ships purpose-built adapters for Binance, OKX, and Bybit. Each adapter exposes fetchCandles (REST) and subscribeCandles / subscribeTicker (WebSocket) with a normalized Candle shape.
Binance adapter
import { binanceAdapter } from 'rn-tradingview';
// REST — fetch historical candles
const candles = await binanceAdapter.fetchCandles('BTCUSDT', '1h', 500);
// WebSocket — live candle stream
const unsub = binanceAdapter.subscribeCandles('BTCUSDT', '1m', (candle) => {
console.log('Binance candle:', candle);
});
// Live ticker (price updates)
const unsubTicker = binanceAdapter.subscribeTicker('BTCUSDT', (ticker) => {
console.log('Binance price:', ticker.price);
});
// Cleanup
unsub();
unsubTicker();Binance WebSocket:
wss://stream.binance.com:9443/ws/<symbol>@kline_<interval>Binance REST:https://api.binance.com/api/v3/klinesSymbol format:BTCUSDT(no hyphen, uppercase)
OKX adapter
import { okxAdapter } from 'rn-tradingview';
// REST — fetch historical candles
const candles = await okxAdapter.fetchCandles('BTC-USDT', '1H', 300);
// WebSocket — live candle stream
const unsub = okxAdapter.subscribeCandles('BTC-USDT', '1m', (candle) => {
console.log('OKX candle:', candle);
});
// Live ticker (price updates)
const unsubTicker = okxAdapter.subscribeTicker('BTC-USDT', (ticker) => {
console.log('OKX price:', ticker.price, '24h vol:', ticker.volume24h);
});
// Cleanup
unsub();
unsubTicker();OKX WebSocket:
wss://wspri.okx.com:8443/ws/v5/ipublic(channels:candle{tf},tickers) OKX REST:https://www.okx.com/api/v5/market/candlesSymbol format:BTC-USDT(hyphen-separated, uppercase)
Bybit adapter
import { bybitAdapter } from 'rn-tradingview';
// REST — fetch historical candles
const candles = await bybitAdapter.fetchCandles('BTCUSDT', '1h', 200);
// WebSocket — live candle stream
const unsub = bybitAdapter.subscribeCandles('BTCUSDT', '1m', (candle) => {
console.log('Bybit candle:', candle);
});
// Live ticker (price updates)
const unsubTicker = bybitAdapter.subscribeTicker('BTCUSDT', (ticker) => {
console.log('Bybit price:', ticker.price);
});
// Cleanup
unsub();
unsubTicker();Bybit WebSocket:
wss://stream.bybit.com/v5/public/spot(topics:kline.<interval>.<symbol>,tickers.<symbol>) Bybit REST:https://api.bybit.com/v5/market/klineSymbol format:BTCUSDT(no hyphen, uppercase)
Custom exchange adapter
Wire any exchange — or your own proprietary data feed — with createExchangeAdapter:
import { createExchangeAdapter, CandlestickChart, mergeLiveCandle } from 'rn-tradingview';
import type { Candle } from 'rn-tradingview';
const myAdapter = createExchangeAdapter({
name: 'MyExchange',
// REST: fetch historical OHLCV
async fetchCandles(symbol, interval, limit = 200, endTime) {
const res = await fetch(
`https://api.myexchange.com/candles?symbol=${symbol}&tf=${interval}&limit=${limit}`
);
const rows = await res.json();
return rows.map((r: any): Candle => ({
t: r.timestamp,
o: r.open,
h: r.high,
l: r.low,
c: r.close,
v: r.volume,
}));
},
// WebSocket: live candle stream
subscribeCandles(symbol, interval, onUpdate) {
const ws = new WebSocket('wss://ws.myexchange.com/stream');
ws.onopen = () =>
ws.send(JSON.stringify({ type: 'subscribe', channel: `candle:${symbol}:${interval}` }));
ws.onmessage = (e) => {
const d = JSON.parse(e.data);
onUpdate({ t: d.t, o: d.o, h: d.h, l: d.l, c: d.c, v: d.v });
};
return () => ws.close();
},
normalizeSymbol: (s) => s.toUpperCase(),
normalizeInterval: (i) => i,
});
// Use with CandlestickChart:
export default function MyChart() {
const [candles, setCandles] = React.useState<Candle[]>([]);
React.useEffect(() => {
myAdapter.fetchCandles('BTCUSDT', '1m').then(setCandles);
const unsub = myAdapter.subscribeCandles('BTCUSDT', '1m', (c) => {
setCandles((prev) => mergeLiveCandle(prev, c));
});
return unsub;
}, []);
return <CandlestickChart candles={candles} symbol="BTCUSDT" interval="1m" height={450} />;
}Normalized Candle Format
All exchange adapters produce the same Candle shape:
type Candle = {
t: number; // Unix timestamp in milliseconds
o: number; // Open
h: number; // High
l: number; // Low
c: number; // Close
v: number; // Volume (base asset)
};All candle arrays are oldest → newest (ascending t).
Depth / Order Book Chart
Single exchange:
import { DepthChart } from 'rn-tradingview';
<DepthChart
exchange="binance" // 'binance' | 'okx' | 'bybit'
symbol="BTCUSDT"
height={300}
/>Multi-exchange with built-in toggle (Binance / OKX / Bybit):
import { ExchangeDepthChart } from 'rn-tradingview';
<ExchangeDepthChart
defaultExchange="binance"
symbol="BTCUSDT"
symbolByExchange={{ okx: 'BTC-USDT', bybit: 'BTCUSDT', binance: 'BTCUSDT' }}
height={300}
/>ExchangeDepthChart renders a Binance / OKX / Bybit toggle bar above the chart and switches the live WebSocket automatically.
OKX — useOkxCandles hook with infinite scroll
import React, { useEffect } from 'react';
import { SafeAreaView, ActivityIndicator } from 'react-native';
import { CandlestickChart, useOkxCandles } from 'rn-tradingview';
export default function OkxScreen() {
const { candles, loading, loadingMore, fetchInitialCandles, fetchMoreCandles } =
useOkxCandles({ instId: 'BTC-USDT', bar: '1m' });
useEffect(() => { void fetchInitialCandles(); }, []);
if (loading) return <ActivityIndicator />;
return (
<SafeAreaView style={{ flex: 1, backgroundColor: '#0B0F14' }}>
<CandlestickChart
candles={candles}
symbol="BTC-USDT"
interval="1m"
height={450}
onLoadMore={(oldestTimestamp) => void fetchMoreCandles(oldestTimestamp)}
loadingMore={loadingMore}
/>
</SafeAreaView>
);
}Exchange Support
| Feature | Binance | OKX | Bybit | Custom |
|---------|:-------:|:---:|:-----:|:------:|
| REST candles | ✅ | ✅ | ✅ | ✅ |
| Live candle WebSocket | ✅ | ✅ | ✅ | ✅ |
| Live ticker WebSocket | ✅ | ✅ | ✅ | optional |
| Order book WebSocket | ✅ | ✅ | ✅ | — |
| useOkxCandles hook | — | ✅ | — | — |
| Infinite scroll history | ✅ | ✅ | ✅ | — |
| Exchange adapter | binanceAdapter | okxAdapter | bybitAdapter | createExchangeAdapter |
| Symbol format | BTCUSDT | BTC-USDT | BTCUSDT | yours |
API Reference
<TradingChart>
All-in-one component: manages WebSocket connections, candle buffer, ticker, order book, drawing persistence.
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| exchange | 'binance' \| 'okx' \| 'bybit' | 'binance' | Exchange to connect to |
| pair | string | required | Trading pair, e.g. "BTCUSDT" / "BTC-USDT" |
| interval | string | '1m' | Timeframe: "1m", "5m", "15m", "1h", "4h", "1d" |
| height | number | 400 | Chart height in px |
| themeMode | 'dark' \| 'light' | 'dark' | Color theme |
<CandlestickChart>
Stateless chart — you own the candle data.
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| candles | Candle[] | required | OHLCV array, oldest → newest |
| symbol | string | — | Label shown in header |
| interval | string | — | Active timeframe label |
| height | number | 400 | Chart height in px |
| width | number | full | Chart width in px |
| themeMode | 'dark' \| 'light' | 'dark' | Color theme |
| onTimeframeChange | (tf: string) => void | — | Called when user picks a timeframe |
| onLoadMore | (oldestTs: number) => void | — | Called when user scrolls past oldest candle |
| loadingMore | boolean | — | Shows pagination spinner |
| indicatorTrigger | number | — | Increment to open indicator sheet |
| contentInset | { top?, bottom?, left?, right? } | — | Safe-area padding override |
<DepthChart>
Single-exchange live order book.
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| exchange | 'binance' \| 'okx' \| 'bybit' | 'binance' | Exchange |
| symbol | string | required | Trading pair |
| height | number | — | Chart height |
| maxLevelsPerSide | number | 100 | Max bid/ask levels |
| throttleMs | number | — | WebSocket update throttle |
<ExchangeDepthChart>
Depth chart with a built-in Binance / OKX / Bybit toggle.
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| defaultExchange | 'binance' \| 'okx' \| 'bybit' | 'binance' | Initial exchange |
| symbol | string | — | Fallback symbol for all exchanges |
| symbolByExchange | { binance?, okx?, bybit? } | — | Per-exchange symbol overrides |
| height | number | — | Chart height |
Exchange adapter interface
interface ExchangeAdapter {
readonly name: string;
fetchCandles(symbol: string, interval: string, limit?: number, endTime?: number): Promise<Candle[]>;
subscribeCandles(symbol: string, interval: string, onUpdate: CandleCallback): Unsubscribe;
subscribeTicker?(symbol: string, onUpdate: TickerCallback): Unsubscribe;
normalizeSymbol(symbol: string): string;
normalizeInterval(interval: string): string;
}createExchangeAdapter
import { createExchangeAdapter } from 'rn-tradingview';
const adapter = createExchangeAdapter({
name: 'MyExchange',
fetchCandles: async (symbol, interval, limit, endTime) => { /* ... */ return candles; },
subscribeCandles: (symbol, interval, onUpdate) => { /* ... */ return () => ws.close(); },
});useOkxCandles hook
const {
candles, // Candle[]
loading, // initial fetch in progress
loadingMore, // pagination in progress
error, // Error | null
hasMore, // more history available
fetchInitialCandles, // () => Promise<void>
fetchMoreCandles, // (oldestTs?: number) => Promise<void>
applyLiveCandle, // (candle: Candle) => void
reset, // () => void
} = useOkxCandles({
instId: 'BTC-USDT', // OKX instrument ID
bar: '1m', // timeframe
initialLimit: 300, // candles to fetch on first load (max 300)
pageLimit: 100, // candles per history page
});Data utilities
import {
fetchKlines, // fetch REST candles (OKX-backed)
subscribeKlines, // subscribe to live candle WebSocket (OKX)
fetchDepth, // fetch order book snapshot (Binance)
subscribeDepth, // subscribe to live depth stream (Binance)
mergeLiveCandle, // merge a forming candle into a candle array
} from 'rn-tradingview';
// Fetch 300 candles
const candles = await fetchKlines('BTC-USDT', '1h', 300);
// Subscribe to live candles
const ws = subscribeKlines('BTC-USDT', '1m', (candle) => {
// merge candle into your state
});
ws.close(); // cleanupIndicator engine (advanced)
import { computeChartIndicators } from 'rn-tradingview';
const result = computeChartIndicators(candles, {
ma: [{ period: 7 }, { period: 25 }, { period: 99 }],
ema: [{ period: 12 }, { period: 26 }],
boll: { period: 20, multiplier: 2 },
rsi: { period: 14 },
macd: { fast: 12, slow: 26, signal: 9 },
kdj: { period: 9 },
obv: true,
});Theming
import { TradingChart, CandlestickChart } from 'rn-tradingview';
// Dark theme (default — matches Binance Mobile)
<TradingChart exchange="binance" pair="BTCUSDT" themeMode="dark" ... />
// Light theme
<CandlestickChart candles={candles} themeMode="light" ... />Import raw tokens if you need to match colors in your own UI:
import { DarkTheme, LightTheme, Themes } from 'rn-tradingview';React Native Compatibility
| rn-tradingview | React Native | React | |----------------|-------------|-------| | 2.x | 0.72 – 0.85 | 18–19 | | 1.x | 0.72 – 0.75 | 18 |
License
MIT © Salil Samdarshy & Shubham Narula
