17c9ee27c0
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
62 lines
1.9 KiB
TypeScript
62 lines
1.9 KiB
TypeScript
import type { MostActiveStock } from "../../../types";
|
|
import Alpaca from "@alpacahq/alpaca-trade-api";
|
|
|
|
const ALPACA_API_KEY = process.env.ALPACA_API_KEY!;
|
|
const ALPACA_SECRET_KEY = process.env.ALPACA_SECRET_KEY!;
|
|
const ALPACA_DATA_URL = process.env.ALPACA_DATA_URL || "https://data.alpaca.markets";
|
|
|
|
const alpaca = new Alpaca({
|
|
keyId: ALPACA_API_KEY,
|
|
secretKey: ALPACA_SECRET_KEY,
|
|
baseUrl: process.env.ALPACA_BASE_URL || "https://paper-api.alpaca.markets",
|
|
dataBaseUrl: ALPACA_DATA_URL,
|
|
retryOnError: false,
|
|
});
|
|
|
|
export async function loader() {
|
|
try {
|
|
const response = await fetch(`${ALPACA_DATA_URL}/v1beta1/screener/stocks/most-actives`, {
|
|
headers: {
|
|
"APCA-API-KEY-ID": ALPACA_API_KEY,
|
|
"APCA-API-SECRET-KEY": ALPACA_SECRET_KEY,
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Alpaca API error: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
const stocks: MostActiveStock[] = (data.most_actives || []).map((item: any) => ({
|
|
symbol: item.symbol,
|
|
name: item.name || item.symbol,
|
|
price: parseFloat(item.price) || 0,
|
|
changePercent: parseFloat(item.change_percent) || 0,
|
|
volume: parseInt(item.volume) || 0,
|
|
}));
|
|
|
|
// If Alpaca's screener returned a symbol as the name, try to fetch the canonical asset name
|
|
await Promise.all(stocks.map(async (s) => {
|
|
if (s.name === s.symbol) {
|
|
try {
|
|
const asset = await alpaca.getAsset(s.symbol);
|
|
if (asset && (asset as any).name) {
|
|
s.name = (asset as any).name;
|
|
}
|
|
} catch (err) {
|
|
// ignore and keep existing name
|
|
}
|
|
}
|
|
}));
|
|
|
|
return Response.json(stocks);
|
|
} catch (error) {
|
|
console.error("Most active stocks API error:", error);
|
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
return Response.json(
|
|
{ error: `Failed to fetch most active stocks: ${message}` },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|