Investment Monitor

Selected Build ยท Finance & Automation

Investment Monitor

A local-only portfolio management system that combines deterministic screening, per-symbol LLM analysis, and a learning loop. It pulls live data from Schwab, screens the Russell 3000 across three risk profiles, produces a CIO-style daily action plan, and mirrors every decision through Alpaca paper trading before any real capital is at risk.

Python 3.12 Flask + SQLAlchemy Schwab API Alpaca paper trading OpenAI + Claude MCP SEC EDGAR
~3,000
Russell 3000 names screened daily
3
Risk profiles run in parallel
3ร—/weekday
Scheduled runs + a Saturday deep run
500k
Token budget cap per run

๐Ÿ“‹ What it does

Investment Monitor runs unattended on a single mini PC, reachable over Tailscale. A scheduled task fires the pipeline three times each weekday โ€” the first run does the heavy LLM work, later runs refresh the deterministic data โ€” plus a Saturday run that backfills five years of history and forces a full LLM pass. A Flask dashboard surfaces the latest CIO plan, holdings analysis, screener results, and learning-loop metrics.

Design stance: Local-only by design โ€” no cloud deployment. Real execution is gated behind a manual config flag (EXECUTION_ENABLED=false by default), so the paper-trading sandbox is the testbed for new strategies before any real-money rollout.

๐Ÿ—๏ธ Daily pipeline

The whole run is implemented end-to-end in one orchestrator (src/orchestration/daily_run.py), read top to bottom. The deterministic screener and action engine always cover the full portfolio; the LLM stages (amber) operate only on a bounded candidate set capped at 90 symbols.

flowchart TD
    A[Schwab snapshot
+ tax-lot sync] --> B[Resolve universe
Russell 3000 + movers + watchlist] B --> C[Shared data fetch
quotes / fundamentals / prices] I[SEC EDGAR Form 4
insider-buying signal] --> D C --> D[Screener x3 profiles
conservative / neutral / aggressive] C --> E[200-week MA screener] D --> F[Performance metrics] E --> F F --> G[Action engine x3
+ LLM explainer] G --> H[Candidate set builder
cap 90 symbols] H --> L{{LLM Analyst
per-symbol BUY/HOLD/SELL}} L --> M{{CIO Synthesizer
unified action plan}} M --> O{{Red-team critique}} O --> P[Decision ledger
+ outcome scoring] H --> S[Strategy engines
TLH ยท collars ยท rotation
duration ยท dividend ยท quality-mom] S --> P P --> R[Email digest] R --> V[Paper trading
Alpaca] classDef llm fill:#fef3c7,stroke:#d97706,color:#000 class L,M,O llm

Deterministic stages cover the full portfolio; amber LLM stages run on the bounded candidate set.

โ˜๏ธ Stack & components

๐Ÿ Python + Flask

Python 3.12, Flask 3.1 dashboard with 90+ routes and 40 templates surfacing the latest run.

๐Ÿ—„๏ธ SQLAlchemy + SQLite

SQLAlchemy 2.0 ORM over a 49-table SQLite database. All persistence flows through one DataStore layer.

๐Ÿฆ Schwab API

OAuth client for live quotes, fundamentals, and price history โ€” the source of truth for holdings and the universe.

๐Ÿ“Š Alpaca paper trading

Every CIO recommendation is executed in a sandbox and tracked against forward returns to feed the learning loop.

๐Ÿค– Unified LLM layer

A provider router pins each stage to OpenAI gpt-4.1-mini (high-volume) or Claude via claude-cli (deep analysis).

๐Ÿ”Ž Brave Search

Research signals feed the agents that screen and contextualise candidates.

๐Ÿ”Œ MCP server

A read-only MCP server (MCP 1.14) exposes the system's data as tools for Claude to query directly.

๐Ÿงฉ Strategy framework

Six pluggable sleeve strategies โ€” tax-loss harvesting, dividend capture, options collars, sector rotation, duration, quality-momentum โ€” registered from strategies.yaml behind one Strategy base class.

๐Ÿ›๏ธ SEC EDGAR Form 4

An insider open-market-purchase counter (transaction code P) over a 90-day window, wired in as an opt-in screening factor and refreshed weekly.

โฐ Windows Task Scheduler

Fires the pipeline three times per weekday plus a Saturday deep-analysis run and a weekly insider-cache backfill.

๐Ÿง  How the LLM work is routed

A single STAGE_ROUTING table is the source of truth for which stage hits which provider. High-volume per-symbol and aggregate work โ€” analyst, CIO, explainer, narrator, macro, tax โ€” is pinned to OpenAI gpt-4.1-mini for cost and speed. The deeper red-team critique routes to Claude via the claude-cli at zero marginal cost.

Cost control: A token-budget circuit breaker caps each daily run at 500k tokens across all LLM stages, and a 2-hour cooldown skips re-running the expensive analyst + narrator on intraday re-runs unless explicitly forced. Every call is traced into an llm_traces table โ€” model, tokens, latency, stage โ€” which the learning loop reads from.

๐Ÿ”„ End-to-end run

Snapshot & universe

Pull a fresh Schwab snapshot, sync tax lots, then resolve the day's universe: Russell 3000 plus market movers and the personal watchlist.

Screen across three profiles

A shared data fetch feeds three parallel screeners (conservative / neutral / aggressive) using a 15-factor model โ€” including an opt-in SEC EDGAR insider-buying signal โ€” alongside a once-daily 200-week moving-average screen.

Deterministic actions

The action engine turns scores into BUY/HOLD/SELL calls per profile and an LLM explainer attaches a plain-English rationale to each.

Build the candidate set

Holdings, today's actions, screen hits, 200-week retests, and pinned names are merged into a bounded candidate set (capped at 90 symbols) โ€” the only thing the expensive LLM stages see.

Analyst โ†’ CIO โ†’ red team

A per-symbol LLM analyst issues BUY/HOLD/SELL with conviction; a CIO synthesizer ranks them into one unified plan plus a watchlist; a red-team pass critiques the plan before it ships.

Run the strategy sleeves

Six registered sleeve strategies โ€” tax-loss harvesting, dividend capture, options collars, sector rotation, duration, and quality-momentum โ€” evaluate the portfolio and surface their signals into the plan for attribution.

Ledger, digest & paper trade

Decisions are written to a ledger with outcome scoring, a digest email goes out, and the approved plan is mirrored as Alpaca paper trades whose forward returns feed the learning loop.

๐Ÿ’ก What it demonstrates