Skip to main content

Coinbase and Binance: Live Crypto Data from the Coinbase API and Binance API

SciTrader has two live exchanges built in, CoinbaseExchange and BinanceExchange. Both read the exchange's public market data API, so they need no API key: historical candles back to when a market listed, and live candles, trades and tickers over WebSocket. Register one and a chart charts it by name.

import { BinanceExchange, CoinbaseExchange, defaultExchangeProvider, idbPriceStore } from "scichart-scitrader";

defaultExchangeProvider.registerExchange(CoinbaseExchange, idbPriceStore);
defaultExchangeProvider.registerExchange(BinanceExchange, idbPriceStore);

Coinbase and Binance Compared​

CoinbaseExchangeBinanceExchange
Exchange name"Coinbase""Binance"
Symbol formatBTC-USD (BASE-QUOTE)BTCUSDT (BASE and QUOTE together)
Intervals1m, 5m, 15m, 1h, 6h, 1dEvery SciTrader interval, 1s to 1M
Candles per request (candleLimit)3001,000
Live dataCandles, trades and tickersCandles, trades and tickers
Watchlist sparklinesA dedicated candle stream (getSparklineCandleStream), fixed at 5 minutesCandles and the candle stream
Order bookNone built in; see Order Book DataNone built in
Endpointsapi.exchange.coinbase.com, ws-feed.exchange.coinbase.comapi.binance.com, stream.binance.com

Intervals. A chart's interval pickers offer only the intervals the exchange serves, from getSupportedIntervals(). Coinbase has no 4h, for example.

Symbols. Each exchange uses its own symbol format. mapSymbol(symbol, from, to) converts between them, e.g. mapSymbol("BTCUSDT", "Binance", "Coinbase") is "BTC-USD"; see Changing the Symbol.

Binance is geo-blocked in some countries

api.binance.com refuses requests from the United States and some other countries, including India, so a chart on Binance shows nothing for users there. Use Coinbase, or your own data, for an audience in those countries. For that reason this page has no live Binance example; the code is the same as for Coinbase, with Binance's name and symbols.

The first chart takes a moment

The first time a chart loads a symbol and interval, the exchange finds where its history starts, the listing date, so panning back stops there. On Coinbase this takes a few requests, which delays the first draw by about a second. The answer is stored with the candles, so later loads skip it.

Charting the Coinbase API​

const financeChartPanel = await SciFinanceChartPanel.create(document.getElementById("chart"), {
exchangeName: CoinbaseExchange.name, // "Coinbase"
symbol: "BTC-USD",
interval: CandleInterval.ONE_HOUR,
period: "1W",
studies: [new OHLCStudy(), new VolumeStudy()],
});

TypeScript Example: A Live Coinbase API Chart​

BTC-USD from Coinbase, updating live. The buttons change the symbol with setSymbol and the interval with changeInterval, offering only the intervals Coinbase serves. The price on the right is the exchange client's live ticker stream.

The code for this example is found below.

import "scichart-scitrader/scitrader.css";
import {
CandleInterval,
CoinbaseExchange,
defaultExchangeProvider,
idbPriceStore,
OHLCStudy,
SciFinanceChartPanel,
VolumeStudy,
} from "scichart-scitrader";

// This example expects this HTML:
// <div style="display: flex; flex-direction: column; height: 100%">
// <div id="toolbar"></div>
// <div id="chart" style="flex: 1; min-height: 0"></div>
// </div>

// Register Coinbase once, at app startup, with a candle store: idbPriceStore keeps downloaded
// candles in IndexedDB, so a reload or a return visit draws from the cache
defaultExchangeProvider.registerExchange(CoinbaseExchange, idbPriceStore);

const SYMBOLS = ["BTC-USD", "ETH-USD", "SOL-USD"]; // Coinbase's symbol format: BASE-QUOTE

async function createChart() {
const toolbar = document.getElementById("toolbar");
Object.assign(toolbar.style, toolbarStyle);

const financeChartPanel = await SciFinanceChartPanel.create(document.getElementById("chart"), {
exchangeName: CoinbaseExchange.name, // "Coinbase": the name it was registered under
symbol: "BTC-USD",
interval: CandleInterval.ONE_HOUR,
period: "1W",
studies: [new OHLCStudy(), new VolumeStudy()],
});
const chart = financeChartPanel.financeApi;

// The intervals Coinbase serves: 1m, 5m, 15m, 1h, 6h and 1d
const intervals = CoinbaseExchange.getSupportedIntervals();

// The registered exchange's client also gives live data: here a ticker, the latest price and
// the 24-hour change, for the chart's symbol
const price = document.createElement("span");
const client = defaultExchangeProvider.getExchange(CoinbaseExchange.name);
let ticker = client.getTickerStream("BTC-USD").subscribe(showTicker);
function showTicker(t: { symbol: string; curDayClose: number; priceChangePercent: number }) {
price.textContent = `${t.symbol} ${t.curDayClose.toLocaleString()} (${t.priceChangePercent.toFixed(2)}% 24h)`;
}

toolbar.append(
buttonGroup(SYMBOLS, (s) => s, "BTC-USD", (symbol) => {
chart.setSymbol(symbol); // reload the chart's candles for the new symbol
ticker.unsubscribe();
ticker = client.getTickerStream(symbol).subscribe(showTicker);
}),
buttonGroup(intervals, (i) => i, CandleInterval.ONE_HOUR, (interval) => chart.changeInterval(interval)),
price
);

// When the page goes away: ticker.unsubscribe(); financeChartPanel.cleanup();
return financeChartPanel;
}

// A row of toggle buttons: one per value, the selected one highlighted
function buttonGroup<T>(values: readonly T[], label: (v: T) => string, selected: T, onSelect: (v: T) => void) {
const group = document.createElement("div");
Object.assign(group.style, { display: "flex", gap: "4px" });
const render = (current: T) =>
group.replaceChildren(
...values.map((value) => {
const b = document.createElement("button");
b.textContent = label(value);
Object.assign(b.style, buttonStyle(value === current));
b.onclick = () => {
render(value);
onSelect(value);
};
return b;
})
);
render(selected);
return group;
}

// The toolbar uses SciTrader's UI colours: its --st-ui-* CSS variables, with the stylesheet's defaults
const toolbarStyle: Partial<CSSStyleDeclaration> = {
display: "flex",
flexWrap: "wrap",
alignItems: "center",
gap: "8px 16px",
padding: "8px",
background: "var(--st-ui-background, #2b2839)",
borderBottom: "1px solid var(--st-ui-divider, rgba(255,255,255,0.1))",
color: "var(--st-ui-text-muted, #9da2bc)",
fontSize: "13px",
};
const buttonStyle = (active = false): Partial<CSSStyleDeclaration> => ({
padding: "4px 10px",
border: "1px solid var(--st-ui-divider, rgba(255,255,255,0.1))",
borderRadius: "6px",
background: active ? "var(--st-ui-selection, #6c63ff)" : "var(--st-ui-surface, #373447)",
color: "var(--st-ui-text, #ffffff)",
font: "inherit",
fontSize: "13px",
cursor: "pointer",
});

createChart();

React Example: A Live Coinbase API Chart​

The same chart in React. The ticker subscription lives in an effect, which resubscribes when the symbol changes.

The code for this example is found below.

import "scichart-scitrader/scitrader.css";
import * as React from "react";
import {
CandleInterval,
CoinbaseExchange,
defaultExchangeProvider,
idbPriceStore,
ISciFinanceChartPanelApi,
ISciFinanceChartPanelConfig,
OHLCStudy,
SciTraderTicker,
VolumeStudy,
} from "scichart-scitrader";
import { SciFinanceChartView } from "scichart-scitrader-react";

// Register Coinbase once, at app startup, with a candle store: idbPriceStore keeps downloaded
// candles in IndexedDB, so a reload or a return visit draws from the cache
defaultExchangeProvider.registerExchange(CoinbaseExchange, idbPriceStore);

const SYMBOLS = ["BTC-USD", "ETH-USD", "SOL-USD"]; // Coinbase's symbol format: BASE-QUOTE
// The intervals Coinbase serves: 1m, 5m, 15m, 1h, 6h and 1d
const INTERVALS = CoinbaseExchange.getSupportedIntervals();

export function CoinbaseChart() {
const chartRef = React.useRef<ISciFinanceChartPanelApi>(null);
const [symbol, setSymbol] = React.useState("BTC-USD");
const [interval, setInterval] = React.useState(CandleInterval.ONE_HOUR);
const [ticker, setTicker] = React.useState<SciTraderTicker>();

// Create the config once per mounted chart: studies are live objects bound to one chart
const config = React.useMemo<ISciFinanceChartPanelConfig>(
() => ({
exchangeName: CoinbaseExchange.name, // "Coinbase": the name it was registered under
symbol: "BTC-USD",
interval: CandleInterval.ONE_HOUR,
period: "1W",
studies: [new OHLCStudy(), new VolumeStudy()],
}),
[]
);

// The registered exchange's client also gives live data: here a ticker, the latest price and
// the 24-hour change, for the chart's symbol. Unsubscribe when the symbol changes or on unmount
React.useEffect(() => {
const subscription = defaultExchangeProvider.getExchange(CoinbaseExchange.name).getTickerStream(symbol).subscribe(setTicker);
return () => subscription.unsubscribe();
}, [symbol]);

// financeApi throws until the chart has initialised
const chart = () => (chartRef.current?.isInitialized ? chartRef.current.financeApi : undefined);

// Fills its parent, so give the parent a height
return (
<div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
<div style={toolbarStyle}>
<ButtonGroup
values={SYMBOLS}
selected={symbol}
onSelect={(s) => {
setSymbol(s);
chart()?.setSymbol(s); // reload the chart's candles for the new symbol
}}
/>
<ButtonGroup
values={INTERVALS}
selected={interval}
onSelect={(i) => {
setInterval(i);
chart()?.changeInterval(i);
}}
/>
{ticker && (
<span>{`${ticker.symbol} ${ticker.curDayClose.toLocaleString()} (${ticker.priceChangePercent.toFixed(2)}% 24h)`}</span>
)}
</div>
<div style={{ flex: 1, minHeight: 0 }}>
<SciFinanceChartView ref={chartRef} config={config} />
</div>
</div>
);
}

// A row of toggle buttons: one per value, the selected one highlighted
function ButtonGroup<T extends string>(props: { values: readonly T[]; selected: T; onSelect: (v: T) => void }) {
return (
<div style={{ display: "flex", gap: 4 }}>
{props.values.map((value) => (
<button key={value} style={buttonStyle(value === props.selected)} onClick={() => props.onSelect(value)}>
{value}
</button>
))}
</div>
);
}

// The toolbar uses SciTrader's UI colours: its --st-ui-* CSS variables, with the stylesheet's defaults
const toolbarStyle: React.CSSProperties = {
display: "flex",
flexWrap: "wrap",
alignItems: "center",
gap: "8px 16px",
padding: 8,
background: "var(--st-ui-background, #2b2839)",
borderBottom: "1px solid var(--st-ui-divider, rgba(255,255,255,0.1))",
color: "var(--st-ui-text-muted, #9da2bc)",
fontSize: 13,
};
const buttonStyle = (active = false): React.CSSProperties => ({
padding: "4px 10px",
border: "1px solid var(--st-ui-divider, rgba(255,255,255,0.1))",
borderRadius: 6,
background: active ? "var(--st-ui-selection, #6c63ff)" : "var(--st-ui-surface, #373447)",
color: "var(--st-ui-text, #ffffff)",
font: "inherit",
fontSize: 13,
cursor: "pointer",
});

Charting the Binance API​

Binance is the same, with Binance's name and symbols. It also serves intervals Coinbase doesn't, such as 4h and 1w:

import { BinanceExchange, CandleInterval, defaultExchangeProvider, idbPriceStore, OHLCStudy, SciFinanceChartPanel, VolumeStudy } from "scichart-scitrader";

defaultExchangeProvider.registerExchange(BinanceExchange, idbPriceStore);

const financeChartPanel = await SciFinanceChartPanel.create(document.getElementById("chart"), {
exchangeName: BinanceExchange.name, // "Binance"
symbol: "BTCUSDT",
interval: CandleInterval.FOUR_HOURS,
period: "3M",
studies: [new OHLCStudy(), new VolumeStudy()],
});

Fewer, larger requests. BinanceExchange.candleLimit sets the candles per request, 1,000 by default, Binance's maximum. Set it before the first chart is created; the client reads it once.

CoinbaseExchange and BinanceExchange API​

Both are IRemoteExchange objects; Building a Custom Exchange documents every member.