fix: consolidate 3 fetchBars calls into 1 per stock and add 500ms delay between sequential loads to avoid rate limiting

This commit is contained in:
2026-05-16 22:14:21 +02:00
parent 5e865b9c26
commit f8a3b7840f
2 changed files with 36 additions and 50 deletions
+17 -41
View File
@@ -2,46 +2,25 @@ import { type IndicatorData } from "../../types";
import { calculateSMA, calculateEMA, calculateRSI, calculateMACD, calculateBollingerBands, calculateATR, calculateVolumeAvg } from "../../utils/indicators";
import alpacaService from "../../lib/alpacaClient";
async function fetchHistoricPrices(symbol: string): Promise<number[]> {
try {
const bars = await alpacaService.fetchBars(symbol, "1Day", { limit: 60 });
return bars.map((b: any) => {
const c = b.ClosePrice ?? b.c ?? 0;
return typeof c === "number" ? c : 0;
}).filter((p: number) => p > 0);
} catch (e) {
console.error(`Failed to fetch bars for ${symbol}:`, e);
return [];
}
}
async function fetchBarsOnce(symbol: string): Promise<{ prices: number[]; volumes: number[]; highs: number[]; lows: number[] }> {
const bars = await alpacaService.fetchBars(symbol, "1Day", { limit: 60 });
const prices: number[] = [];
const volumes: number[] = [];
const highs: number[] = [];
const lows: number[] = [];
async function fetchVolumes(symbol: string): Promise<number[]> {
try {
const bars = await alpacaService.fetchBars(symbol, "1Day", { limit: 60 });
return bars.map((b: any) => {
const v = b.Volume ?? b.v ?? 0;
return typeof v === "number" ? v : 0;
}).filter((v: number) => v > 0);
} catch (e) {
return [];
for (const b of bars) {
const c = b.ClosePrice ?? b.c ?? 0;
const v = b.Volume ?? b.v ?? 0;
const h = b.HighPrice ?? b.h ?? 0;
const l = b.LowPrice ?? b.l ?? 0;
if (typeof c === "number" && c > 0) prices.push(c);
if (typeof v === "number" && v > 0) volumes.push(v);
if (typeof h === "number" && h > 0) highs.push(h);
if (typeof l === "number" && l > 0) lows.push(l);
}
}
async function fetchHighLow(symbol: string): Promise<{ highs: number[]; lows: number[] }> {
try {
const bars = await alpacaService.fetchBars(symbol, "1Day", { limit: 60 });
const highs: number[] = [];
const lows: number[] = [];
for (const b of bars) {
const h = b.HighPrice ?? b.h ?? 0;
const l = b.LowPrice ?? b.l ?? 0;
if (typeof h === "number" && h > 0) highs.push(h);
if (typeof l === "number" && l > 0) lows.push(l);
}
return { highs, lows };
} catch (e) {
return { highs: [], lows: [] };
}
return { prices, volumes, highs, lows };
}
export async function loader({ request }: { request: Request }) {
@@ -53,14 +32,11 @@ export async function loader({ request }: { request: Request }) {
}
try {
const prices = await fetchHistoricPrices(symbol.toUpperCase());
const { prices, volumes, highs, lows } = await fetchBarsOnce(symbol.toUpperCase());
if (prices.length < 26) {
return Response.json({ error: "Insufficient price data" }, { status: 404 });
}
const volumes = await fetchVolumes(symbol.toUpperCase());
const { highs, lows } = await fetchHighLow(symbol.toUpperCase());
const sma20 = calculateSMA(prices, 20);
const sma50 = prices.length >= 50 ? calculateSMA(prices, 50) : 0;
const ema12 = calculateEMA(prices, 12);