Jimin Huang
Change settings
84b00d4
raw
history blame
2.28 kB
// src/lib/prices.ts
type PriceMap = Record<string, number>
// Map your asset code -> provider + symbol
const MAP: Record<string, { p: 'binance'|'stooq'; s: string }> = {
// crypto (USDT pairs)
BTC: { p: 'binance', s: 'BTCUSDT' },
ETH: { p: 'binance', s: 'ETHUSDT' },
SOL: { p: 'binance', s: 'SOLUSDT' },
BNB: { p: 'binance', s: 'BNBUSDT' },
DOGE:{ p: 'binance', s: 'DOGEUSDT' },
XRP: { p: 'binance', s: 'XRPUSDT' },
// equities (stooq wants .us)
AAPL:{ p: 'stooq', s: 'aapl.us' },
MSFT:{ p: 'stooq', s: 'msft.us' },
BMRN:{ p: 'stooq', s: 'bmrn.us' },
MRNA:{ p: 'stooq', s: 'mrna.us' },
TSLA:{ p: 'stooq', s: 'tsla.us' },
};
// --- simple cache + pub/sub
let latest: PriceMap = {};
const subs = new Set<(m: PriceMap)=>void>();
const push = () => subs.forEach(fn => fn({ ...latest }));
export function subscribePrices(fn: (m: PriceMap)=>void) {
subs.add(fn); fn({ ...latest });
return () => subs.delete(fn);
}
async function fetchBinance(symbol: string) {
const r = await fetch(`https://api.binance.com/api/v3/ticker/price?symbol=${encodeURIComponent(symbol)}`);
const j = await r.json(); const n = Number(j?.price);
return Number.isFinite(n) ? n : undefined;
}
async function fetchStooq(symbol: string) {
const url = `https://stooq.com/q/l/?s=${encodeURIComponent(symbol)}&f=sd2t2ohlcv&h&e=csv`;
const r = await fetch(url);
const txt = await r.text(); // first line is header; second line has data, column 'Close'
const line = txt.split('\n')[1] || '';
const cols = line.split(','); // Symbol,Date,Time,Open,High,Low,Close,Volume
const n = Number(cols[6]);
return Number.isFinite(n) ? n : undefined;
}
export async function pollPrices(codes: string[], intervalMs = 30000) {
const uniq = [...new Set(codes)].filter(c => MAP[c]);
async function tick() {
await Promise.all(uniq.map(async code => {
const { p, s } = MAP[code];
const px = p === 'binance' ? await fetchBinance(s) : await fetchStooq(s);
if (px !== undefined) latest[code] = px;
}));
push();
}
await tick();
setInterval(tick, intervalMs);
}
export const fmtUSD = (n?: number) =>
typeof n === 'number'
? n.toLocaleString(undefined, { style: 'currency', currency: 'USD', maximumFractionDigits: 2 })
: 'β€”';