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 { 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 fetchVolumes(symbol: string): Promise { 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 []; } } 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: [] }; } } export async function loader({ request }: { request: Request }) { const url = new URL(request.url); const symbol = url.searchParams.get("symbol"); if (!symbol) { return Response.json({ error: "Symbol is required" }, { status: 400 }); } try { const prices = await fetchHistoricPrices(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); const ema26 = calculateEMA(prices, 26); const rsi14 = calculateRSI(prices, 14); const macd = calculateMACD(prices); const bb = calculateBollingerBands(prices, 20); const atr = highs.length > 0 && lows.length > 0 ? calculateATR(highs, lows, prices, 14) : 0; const avgVol = volumes.length > 0 ? calculateVolumeAvg(volumes, 20) : 0; const data: IndicatorData = { symbol: symbol.toUpperCase(), indicators: { sma: sma20, sma50, ema12, ema26, rsi: rsi14, macd: macd.histogram, bbUpper: bb.upper, bbLower: bb.lower, bbMiddle: bb.middle, atr, avgVolume: avgVol, }, }; return Response.json(data); } catch (error) { console.error("Indicators error:", error); return Response.json({ error: "Failed to fetch indicators" }, { status: 500 }); } }