Files
market_screener/ui/README.md
T
2026-06-04 01:36:28 -04:00

115 lines
3.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Market Screener UI
SvelteKit 5 dashboard for the [Market Screener](../market_screener) API. Provides an interactive interface for screening stocks, ETFs, and bonds — and tracking your portfolio with live hold/sell/add advice.
---
## Quick Start
This UI requires the Market Screener API running on port 3000.
```bash
# Recommended: start both from the API repo
cd ../market_screener
npm run dev # starts API (:3000) + this UI (:5173) together
# Or start the UI independently
npm install
npm run dev # http://localhost:5173
```
---
## Pages
### Screener (`/`)
- Enter any tickers (comma or space separated) and click **Screen**
- Click **📰 Catalysts** to load today's news-driven tickers and screen them automatically (one click)
- Market context strip shows live benchmarks: 10Y yield, VIX, S&P 500, P/E ratios, rate regime
- Signal Summary table ranks all assets by signal strength
- Drill-down tables for Stocks, ETFs, and Bonds with **Mkt-Adjusted** / **Graham** tab toggle
- Ticker column stays pinned while scrolling wide tables
### Portfolio (`/portfolio`)
- Reads `portfolio.json` from the API server
- Shows total value, cost basis, and unrealised G/L
- Per-holding advice: ✅ Hold & Add, 🟡 Reduce, 🔴 Sell
- If SimpleFIN is configured: net worth, account balances, 30-day spending breakdown
---
## Signals Explained
| Signal | Meaning |
|---|---|
| ✅ Strong Buy | Passes both Market-Adjusted AND Fundamental gates |
| ⚡ Momentum | Passes market-adjusted, holds fundamentally |
| ⚠️ Speculation | Passes market-adjusted, fails fundamental — priced for perfection |
| 🔄 Neutral | Hold territory in one or both lenses |
| ❌ Avoid | Fails both gates |
The **Mkt-Adjusted** tab uses gates derived from live market data (e.g. S&P P/E × 1.5 for the P/E gate). The **Graham** tab uses strict historical value-investing gates (P/E < 15×, PEG < 1.0).
---
## Tech Stack
| Layer | Choice |
|---|---|
| Framework | SvelteKit 2 + Svelte 5 |
| Build tool | Vite 6 |
| Adapter | `@sveltejs/adapter-auto` |
| Rendering | Client-side only (SSR disabled) |
| API | Proxied via Vite dev server → Fastify on :3000 |
---
## Project Structure
```
src/
app.html HTML shell
app.css Global reset + dark theme base
routes/
+layout.js ssr = false
+layout.svelte Nav bar
+page.svelte Screener page
portfolio/
+page.js load() → fetches /api/finance/portfolio
+page.svelte Portfolio + SimpleFIN page
lib/
api.js All API fetch functions
SignalBadge.svelte Signal pill component
MarketContext.svelte Benchmark strip component
vite.config.js /api proxy → localhost:3000
svelte.config.js SvelteKit config
```
---
## Configuration
### API URL
In `vite.config.js`, the Vite dev server proxies `/api/*` to `http://localhost:3000`. To point at a different API host, update the `proxy` target there.
For production, configure your reverse proxy (nginx, Caddy, etc.) to route `/api/*` to the Fastify server.
### CORS
The Fastify API allows `http://localhost:5173` by default. If you deploy the UI to a different origin, set `CLIENT_ORIGIN` in the API's `.env`:
```
CLIENT_ORIGIN=https://your-deployed-ui.example.com
```
---
## Development Notes
- Uses Svelte 5 runes: `$state`, `$derived`, `$derived.by`, `$props`
- `onclick={handler}` not `on:click` — Svelte 5 syntax
- Page data loaded via `+page.js` `load()` function, not `onMount`
- Global CSS lives in `src/app.css` — no `:global()` in component `<style>` blocks
- `asset.displayMetrics` (plain object from API) — never call `getDisplayMetrics()` in the browser