8429db504a
- 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
53 lines
1.7 KiB
TypeScript
53 lines
1.7 KiB
TypeScript
import { useState, useEffect } from "react";
|
|
|
|
export default function AlpacaAccountInfo() {
|
|
const [account, setAccount] = useState<{
|
|
cash: number;
|
|
buying_power: number;
|
|
portfolio_value: number;
|
|
} | null>(null);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
const fetchAccount = async () => {
|
|
try {
|
|
const res = await fetch("/api/alpaca/account");
|
|
if (!res.ok) throw new Error("API error");
|
|
const data = await res.json();
|
|
setAccount(data);
|
|
} catch {
|
|
setError("Failed to load account info.");
|
|
}
|
|
};
|
|
fetchAccount();
|
|
}, []);
|
|
|
|
if (error) return <p className="text-red-600">{error}</p>;
|
|
if (!account) return <p className="text-gray-500">Loading account…</p>;
|
|
|
|
return (
|
|
<div className="bg-white border rounded-lg p-4 shadow-sm">
|
|
<h2 className="text-lg font-semibold mb-2">Alpaca Account</h2>
|
|
<dl className="space-y-1 text-sm">
|
|
<div className="flex justify-between">
|
|
<dt className="text-gray-600">Cash</dt>
|
|
<dd className="font-mono">
|
|
${account.cash.toLocaleString(undefined, { minimumFractionDigits: 2 })}
|
|
</dd>
|
|
</div>
|
|
<div className="flex justify-between">
|
|
<dt className="text-gray-600">Buying Power</dt>
|
|
<dd className="font-mono">
|
|
${account.buying_power.toLocaleString(undefined, { minimumFractionDigits: 2 })}
|
|
</dd>
|
|
</div>
|
|
<div className="flex justify-between">
|
|
<dt className="text-gray-600">Portfolio Value</dt>
|
|
<dd className="font-mono">
|
|
${account.portfolio_value.toLocaleString(undefined, { minimumFractionDigits: 2 })}
|
|
</dd>
|
|
</div>
|
|
</dl>
|
|
</div>
|
|
);
|
|
} |