Expand description
Historical klines (OHLCV candles) via Binance’s public, unauthenticated REST
endpoints — spot (/api/v3/klines) and futures continuous
(/fapi/v1/continuousKlines).
Historical klines (OHLCV candles) via Binance’s public, unauthenticated
REST endpoints.
Gives consumers free historical candle data for research/backtest on both
BinanceSpot and
BinanceFuturesUsd — no API key, no paid
data subscription. Construct a client for the surface you want and call
fetch_candles:
use rustrade_data::exchange::binance::historical::BinanceHistoricalClient;
use rustrade_data::subscription::candle::CandleInterval;
use chrono::{Duration, Utc};
use futures::StreamExt;
let client = BinanceHistoricalClient::spot();
let end = Utc::now();
let start = end - Duration::days(1);
let mut stream = client.fetch_candles("BTCUSDT", CandleInterval::Min1, start, end);
while let Some(candle) = stream.next().await {
println!("{:?}", candle?);
}§Two surfaces, one mapping
Spot and futures return the same array-of-arrays row shape and share one
row→Candle mapping. They differ only on host, page cap, and URL params:
| Surface | Endpoint | Host | Page cap | Market param |
|---|---|---|---|---|
spot | /api/v3/klines | api.binance.com | 1000 | symbol |
futures | /fapi/v1/continuousKlines | fapi.binance.com | 1500 | pair + contractType=PERPETUAL |
The futures path uses the continuous-contract surface (contractType=PERPETUAL)
rather than /fapi/v1/klines. For a perpetual this is the same data as the
symbol klines plus sub-minute resolutions: /fapi/v1/klines returns
400 Invalid interval for Sec1, whereas the
continuous surface serves genuine 1-second candles.
§Rate limits & resumable backfill
On HTTP 429/418 the stream yields
BinanceDataError::RateLimited and ends — it never waits, retries, or
runs a process-global limiter (the consumer owns retry/backoff). The stream is
resumable: on a RateLimited error, wait retry_after, then re-invoke
fetch_candles with start advanced to 1ms past the last close_time
already received (last_close_time + 1ms, i.e. the next candle’s open). The
[start, end] range is close_time-inclusive, so resuming exactly at
last_close_time would re-yield that final candle; the +1ms step skips it
without leaving a gap. No progress is lost — pagination keys off open_time,
and open ≡ close − interval.
A long unattended backfill (a 90-day 1s series is ≈ 7.8M candles over
thousands of requests) will not “just work” without that resume loop on
the consumer side, but the default pre-pacing
keeps a single steady backfill within Binance’s weight budget so the common
case rarely trips a 429 in the first place.
Structs§
- Binance
Historical Client - REST client for Binance historical klines on a single surface (spot or
futures-continuous). Construct with
spotorfutures; both bake in the surface’s host, page cap, and a conservative default pre-pace.