SPB Git forge

spb/market-atlas

Public
12commits 1branches 0releases
1.1 MBsize
maindefault branch
10 days agolast push
TypeScript 96.7% SQL 1.6% CSS 0.8% JavaScript 0.5%
10.2 KB · 156 lines tsx
Raw Blame History
1import type { Metadata } from "next";2import Link from "next/link";3import { Page, PageHeader } from "@/components/ui/section";4import { SITE_URL } from "@/lib/site";56export const metadata: Metadata = { title: "Developers", description: "Market Atlas API: REST endpoints, WebSocket and SSE streams, envelopes, errors and rate limits.", alternates: { canonical: "/developers" } };78const REST: Array<[string, string]> = [9  ["GET /v1/stats", "Live telemetry (instruments, connectors, observations today, events, freshness)."],10  ["GET /v1/markets", "Global overview: featured indices, crypto, FX, rates, commodities, equities, movers, exchanges with state, breadth."],11  ["GET /v1/instruments?asset_class=&exchange=&country=&q=&quoted=1&sort=&limit=&offset=", "Instrument master with canonical quotes. sort ∈ symbol | change | -change | volume | name."],12  ["GET /v1/instruments/{id|SYMBOL|VENUE:SYMBOL}", "Instrument detail: company, exchange + status, quote, aliases, observing sources, related instruments."],13  ["GET /v1/quotes/{id}", "One canonical quote."],14  ["GET /v1/quotes?ids=a,b,c", "Up to 200 canonical quotes."],15  ["GET /v1/quotes/{id}/provenance", "“Why this price?” — source coverage matrix: every contribution with observation_type, delta_bps vs consensus, weight, age, inclusion and reason; plus comparability, proxy/validator confirmations, coverage and shared_upstream_pairs."],16  ["GET /v1/coverage?asset_class=&tier=A|B|C|D&limit=", "Source Coverage Engine: summary (quoted, multiSource, byFamilies ≥5/≥3/≥2/1/0, weightedScore, tiers attainment, byAssetClass, proxiesConfirming, validatorsConfirming), targets, source-expansion queue, inferred shared upstreams (lineage)."],17  ["GET /v1/coverage/{id}", "Coverage of one instrument: tier, target, families, observations, proxies, validators, live/delayed/official counts, score, status, gap."],18  ["GET /v1/history/{id}?resolution=1m|5m|15m|1h|1d&from=&to=&limit=", "OHLCV bars (t, o, h, l, c, v, n sources, p producer)."],19  ["GET /v1/events?type=&instrument=&country=&asset_class=&severity=&since=&before=&limit=", "Canonical events; GET /v1/events/{id} for one."],20  ["GET /v1/filings?form=&cik=&q=&limit=&offset=", "Regulatory filings observed on EDGAR."],21  ["GET /v1/exchanges · GET /v1/exchanges/{id}", "Venues with session state, holidays, breadth, movers, events."],22  ["GET /v1/countries · GET /v1/countries/{code}", "Country atlas: exchanges, indices, rates, FX, equities, events."],23  ["GET /v1/search?q=", "Hybrid search grouped by asset class, exchange, country."],24  ["GET /v1/compare?ids=&resolution=", "Rebased series, return/volatility/drawdown, pairwise correlation."],25  ["GET /v1/changes?window=1m|5m|15m|1h|1d", "What changed: movers > 1 %, events, filings, by type."],26  ["GET /v1/breadth?scope=world|US|xnas", "Advancers/decliners/highs/lows for a scope."],27  ["GET /v1/sources · GET /v1/connectors · GET /v1/data-health · GET /v1/status · GET /v1/health · GET /v1/metrics", "Provenance directory, connector operations, health, public status, liveness, Prometheus metrics."],28];2930export default function DevelopersPage() {31  const base = SITE_URL;32  const ws = base.replace(/^http/, "ws");33  return (34    <Page>35      <PageHeader kicker="API v1" title="Developers" lead="Public, read-only API over the same canonical data the site shows. Every response carries provenance metadata; values whose data rights forbid redistribution are withheld rather than silently omitted." />36      <div className="prose-ma max-w-3xl">37        <h2>Base URL & envelope</h2>38        <pre>39          <code>{`${base}/v14041{ "data": …, "meta": { "request_id": "…", "timestamp": "2026-09-12T14:31:42.512Z", "data_status": "DELAYED" } }`}</code>42        </pre>43        <p>44          Errors are structured: <code>{`{ "error": { "code": "INSTRUMENT_NOT_FOUND", "message": "instrument not found" } }`}</code> with the matching HTTP status. No stack traces.45        </p>46        <h2>Rate limits</h2>47        <p>48          20 requests per second sustained per IP (burst 300) on <code>/v1</code> REST; <code>429</code> with <code>Retry-After</code> when exceeded. Streams and web pages are not counted. Higher limits and API keys will come with the developer accounts.49        </p>50        <h2>REST endpoints</h2>51        <table>52          <thead>53            <tr>54              <th>Endpoint</th>55              <th>Description</th>56            </tr>57          </thead>58          <tbody>59            {REST.map(([e, d]) => (60              <tr key={e}>61                <td>62                  <code>{e}</code>63                </td>64                <td>{d}</td>65              </tr>66            ))}67          </tbody>68        </table>69        <h3>Example</h3>70        <pre>71          <code>{`curl ${base}/v1/quotes/BTC-USD7273{74  "data": {75    "instrument_id": "crypto_btc_usd", "symbol": "BTC-USD", "price": 77326.37, "change_percent": 0.0275,76    "bid": 77326.36, "ask": 77326.37, "currency": "USD",77    "source_count": 4, "observation_count": 7, "proxy_count": 0, "validator_count": 0, "comparability": "LIVE",78    "dispersion_bps": 2.13, "confidence": 0.958, "freshness_ms": 1552,79    "data_status": "REALTIME", "market_state": null, "rights_status": "PUBLIC_ATTRIBUTED", "withheld": false,80    "updated_at": "2026-09-12T08:42:34.479Z", "source_timestamp": "2026-09-12T08:42:34.358Z"81  },82  "meta": { "request_id": "…", "timestamp": "…", "data_status": "REALTIME" }83}`}</code>84        </pre>85        <h2>Quote fields</h2>86        <ul>87          <li>88            <code>data_status</code>: <code>REALTIME</code> · <code>DELAYED</code> · <code>AT_CLOSE</code> · <code>END_OF_DAY</code> · <code>STALE</code> · <code>WITHHELD</code>. Never treat anything but <code>REALTIME</code> as live.89          </li>90          <li>91            <code>source_count</code> = independent <em>voting</em> source families; <code>observation_count</code> = fresh observations of any role; <code>proxy_count</code> = stablecoin/derived proxies agreeing within 50 bp; <code>validator_count</code> = restricted-rights sources agreeing within 25 bp; <code>comparability</code> ∈ <code>LIVE</code> · <code>FIX</code> · <code>EOD</code> = class of the canonical value; <code>dispersion_bps</code> = spread between voting sources; <code>confidence</code> ∈ [0, 0.995].92          </li>93          <li>94            Provenance contributions: <code>observation_type</code> ∈ TRADE · MID · QUOTE · INDEX_VALUE · INDICATIVE · STABLECOIN_PROXY · DERIVED · OFFICIAL_FIX · REFERENCE_RATE · SETTLEMENT · EOD_CLOSE · NAV; <code>delta_bps</code> = distance to the canonical value; <code>reason</code> ∈ stale · not_comparable · temporal_mismatch · validation_only · validator_disagrees · outlier. Validator values are <code>null</code> (withheld).95          </li>96          <li>97            <code>freshness_ms</code> = age of the newest included observation at response time; <code>source_timestamp</code> is the source's own time when published.98          </li>99        </ul>100        <h2>WebSocket stream</h2>101        <pre>102          <code>{`${ws}/v1/stream103104→ { "action": "subscribe", "channels": ["quotes:BTC-USD", "quotes:AAPL", "events:*", "market:xnas"] }105← { "type": "hello", "version": 1, "server_seq": 1024, "ts": 1789202146812 }106← { "type": "subscriptions", "channels": ["quotes:crypto_btc_usd", "quotes:eq_us_xnas_aapl", "events:*", "market:xnas"] }107← { "type": "batch", "seq": 1, "ts": 1789202146921, "messages": [108      { "type": "quote", "instrument_id": "crypto_btc_usd", "symbol": "BTC-USD", "price": 77326.37, "change": 21.27, "change_pct": 0.0275,109        "bid": 77326.36, "ask": 77326.37, "volume": 6634.6, "currency": "USD", "timestamp": 1789202146563, "received": 1789202146819,110        "confidence": 0.906, "sources": 2, "status": "REALTIME" },111      { "type": "event", "event": { "id": "evt_…", "type": "TRADING_HALT", "title": "…", "severity": "WARNING", "confidence": 1, "source_count": 1, "sources": ["nasdaq-trader"], "instrument_ids": [], "data": { … } } },112      { "type": "market_state", "exchangeId": "xnas", "state": "OPEN", "at": 1789392600000 }113   ] }114← { "type": "heartbeat", "ts": …, "seq": 42 }     (every 25 s)115→ { "action": "ping", "id": 1 }  ←  { "type": "pong", "id": 1, "ts": … }116→ { "action": "unsubscribe", "channels": ["quotes:AAPL"] }`}</code>117        </pre>118        <p>Channels:</p>119        <ul>120          <li>121            <code>quotes:&lt;SYMBOL|id&gt;</code> one instrument · <code>quotes:*</code> everything (throttled to 2 updates/s per instrument) · <code>quotes:class:CRYPTO</code> one asset class · <code>tape</code> compact price changes.122          </li>123          <li>124            <code>events:*</code> · <code>events:&lt;SYMBOL|id&gt;</code> · <code>events:US</code> (country) · <code>events:type:TRADING_HALT</code>.125          </li>126          <li>127            <code>market:&lt;exchange&gt;</code> or <code>market:*</code> for session-state changes.128          </li>129        </ul>130        <p>131          Frames are batched (≈ 10 per second per client) and carry a per-client <code>seq</code>; a gap means messages were dropped under backpressure. Up to 500 channels per connection.132        </p>133        <h2>Server-Sent Events</h2>134        <pre>135          <code>{`curl -N "${base}/v1/sse?channels=quotes:BTC-USD,events:*"136137event: hello138data: {"version":1,"channels":["quotes:crypto_btc_usd","events:*"],"ts":…}139140event: batch141id: 58142data: {"type":"batch","seq":1,"ts":…,"messages":[{"type":"quote",…}]}`}</code>143        </pre>144        <h2>Identifiers</h2>145        <p>146          Stable public ids: <code>eq_us_xnas_aapl</code>, <code>etf_us_arcx_spy</code>, <code>index_us_spx</code>, <code>crypto_btc_usd</code>, <code>fx_eur_usd</code>, <code>rate_us_us10y</code>, <code>cmd_xcme_gc_f</code>. Endpoints accepting <code>{"{id}"}</code> also accept a bare symbol (<code>AAPL</code>, <code>BTC-USD</code>) or <code>VENUE:SYMBOL</code>.147        </p>148        <h2>Attribution & terms</h2>149        <p>150          Data carries the rights status of its sources; see <Link href="/licensing">data rights</Link>. Cboe values are 15-minute delayed and must be displayed as such; venue and official-source attributions must be preserved when redistributing. Market Atlas is an informational platform, not investment advice.151        </p>152      </div>153    </Page>154  );155}156