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%
3.4 KB · 74 lines typescript
Raw Blame History
1import { defineConnector, raw, type NormalizedBatch } from "@market-atlas/connector-sdk";2import { parseTimestamp } from "@market-atlas/market-model";3import { MAJOR_BASES, cryptoSeeds } from "../_shared/crypto.js";4import { pairObservations } from "../_shared/pairs.js";56const CRYPTO_PAIRS: Array<[string, string]> = MAJOR_BASES.filter((b) => b !== "PAXG").map((b) => [b, "USDT"] as [string, string]).concat([["BNB", "USDT"], ["TRX", "USDT"], ["PAXG", "USDT"]]);7/** Fiat/stablecoin markets → live FX proxies (USDT ≈ USD), labelled STABLECOIN_PROXY. */8const FX_PROXY_PAIRS: Array<[string, string]> = [["EUR", "USDT"], ["USDT", "BRL"], ["USDT", "MXN"], ["USDT", "TRY"], ["USDT", "ZAR"], ["USDT", "ARS"]];9const PAIRS = [...CRYPTO_PAIRS, ...FX_PROXY_PAIRS];10const SYMBOLS = PAIRS.map(([b, q]) => `${b}${q}`);11const streamUrl = (symbols: string[]) => `wss://stream.binance.com:9443/stream?streams=${symbols.map((s) => `${s.toLowerCase()}@miniTicker`).join("/")}`;1213/** Binance combined stream, `<symbol>@miniTicker` (1 s cadence, exchange event time). USDT-quoted pairs. */14export const binanceWs = defineConnector({15  metadata: {16    id: "binance-ws",17    name: "Binance — miniTicker combined stream",18    version: "1.0.0",19    sourceId: "binance",20    organization: "Binance",21    sourceType: "WEBSOCKET",22    jurisdiction: null,23    rightsStatus: "PUBLIC_ATTRIBUTED",24    realtimeStatus: "REALTIME",25    expectedLatencyMs: 1000,26    supportsStreaming: true,27    supportsHistorical: false,28    assetClasses: ["CRYPTO", "FOREX"],29    exchanges: ["binance"],30    homepage: "https://developers.binance.com/docs/binance-spot-api-docs/web-socket-streams",31    description: "Public Binance spot combined WebSocket stream (miniTicker per symbol, pushed every second) for USDT-quoted majors. Exchange event time (E) is used as source timestamp.",32    rightsNotes: "Public market data displayed with attribution to Binance. Availability may vary by jurisdiction.",33    termsUrl: "https://www.binance.com/en/terms",34    sourceFamily: "binance",35    enabled: true,36  },37  seeds: cryptoSeeds(CRYPTO_PAIRS, "binance", (b, q) => `${b}${q}`),38  defaultSymbols: SYMBOLS,39  async start(ctx) {40    const ws = ctx.openWebSocket(streamUrl(ctx.watchedSymbols()), {41      label: "binance",42      staleAfterMs: 60_000,43      heartbeat: null, // Binance pings the client; ws library answers pongs automatically.44      onMessage: (data) => {45        let msg: any;46        try {47          msg = JSON.parse(data);48        } catch {49          return;50        }51        if (msg?.data?.e === "24hrMiniTicker") ctx.emit(raw("binance-ws", "binance", "miniTicker", msg.data));52      },53    });54    ws.connect();55  },56  normalize(r): NormalizedBatch {57    const m = r.payload as Record<string, unknown>;58    if (r.kind !== "miniTicker" || typeof m.s !== "string") return { observations: [] };59    const pair = PAIRS.find(([b, q]) => `${b}${q}` === m.s);60    const base = pair?.[0] ?? (m.s.endsWith("USDT") ? m.s.slice(0, -4) : null);61    const quote = pair?.[1] ?? (m.s.endsWith("USDT") ? "USDT" : null);62    if (!base || !quote) return { observations: [] };63    return {64      observations: pairObservations(m.s, base, quote, "binance", { last: m.c, open: m.o, high: m.h, low: m.l, volume: m.v }, {65        sourceTimestamp: parseTimestamp(m.E),66        timestampTrust: "EXCHANGE",67        rightsStatus: "PUBLIC_ATTRIBUTED",68        realtimeStatus: "REALTIME",69      }),70    };71  },72  fixturesDir: "fixtures",73});74