// Refreshes data/sp500.json with daily S&P 500 close prices from Yahoo Finance's // public chart endpoint (no API key required). Run with: node scripts/fetch-sp500.mjs import { writeFileSync } from "node:fs"; import { fileURLToPath } from "node:url"; import { dirname, join } from "node:path"; const __dirname = dirname(fileURLToPath(import.meta.url)); const OUT_PATH = join(__dirname, "..", "data", "sp500.json"); const URL = "https://query1.finance.yahoo.com/v8/finance/chart/%5EGSPC?range=10y&interval=1d"; const res = await fetch(URL, { headers: { "User-Agent": "Mozilla/5.0" } }); if (!res.ok) { throw new Error(`Yahoo Finance request failed: ${res.status} ${res.statusText}`); } const data = await res.json(); const result = data?.chart?.result?.[0]; if (!result) { throw new Error("Unexpected response shape from Yahoo Finance"); } const { timestamp } = result; const closes = result.indicators.quote[0].close; const series = []; for (let i = 0; i < timestamp.length; i++) { if (closes[i] == null) continue; const date = new Date(timestamp[i] * 1000).toISOString().slice(0, 10); series.push({ date, close: Number(closes[i].toFixed(2)) }); } writeFileSync(OUT_PATH, JSON.stringify({ source: "yahoo-finance:^GSPC", updatedAt: new Date().toISOString(), series }, null, 2)); console.log(`Wrote ${series.length} points to ${OUT_PATH}`);