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%
2.4 KB · 73 lines typescript
Raw Blame History
1import type { AssetClass, InstrumentHint } from "./index.js";23const slug = (s: string) =>4  s5    .toLowerCase()6    .normalize("NFKD")7    .replace(/[̀-ͯ]/g, "")8    .replace(/[^a-z0-9]+/g, "_")9    .replace(/^_+|_+$/g, "");1011/**12 * Canonical symbol form used inside instrument ids and for alias matching.13 * "BRK.B", "BRK-B", "BRK/B", "BRK B" → "brk_b".14 */15export function canonicalSymbol(symbol: string): string {16  return slug(symbol.trim());17}1819/** Deterministic stable ids; never database sequences. */20export function makeInstrumentId(assetClass: AssetClass, hint: { symbol: string } & Partial<InstrumentHint>): string {21  const sym = canonicalSymbol(hint.symbol);22  switch (assetClass) {23    case "CRYPTO":24      return `crypto_${slug(hint.base ?? sym)}_${slug(hint.quote ?? "usd")}`;25    case "FOREX":26      return `fx_${slug(hint.base ?? sym.slice(0, 3))}_${slug(hint.quote ?? sym.slice(3, 6))}`;27    case "INDEX":28      return `index_${slug(hint.country ?? "xx")}_${sym.replace(/^[_^.]+/, "")}`;29    case "TREASURY":30    case "INTEREST_RATE":31    case "BOND":32      return `rate_${slug(hint.country ?? "xx")}_${sym}`;33    case "COMMODITY":34    case "FUTURE":35      return `${assetClass === "FUTURE" ? "fut" : "cmd"}_${slug(hint.exchangeId ?? "xx")}_${sym}`;36    case "ETF":37    case "ETN":38    case "REIT":39    case "ADR":40    case "GDR":41    case "EQUITY":42    default: {43      const prefix =44        assetClass === "ETF" || assetClass === "ETN"45          ? "etf"46          : assetClass === "MUTUAL_FUND"47            ? "fund"48            : assetClass === "OPTION"49              ? "opt"50              : "eq";51      const venue = slug(hint.mic ?? hint.exchangeId ?? "xxxx");52      return `${prefix}_${slug(hint.country ?? "xx")}_${venue}_${sym}`;53    }54  }55}5657export function makeCompanyId(name: string): string {58  return slug(name).replace(/_/g, "-").slice(0, 80);59}6061export function makeEventId(ts: number, fingerprint: string): string {62  return `evt_${ts.toString(36)}_${fingerprint.slice(0, 12)}`;63}6465/** Split "BTC-USD" / "BTC/USD" / "BTCUSD" (6 letters) into base and quote. */66export function splitPair(symbol: string): { base: string; quote: string } | null {67  const m = symbol.toUpperCase().match(/^([A-Z0-9]{2,10})[-_/]([A-Z0-9]{2,6})$/);68  if (m) return { base: m[1]!, quote: m[2]!, };69  const compact = symbol.toUpperCase();70  if (/^[A-Z]{6}$/.test(compact)) return { base: compact.slice(0, 3), quote: compact.slice(3) };71  return null;72}73