Historical queries
HistoricalService returns archived trades and candles for any pair within the deployment's retention window. It is public and runs on the public listener. Pulls from the deployment's historical archive when configured.
What's available
| RPC | Returns | Cap |
|---|---|---|
GetTrades | Trades within [start, end) for a pair. | 1,000 rows per call |
GetCandles | OHLCV candles at one of seven intervals. | 10,000 rows per call |
If the deployment doesn't have the historical archive enabled, every RPC returns FAILED_PRECONDITION. Read it once at boot to feature-gate the UI.
Range semantics
startandendareTimestamp { micros }values, i.e. Unix microseconds.startis inclusive.endis exclusive. Unset ormicros = 0means "now".GetTradesreturns rows newest-first.GetCandlesreturns rows oldest-first.- Maximum window is 30 days per call. Larger spans need to be paginated.
- Historical
price,size, and OHLCV values areDecimalstrings — the same wire format as the live book and fill streams. Parse with a fixed-precision type (rust_decimal,bignumber.js).
Backfill recipe
To paginate a long span (e.g. a year of 1-minute candles), chunk by the row cap:
use sweetspot_api_client::api::proto::{CandleInterval, GetCandlesRequest, Pair, SpotId, Timestamp};
let mut historical = client.historical();
let interval_us = 5 * 60 * 1_000_000u64;
let max_rows = 10_000u64;
let window_us = max_rows * interval_us;
let mut start = start_us;
let mut all = Vec::new();
while start < end_us {
let end = (start + window_us).min(end_us);
let res = historical
.get_candles(GetCandlesRequest {
pair: Some(Pair { base: Some(SpotId { id: 1 }), quote: Some(SpotId { id: 0 }) }),
interval: CandleInterval::CandleInterval5m.into(),
start: Some(Timestamp { micros: start }),
end: Some(Timestamp { micros: end }),
})
.await?
.into_inner();
all.extend(res.candles);
start = end;
}import {
GrpcWebTransport,
HistoricalService,
createServiceClient,
} from "@superis-labs/sweetspot-client";
import {
CandleInterval,
type Candle,
} from "@superis-labs/sweetspot-client/gen/sweetspot/api/v1/historical/messages_pb.js";
const historical = createServiceClient(
HistoricalService,
new GrpcWebTransport({
baseUrl: "https://api.superis.exchange",
}),
);
const intervalUs = 5n * 60n * 1_000_000n;
const maxRows = 10_000n;
const windowUs = maxRows * intervalUs;
let start = startUs;
const all: Candle[] = [];
while (start < endUs) {
const end = start + windowUs > endUs ? endUs : start + windowUs;
const { candles } = await historical.getCandles({
pair: { base: { id: 1n }, quote: { id: 0n } },
interval: CandleInterval.CANDLE_INTERVAL_5M,
start: { micros: start },
end: { micros: end },
});
all.push(...candles);
start = end;
}from flint import Client, Endpoints
from flint.gen.sweetspot.api.v1 import common_pb2
from flint.gen.sweetspot.api.v1.historical import messages_pb2 as hist
client = Client(
Endpoints(
public_url="https://api.superis.exchange",
)
)
request = hist.GetCandlesRequest(
pair=common_pb2.Pair(
base=common_pb2.SpotId(id=1),
quote=common_pb2.SpotId(id=0),
),
interval=hist.CANDLE_INTERVAL_5M,
start=common_pb2.Timestamp(micros=start_us),
end=common_pb2.Timestamp(micros=end_us),
)
response = await client.historical_candles(request)Stitching with live
For a chart that shows the last 24h:
GetCandleswithstart.micros = now_us - 86_400_000_000andend.micros = now_usto pull the historical body.- Subscribe to
MarketDataService.Subscribefor the pair to drive live updates fromnowforward, computing the last candle yourself from the fill stream — or justGetCandlesagain every interval for less aggressive UIs.
The historical and live paths align on the interval boundary.
When to prefer live
HistoricalService.GetTrades over a recent window is more expensive than just streaming MarketDataService.SubscribeFills and ringing your own buffer. Use the historical path for backfill or for ranges older than your in-memory retention; use the live path for anything inside the active session.
