feat: add stock indicators route and Alpaca account info

- New /stocks route with StockViewer component
- New /api/indicators endpoint with SMA, EMA, RSI, MACD
- New /api/alpaca/account endpoint
- AlpacaAccountInfo component on home page
- Indicator calculation utilities
- Tests for utilities and components
- Vite proxy config for /api
This commit is contained in:
2026-05-12 21:07:18 +02:00
parent aaafe8fa3f
commit 8429db504a
18 changed files with 2811 additions and 6 deletions
+54
View File
@@ -0,0 +1,54 @@
import { type IndicatorData } from "../../types";
import {
calculateSMA,
calculateEMA,
calculateRSI,
calculateMACD,
} from "../../utils/indicators";
// Replace with actual Alpaca API call
async function fetchHistoricPrices(symbol: string): Promise<number[]> {
return [
150.0, 152.3, 151.8, 153.5, 155.0, 154.2, 156.7, 158.1, 157.5, 159.0,
160.2, 158.9, 161.5, 163.0, 162.5, 164.8, 166.3, 165.0, 167.5, 169.0,
168.2, 170.5, 172.0, 171.5, 173.2,
];
}
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 === 0) {
return Response.json(
{ error: "No price data found" },
{ status: 404 }
);
}
const sma = calculateSMA(prices);
const ema = calculateEMA(prices);
const rsi = calculateRSI(prices);
const macd = calculateMACD(prices);
const data: IndicatorData = {
symbol: symbol.toUpperCase(),
indicators: { sma, ema, rsi, macd },
};
return Response.json(data);
} catch (error) {
return Response.json(
{ error: "Failed to fetch indicators" },
{ status: 500 }
);
}
}