( symbol: string, fetchImpl: typeof fetch, )
| 34 | } |
| 35 | |
| 36 | async function fetchSeries( |
| 37 | symbol: string, |
| 38 | fetchImpl: typeof fetch, |
| 39 | ): Promise<Series[]> { |
| 40 | const url = `${BASE}/v8/finance/chart/${encodeURIComponent(normalizeSymbol(symbol))}?range=2y&interval=1d`; |
| 41 | const res = await fetchImpl(url, { headers: { "User-Agent": UA } }); |
| 42 | if (!res.ok) return []; |
| 43 | const json = (await res.json()) as { |
| 44 | chart?: { result?: Array<{ timestamp?: number[]; indicators?: { quote?: Array<{ close?: Array<number | null> }> } }> }; |
| 45 | }; |
| 46 | const r = json.chart?.result?.[0]; |
| 47 | if (!r) return []; |
| 48 | const ts = r.timestamp ?? []; |
| 49 | const closes = r.indicators?.quote?.[0]?.close ?? []; |
| 50 | const out: Series[] = []; |
| 51 | for (let i = 0; i < ts.length; i++) { |
| 52 | const c = closes[i]; |
| 53 | if (c == null) continue; |
| 54 | out.push({ date: new Date(ts[i]! * 1000).toISOString().slice(0, 10), close: c }); |
| 55 | } |
| 56 | return out; |
| 57 | } |
| 58 | |
| 59 | function closeOn(series: Series[], date: string): number | null { |
| 60 | // Nearest close at or before `date`. |
no test coverage detected