Sequence/docs

Market Data

Everything you need to see the market — NBBO and book snapshots, balance + position views, fees, pre-trade previews, history, funding rates, and prediction-market discovery. Most of these endpoints are cold-resilient by default: the first call on an unwarmed symbol falls back through dynamic-subscribe → edge-routed REST snapshot → venue public API, so you don't need an explicit warm step before trading.


Quote — single symbol

NBBO + per-venue BBO + merged book. The one call every strategy starts with.

rust
let q = seq.quote("BTC-USD").await?;
println!("mid={:.2} spread={}bps source={}",
    q.nbbo.mid, q.nbbo.spread_bps, q.source);

Returns Quote { symbol, nbbo, venues: HashMap<_, QuoteVenue>, book: Option<QuoteBook>, source }.

The source field

Every quote tells you which path served it. Trading code must gate on source == "edge_nbbo" for live-WS guarantees; research can accept any non-unavailable source.

ValueMeaning
edge_nbboCache hit — live WebSocket NBBO, sub-ms
edge_rpc_snapshotCold-path REST through the edge — 100–300ms, also kicks off background WS subscribe
venue_public_apiGraceful-degradation fallback — edge RPC unreachable
unavailableNo path produced book data (market empty, venue 404'd)

Skipping the cold-subscribe wait

For research-grade scans where you don't care if the first call returns zeros on cold symbols, skip the up-to-2s wait:

rust
let q = seq.quote("BTC-USD").nowait(true).send().await?;

Trading code must never pass nowait=true — first-call zeros on cold tickers will silently misroute orders.


Quote — batch (50+ symbols)

POST /v1/quotes_batch does server-side fan-out with bounded concurrency. Per-symbol errors return as partials so one bad ticker can't fail the whole batch.

rust
let r = seq.quotes_batch(&[
    "BTC-USD",
    "4394372887385518214471608448209527405727552777602031099972143344338178308080",
    "KXNBA-26-TOR",
])
.depth(20)
.nowait(true)        // recommended for batches of 50+
.concurrency(64)     // cap 256
.send()
.await?;
 
for entry in r.quotes {
    match entry {
        BatchQuoteEntry::Ok(q) => { /* q.source, q.nbbo, q.book */ }
        BatchQuoteEntry::Err { symbol, error } => eprintln!("{symbol}: {error}"),
    }
}
ParamDefaultNotes
depth10Book levels per side (1–100)
nowaittrueDefault true — serial 2s waits are catastrophic at batch scale
concurrency64Max concurrent upstream fetches (cap 256)
instrument_typeautoOverride "spot" / "perp" / "prediction"

Positions & Balances (unified)

One endpoint, one shape, across fiat, crypto, perps, and event contracts. Fills come from three reconciled sources (fills → write path, venue balance APIs, venue portfolio APIs).

rust
use sequence_sdk::InstrumentKind;
 
// All active positions across every venue
let resp = seq.positions_unified().fetch().await?;
println!("NAV = ${:.2}", resp.totals.nav_usd_1e9 as f64 / 1e9);
 
// Cash-only (fiat + crypto stablecoins)
let cash = seq.positions_unified().cash_only().fetch().await?;
 
// Event contracts on Kalshi + Polymarket
let events = seq.positions_unified()
    .events_only()
    .venue("kalshi")
    .venue("polymarket")
    .fetch().await?;

Builder methods: .venue(s), .kind(k), .cash_only(), .events_only(), .include_closed(b).

Each PositionView carries qty_1e8, entry_price_usd_1e9, current_price_usd_1e9, unrealized_pnl_usd_1e9, realized_pnl_usd_1e9, fees_usd_1e9, lifecycle, settled: bool, settled_mark_usd_1e9: Option<i64>. settled flips to true the instant resolution telemetry lands — check it to render post-settlement P&L without waiting for the venue to zero out qty.

instrument.kind is a tagged union:

kindAdditional fields
"fiat"code (e.g. "USD")
"crypto"symbol (e.g. "BTC", "USDC")
"perp"symbol, base
"event_contract"market_slug, outcome, token_id?, expiry_ts?
Note

The legacy balances(), positions(), perp_positions(), and portfolio() methods are deprecated and point at endpoints that now return 404. Migrate to positions_unified() before the next major.


Fees

Maker/taker fees per venue for a ticker. null taker/maker means "do not route here," not "free."

rust
let resp = seq.fees("KXMLBHR-26APR292140KCATH-ATHLBUTLER4-1:YES")
    .venues(&["kalshi", "polymarket"])
    .fetch().await?;
for row in &resp.fees {
    println!("{} taker={:?} maker={:?}",
        row.venue, row.taker_bps, row.maker_bps);
}

/v1/fees returns the fee components and curve formula (fee_model, components.rate_bps, formula.taker_fee_usd) so latency-sensitive callers can compute the exact realized fee locally — fetch once per ticker, cache, evaluate per fill. For a server-authoritative answer that also includes size-aware slippage and total landed cost, use preview() below.


Pre-trade Preview

Estimated fee + slippage + total cost + historical time-to-first-fill across candidate venues, without submitting.

rust
use sequence_sdk::Side;
 
let p = seq.preview("ETH-USD", Side::Buy, 50.0).await?;
println!("best_venue={} cost_bps={}",
    p.best_venue, p.estimated_total_cost_bps);

Returns OrderPreview { candidate_venues, best_venue, estimated_fee_bps, worst_case_fee_bps, estimated_slippage_bps, estimated_total_cost_bps, historical_ttff, nbbo, source, generated_at_ns, … }.

Cold-resilient by default. First call on a cold ticker takes ~200–500ms and returns real fee + slippage + NBBO. NBBO fields (bid_px_1e9, ask_px_1e9, mid_px_1e9, spread_bps) are nullable — one-sided books return None on the missing side rather than serializing sentinel values. The same cold-fallback applies to /v1/intelligence/depth, /v1/intelligence/slippage, /v1/intelligence/routing, and /v1/execution/forecast — no explicit quote() warm step needed.


Price History

Unified history primitive across CEX, perp, DEX, Kalshi, and Polymarket. Bar mode (default) or tick mode (fidelity_secs=0).

rust
use sequence_sdk::builders::history::Range;
 
// Year of Binance BTC-USDT 5-min bars
let btc = seq.price_history("BTC-USDT")
    .range(Range::OneYear).fidelity_secs(300).venue("binance")
    .fetch().await?;
 
// Last 500 tape prints with qty + side
let ticks = seq.price_history("BTC-USDC").ticks(500).fetch().await?;
 
// Polymarket 5-min lifecycle, include Chainlink underlying
let hist = seq.price_history("btc-updown-5m-1776537600")
    .fidelity_secs(0).limit(50_000).underlying()
    .fetch().await?;
if let Some(u) = hist.underlying {
    if u.agrees_with_settlement == Some(false) { /* drop for ML */ }
}

Builder methods: .range(Range), .fidelity_secs(secs), .venue(v), .ticks(n), .start_ts(s) / .end_ts(s), .paginated(), .underlying(), .fetch().

Key points:

  • fidelity_secs=0 switches to tick mode — points carry qty_1e8, side, venue_id.
  • venue is required for long-range (>24h) CEX/perp/DEX queries; ignored for Polymarket / Kalshi / short-range.
  • paginate=true (Polymarket-only) walks back in 7-day windows to bypass the venue's ~5k-point per-call cap.
  • underlying=true includes the Chainlink/Binance underlying curve for Polymarket crypto updowns; agrees_with_settlement == false is a signal to drop for ML training.

Funding Rates

Perpetual funding rates, normalized to bps_per_hour so Binance (8h cadence) and Hyperliquid (continuous) are directly comparable.

rust
let all = seq.funding_rates().await?;
let one = seq.funding_rate("hyperliquid", "ETH-USD-PERP").await?;
let venue = seq.funding_rates_for_venue("binance").await?;

Each FundingRate carries rate_bps_per_hour, predicted_rate_bps_per_hour, mark_price_1e9, open_interest_1e8, next_settlement_ns, snapshot_age_ms.

funding_history returns a signed rate_1e9 per settlement — divide by 1e9 then multiply by 10,000 for per-settlement bps. Positive means longs pay shorts.


Prediction-Market Discovery

Unified Kalshi + Polymarket discovery. Every market comes back in the same shape so you can call quote(market.yes_token_id) without branching on venue.

rust
// Whole open Kalshi universe (~43k rows, ~4 s)
let all = seq.markets("kalshi").active_only(true).fetch_all().await?;
 
// Manual cursor for streaming/progress
let p1 = seq.markets("kalshi").active_only(true).limit(1000).fetch().await?;
if let Some(c) = p1.next_cursor.as_deref() {
    let p2 = seq.markets("kalshi").active_only(true).limit(1000)
        .cursor(c).fetch().await?;
}
 
// Direct slug lookup
let m = seq.market("fed-decision-in-october", "polymarket").await?;

For "everything Kalshi/PM ever recorded," pair active=true, closed=true — see Status filters for the full matrix.

Note

Tripwire — order_by: the SDK's previous default of order_by("volume") silently routed every Kalshi call through a 4× over-fetch + client-side rerank that broke cursor invariants — exhaustive walks capped at ~25% of the catalog. The default is now empty (no sort); pass order_by("volume") explicitly only when you want top-by-volume and aren't paginating.


Settlement (prediction markets)

Prediction-market ground truth. resolved_outcome is always what the venue paid — never reconstructed from our Chainlink read.

rust
let s = seq.settlement("btc-updown-5m-1776537600")
    .with_underlying()
    .fetch().await?;
if s.status == "resolved" {
    println!("paid: {:?}", s.resolved_outcome);
}

Returns Settlement { slug, question, outcomes, outcome_token_ids, yes_token_id, no_token_id, condition_id, neg_risk, status, resolved_outcome, outcome_source, yes_price, no_price, event_start_s, event_end_s, resolution_source, underlying }.

underlying=true includes the Chainlink curve resampled inside the event window (slower — bounded on-chain RPC). When agrees_with_settlement == false, the on-chain price disagreed with the venue's payout — drop for ML training.


Fixed-point conventions

Every wire payload uses the same scale. The _1e8 / _1e9 / _bps / _ns suffixes are load-bearing:

SuffixScaleExample
_1e8× 10⁸1 BTC = 100_000_000, 0.5 ETH = 50_000_000
_1e9× 10⁹$50,000 = 50_000_000_000_000
_bpsbasis points10 bps = 0.10%
_nsnanoseconds since Unix epoch1705406400000000000
(no suffix)human floatbid: 73984.57

The Rust SDK exposes Qty / Px wrappers that hold both views (Qty::from_human(1.5)qty.human() == 1.5). The Python SDK keeps responses as plain dicts — convert explicitly: qty = row["qty_1e8"] / 1e8.


Next steps