# Most Active Stocks Table Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Replace the StockViewer on `/stocks` with a table of most active stocks from Alpaca's screener API. **Architecture:** Server proxy route calls Alpaca screener, React component fetches and auto-refreshes every 30s with clickable rows linking to `/analyze/TICKER`. **Tech Stack:** React Router 7, React, TailwindCSS, fetch API, Alpaca Markets API --- ### Task 1: Add MostActiveStock type to types.ts **Files:** - Modify: `app/types.ts` - [ ] **Step 1: Add MostActiveStock interface** Add to `app/types.ts` after the `AlpacaAccount` interface: ```typescript export interface MostActiveStock { symbol: string; name: string; price: number; changePercent: number; volume: number; } ``` - [ ] **Step 2: Commit** ```bash git add app/types.ts git commit -m "types: add MostActiveStock interface" ``` --- ### Task 2: Create API route for most active stocks **Files:** - Create: `app/routes/api/stocks/most-actives.ts` - [ ] **Step 1: Create the server proxy route** Create `app/routes/api/stocks/most-actives.ts`: ```typescript import type { MostActiveStock } from "../../../types"; 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"; 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, })); 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 } ); } } ``` - [ ] **Step 2: Commit** ```bash git add app/routes/api/stocks/most-actives.ts git commit -m "feat: add most-actives API proxy route" ``` --- ### Task 3: Register the new API route **Files:** - Modify: `app/routes.ts` - [ ] **Step 1: Add route entry** Add this line to `app/routes.ts` after the existing `api/stocks` route (line 11): ```typescript route("api/stocks/most-actives", "routes/api/stocks/most-actives.ts"), ``` The routes array should look like: ```typescript export default [ index("routes/landing.tsx"), route("api/alpaca/account", "routes/api/alpaca/account.ts"), route("api/alpaca/quote/:ticker", "routes/api/alpaca/quote.ts"), route("api/alpaca/orders", "routes/api/alpaca/orders.ts"), route("api/alpaca/positions", "routes/api/alpaca/positions.ts"), route("api/indicators", "routes/api/indicators.ts"), route("api/analyze", "routes/api/analyze.ts"), route("api/stocks", "routes/api/stocks/index.ts"), route("api/stocks/most-actives", "routes/api/stocks/most-actives.ts"), route("stocks", "routes/stocks.tsx"), route("analyze", "routes/analyze.tsx"), route("analyze/:ticker", "routes/analyze.ticker.tsx"), ] satisfies RouteConfig; ``` - [ ] **Step 2: Commit** ```bash git add app/routes.ts git commit -m "routes: register most-actives API endpoint" ``` --- ### Task 4: Create MostActiveStocks component **Files:** - Create: `app/components/MostActiveStocks.tsx` - [ ] **Step 1: Create the component** Create `app/components/MostActiveStocks.tsx`: ```typescript import { useState, useEffect, useCallback } from "react"; import { Link } from "react-router"; import type { MostActiveStock } from "../types"; function formatVolume(vol: number): string { if (vol >= 1_000_000_000) return `${(vol / 1_000_000_000).toFixed(1)}B`; if (vol >= 1_000_000) return `${(vol / 1_000_000).toFixed(1)}M`; if (vol >= 1_000) return `${(vol / 1_000).toFixed(1)}K`; return vol.toString(); } function formatPrice(price: number): string { return `$${price.toFixed(2)}`; } function formatChangePercent(pct: number): string { return `${pct >= 0 ? "+" : ""}${pct.toFixed(2)}%`; } export default function MostActiveStocks() { const [stocks, setStocks] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const fetchData = useCallback(async () => { try { setError(null); const res = await fetch("/api/stocks/most-actives"); if (!res.ok) { const data = await res.json(); throw new Error(data.error || "Failed to fetch data"); } const data = await res.json(); setStocks(data); } catch (err) { const message = err instanceof Error ? err.message : "Failed to fetch most active stocks."; setError(message); } finally { setLoading(false); } }, []); useEffect(() => { fetchData(); const interval = setInterval(fetchData, 30000); return () => clearInterval(interval); }, [fetchData]); if (loading) { return (
{Array.from({ length: 8 }).map((_, i) => (
))}
); } if (error && stocks.length === 0) { return (

{error}

); } return (
{error && (

{error}

)}
{stocks.map((stock) => ( ))}
Symbol Name Price Change % Volume
{stock.symbol} {stock.name} {formatPrice(stock.price)} = 0 ? "text-green-600" : "text-red-600"}`}> {formatChangePercent(stock.changePercent)} {formatVolume(stock.volume)}
); } ``` - [ ] **Step 2: Commit** ```bash git add app/components/MostActiveStocks.tsx git commit -m "feat: add MostActiveStocks table component with auto-refresh" ``` --- ### Task 5: Update stocks.tsx page **Files:** - Modify: `app/routes/stocks.tsx` - [ ] **Step 1: Replace StockViewer with MostActiveStocks** Replace the entire contents of `app/routes/stocks.tsx`: ```typescript import MostActiveStocks from "../components/MostActiveStocks"; import Navbar from "../components/Navbar"; export default function Stocks() { return (

Most Active Stocks

Real-time view of the most actively traded stocks, auto-refreshing every 30 seconds.

); } ``` - [ ] **Step 2: Commit** ```bash git add app/routes/stocks.tsx git commit -m "feat: replace StockViewer with MostActiveStocks on stocks page" ``` --- ### Task 6: Verify and test **Files:** - All modified files - [ ] **Step 1: Run typecheck** ```bash npm run typecheck ``` Expected: No type errors. If there are errors, fix them before proceeding. - [ ] **Step 2: Run dev server and verify** ```bash npm run dev ``` Navigate to `http://localhost:5173/stocks` and verify: - Table loads with most active stocks - Symbol links navigate to `/analyze/TICKER` - Change % is color-coded (green for positive, red for negative) - Data auto-refreshes every 30 seconds - Loading skeleton shows on initial load - Error state shows with retry button if API fails - [ ] **Step 3: Final commit (if any fixes needed)** ```bash git add -A git commit -m "fix: address typecheck/dev issues" ```