Skip to Content
Symmio Trading-SDK — the SDK surface for builders on Arbitrum
CoreCandlescreateBinanceCandleSource

createBinanceCandleSource

Create a CandleSource backed by Binance klines. History comes from the REST /klines endpoint, paged backwards from the end of the requested range, and live bars from the kline WebSocket stream.

Both are reachable directly from a browser — Binance serves permissive CORS headers on market data, so no proxy and no API key is involved.

import { createBinanceCandleSource } from "@symmio/trading-core"; const source = createBinanceCandleSource(); const { candles, noMoreData } = await source.getCandles({ marketName: "BTCUSDT", resolution: "1m", from: rangeStart, to: rangeEnd, limit: 60, }); const unwatch = source.watchCandles?.({ marketName: "BTCUSDT", resolution: "1m", onCandle: (candle, { closed }) => series.update(candle), });

Parameters

market"usd-m-futures" | "spot"optional

Which Binance market to read. Defaults to "usd-m-futures" — its symbols are perpetual contracts, matching what a SYMMIO market actually is. Use "spot" for markets with no futures listing.

restUrlstringoptional

Override the REST host — a regional mirror, or your own caching proxy.

wsUrlstringoptional

Override the WebSocket endpoint. Keep the futures /market/ route; see the routing note below.

resolveSymbol(marketName: string) => string | undefinedoptional

Map a SYMMIO market name onto a Binance symbol, or return undefined when the market has no Binance listing. Defaults to an upper-case identity mapping.

webSocketConstructorWebSocketConstructoroptional

WebSocket implementation for watchCandles. Defaults to globalThis.WebSocket; pass the ws package in Node environments without one.

Returns

CandleSource

A source with id of `binance:${market}`, priceBasis of "reference-exchange", the market’s supported resolutions, maxCandlesPerRequest (1500 futures, 1000 spot), and all three methods implemented.

The WebSocket route is not the documented one

Binance routes futures streams by class. On fstream.binance.com the documented /stream and /ws forms accept the SUBSCRIBE frame, acknowledge it with {"result":null}, and then never push a single kline — a feed that reports open and silently never ticks. Only the /market/ paths deliver kline frames, which is why the default is wss://fstream.binance.com/market/stream. Spot needs no such prefix.

This is deliberately not the /public/stream route the orderbook source dials — depth and klines live on different route classes. If you override wsUrl, keep the route class.

Symbol mapping

The default mapping upper-cases the market name, which holds for current SYMMIO deployments where market names are already Binance USD-M symbols. Override resolveSymbol rather than relying on that coincidence if your deployment’s names can diverge — an unmapped name otherwise resolves to a symbol that does not exist and the chart simply stays empty.

const source = createBinanceCandleSource({ resolveSymbol: (marketName) => SYMBOL_BY_MARKET[marketName], });

getSymbol returns undefined for a market the venue does not list — the check to run before rendering a chart for it.

How history is paged

Binance caps a bounded range request from its start: sending startTime, endTime, and limit together returns the oldest limit bars in the window, which for a chart scrolling back is the wrong end entirely. The source therefore pages backwards from to, sending endTime only, and applies the from bound client-side. Requests are capped at the venue’s per-request limit and paged transparently, so ask for as many bars as you need.

Low-level exports

The pieces the source is built from are exported for consumers assembling their own:

ExportWhat it is
BINANCE_REST_URLDefault REST host per market.
BINANCE_WS_URLDefault combined-stream WebSocket endpoint per market (futures uses /market/).
BINANCE_KLINES_PATHKlines REST path per market.
BINANCE_EXCHANGE_INFO_PATHExchange-info REST path per market, used to resolve price precision.
BINANCE_MAX_LIMITBars per request the venue accepts — 1500 futures, 1000 spot; more is a hard -1130 error.
parseBinanceKlineREST kline tuple → Candle. Throws INVALID_BINANCE_KLINE on malformed input.
parseBinanceKlineEventWebSocket k payload → Candle.
toBinanceIntervalSDK resolution → Binance interval string, or undefined when the market has no equivalent bucket.
getBinanceSupportedResolutionsResolutions a Binance market can serve, ascending.
BinanceMarket"usd-m-futures" | "spot".

Spot additionally serves 1s klines; futures does not, and neither market has the SDK’s 10s bucket.

Throws

  • UNSUPPORTED_CANDLE_RESOLUTION — the market has no klines interval for the requested resolution.
  • UNMAPPED_CANDLE_MARKETresolveSymbol returned undefined for the market.
  • NO_WEBSOCKET_IMPLEMENTATIONwatchCandles was called with no WebSocket available and none injected.

Operational notes

  • exchangeInfo is fetched once per source and shared by every getSymbol call; a rejection clears the cache so a transient failure does not poison the source for its lifetime. Memoize the source — recreating it per render refetches that and re-dials any live subscription.
  • api.binance.com and fapi.binance.com are blocked in some jurisdictions; restUrl / wsUrl exist for that.
Last updated on