Files
AITrader/docs/superpowers/plans/2026-05-14-stock-detail-page.md
henry 2e22fd5635 feat: add stock detail page with chart, position, and orders
- Add /api/alpaca/orders endpoint for order history
- Add TradingView chart component for candlestick visualization
- Add /analyze/:ticker route with position and orders display
- Make ticker cells in analyze page clickable for navigation
2026-05-14 11:00:35 +02:00

7.3 KiB

Stock Detail Page 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: Create stock detail page at /analyze/:ticker with TradingView chart, position, orders, and trading graph results.

Architecture: Dynamic route analyze.ticker.tsx that fetches ticker data, runs TradingGraph analysis, and displays chart, position, orders, and results.

Tech Stack: React Router 7, TradingView lightweight charts, Alpaca API, Prisma


Prerequisite Check

  • Verify Alpaca API key is configured in .env
  • Verify @tradingview/lightweight-charts can be installed

Task 1: Add Alpaca Orders API Endpoint

Files:

  • Create: app/routes/api/alpaca/orders.ts

  • Step 1: Write the failing test

// tests/orders.test.ts
import { test, expect } from "@playwright/test";

test("GET /api/alpaca/orders returns orders list", async ({ page }) => {
  const res = await page.request.get("/api/alpaca/orders");
  expect(res.ok()).toBeTruthy();
  const data = await res.json();
  expect(data.orders).toBeDefined();
});
  • Step 2: Run test to verify it fails Run: npm run test:e2e Expected: 404 Not Found

  • Step 3: Write minimal implementation

import Alpaca from "@alpacahq/alpaca-trade-api";

const alpaca = new Alpaca({
  keyId: process.env.ALPACA_API_KEY!,
  secretKey: process.env.ALPACA_SECRET_KEY!,
  baseUrl: process.env.ALPACA_BASE_URL || "https://paper-api.alpaca.markets",
  retryOnError: false,
});

export async function loader() {
  try {
    const orders = await alpaca.getOrders();
    return Response.json({ orders });
  } catch (error) {
    console.error("Alpaca orders error:", error);
    return Response.json({ orders: [] }, { status: 500 });
  }
}
  • Step 4: Register route in routes.ts
route("api/alpaca/orders", "routes/api/alpaca/orders.ts"),
  • Step 5: Run test to verify it passes Run: npm run test:e2e -- tests/orders.test.ts Expected: PASS

  • Step 6: Commit

git add app/routes/api/alpaca/orders.ts tests/orders.test.ts
git commit -m "feat: add alpaca orders API endpoint"

Task 2: Install TradingView Lightweight Charts

Files:

  • None (npm install)

  • Step 1: Install dependency

npm install @tradingview/lightweight-charts
  • Step 2: Run typecheck to verify installation Run: npx tsc --noEmit Expected: No errors

  • Step 3: Commit

git add package.json package-lock.json
git commit -m "feat: install tradingview lightweight charts"

Task 3: Create TradingView Chart Component

Files:

  • Create: app/components/TradingViewChart.tsx

  • Step 1: Write the component

import { useEffect, useRef } from "react";
import * as LightweightCharts from "@tradingview/lightweight-charts";

interface TradingViewChartProps {
  ticker: string;
  data?: Array<{ time: string; open: number; high: number; low: number; close: number }>;
}

export default function TradingViewChart({ ticker, data }: TradingViewChartProps) {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!containerRef.current) return;

    const chart = LightweightCharts.createChart(containerRef.current, {
      width: containerRef.current.clientWidth,
      height: 400,
    });

    const candlestickSeries = chart.addCandlestickSeries();
    
    if (data && data.length > 0) {
      candlestickSeries.setData(data);
    }

    return () => chart.remove();
  }, [data]);

  return (
    <div className="bg-white rounded-xl shadow-lg p-4">
      <h3 className="text-lg font-bold mb-3">{ticker} Price Chart</h3>
      <div ref={containerRef} />
    </div>
  );
}
  • Step 2: Run typecheck Run: npm run typecheck Expected: PASS

  • Step 3: Commit

git add app/components/TradingViewChart.tsx
git commit -m "feat: add tradingview chart component"

Task 4: Create Stock Detail Route

Files:

  • Create: app/routes/analyze.ticker.tsx

  • Modify: app/routes.ts

  • Step 1: Create the route file

import { db } from "../lib/db.server";
import TradingViewChart from "../components/TradingViewChart";
import type { TradingDecision } from "../types/agents";

export const meta = () => [{ title: "Stock Detail - AITrader" }];

interface LoaderData {
  ticker: string;
  position: number | null;
  orders: any[];
  analysis: TradingDecision | null;
}

export async function loader({ params }: { params: { ticker: string } }) {
  const ticker = params.ticker?.toUpperCase() || "";
  
  // Fetch position
  const posRes = await fetch(`${process.env.BASE_URL}/api/alpaca/positions`);
  const positions = posRes.ok ? await posRes.json() : [];
  const position = positions.find((p: any) => p.ticker === ticker)?.qty ?? null;

  // Fetch orders
  const ordRes = await fetch(`${process.env.BASE_URL}/api/alpaca/orders`);
  const ordersData = ordRes.ok ? await ordRes.json() : { orders: [] };
  const orders = ordersData.orders?.filter((o: any) => o.symbol === ticker) || [];

  return Response.json({ ticker, position, orders });
}

export default function StockDetail() {
  const { ticker, position, orders } = useLoaderData() as LoaderData;

  return (
    <div className="min-h-screen bg-gradient-to-br from-gray-50 to-blue-50">
      <Navbar />
      <div className="mx-auto max-w-7xl px-6 py-8">
        <h1 className="text-3xl font-bold text-gray-900 mb-6">{ticker} Detail</h1>
        
        <TradingViewChart ticker={ticker} />
        
        <div className="mt-6">
          <h2>Position</h2>
          <p>{position ? `Qty: ${position}` : "No position"}</p>
        </div>
        
        <div className="mt-6">
          <h2>Recent Orders</h2>
          {orders.length === 0 ? <p>No orders</p> : <pre>{JSON.stringify(orders, null, 2)}</pre>}
        </div>
      </div>
    </div>
  );
}
  • Step 2: Register route in routes.ts
route("analyze/:ticker", "routes/analyze.ticker.tsx"),
  • Step 3: Run typecheck and test Run: npm run typecheck && npm run test:e2e Expected: All pass

  • Step 4: Commit

git add app/routes/analyze.ticker.tsx app/routes.ts
git commit -m "feat: add stock detail route"

Task 5: Add Navigation from Analyze Page

Files:

  • Modify: app/routes/analyze.tsx

  • Step 1: Make ticker clickable

// Change from:
<td className="py-3 px-4 font-bold text-gray-900">{stock.ticker}</td>

// To:
<td className="py-3 px-4 font-bold text-gray-900">
  <Link to={`/analyze/${stock.ticker}`} className="text-blue-600 hover:underline">
    {stock.ticker}
  </Link>
</td>
  • Step 2: Add Link import
import { Link } from "react-router";
  • Step 3: Run tests Run: npm run test:e2e Expected: All pass

  • Step 4: Commit

git add app/routes/analyze.tsx
git commit -m "feat: add navigation to stock detail page"

Task 6: Final Verification

Files:

  • Check: package.json, tsconfig.json

  • Step 1: Run complete test suite

npm run typecheck
npm run test:e2e -- --reporter=line

Expected: All 8+ tests pass

  • Step 2: Commit
git commit -am "chore: verify stock detail implementation"