Stock Demon Overview Strategy Portfolio Earnings Digest Health Architecture Private cockpit · Not investment advice

System Architecture

How Stock Demon collects data, generates intelligence, and monitors itself. A personal AI-infrastructure market analysis system built on Cloudflare Workers + D1.

External data source
Compute / workers
Storage
Dashboard pages
Monitoring
📡 Financial Modeling Prep
  • Company profiles (price, volume, beta, range)
  • Historical daily prices (5-year backfill)
  • Fundamentals, market cap, analyst estimates
  • Earnings dates & EPS/revenue estimates
  • Price target consensus
REST API · polled on schedule, not real-time
🔍 Web Search
  • Per-ticker news search
  • Classified against market expectations
  • Lean: bullish / bearish / neutral
  • Horizon: near-term / long-term
The core thesis: judge news vs expectations, not in absolute terms
🏗️ Universe
  • ~42 AI-infrastructure names
  • 7 layers: silicon → foundry → memory → networking → servers → cloud → power
  • Dynamic: add/remove via self-service flow
  • All pipelines read from companies table
Never hardcoded — universe-driven queries everywhere
▼ ▼ ▼
⚙️ Cloudflare Worker

Edge-deployed, runs whether or not the desktop is open.

  • Daily price pull → price_snapshots
  • Daily supplements → market cap, price targets, estimate + PT snapshots
  • Weekly fundamentals refresh
  • Pre-earnings radar scan
  • 5-year historical backfill engine
  • Add-symbol orchestrator (full pipeline)
  • SSR dashboard (all pages)
  • Earnings revisions → snapshot tables → compute deltas COMMODITY
Cron-triggered + on-demand HTTP routes
🤖 Cowork AI Agents

Scheduled tasks — run while the desktop app is open.

  • News scan — expectations-aware classification
  • Deterioration scan — flags drops, volume spikes, near-lows
  • Trade guidance — model portfolio rebalance (weekly)
  • Pre-earnings ping — alerts when held names report soon
  • Weekly digest — narrative market synthesis
  • Guidance classifier — post-earnings guidance direction UNPROVEN LIVE
  • Ops health report — daily self-check
Each writes a heartbeat to job_runs on completion
🧠 Analysis Engine

Offline analysis, runs locally against exported data.

  • Backtester — mechanical signals over 4.5yr history
  • Earnings-surprise study — miss/beat excess returns
  • Knowledge repo — extracted lessons + params
  • Results written back to D1
Point-in-time discipline: 60-day reporting lag, no look-ahead
▼ ▼ ▼
🗄️ Cloudflare D1 — SQLite at the edge

Single database, all components read/write. ~20 tables across four domains:

Market Data
  • companies (universe)
  • price_snapshots (daily prices)
  • fundamentals_annual
  • market_cap_history
  • analyst_history
  • price_targets
Intelligence
  • news (expectations-aware)
  • alerts (deterioration flags)
  • earnings_radar
  • earnings_surprises
  • analyst_estimate_snapshots (new)
  • price_target_snapshots (new)
  • earnings_revisions (new)
  • weekly_digests
Portfolio & Backtest
  • live_positions / live_actions
  • live_equity (thesis scorecard)
  • backtest_runs / equity / trades
  • kb_lessons / kb_params
Operations
  • job_runs (heartbeats)
  • add_symbol_status
▼ ▼ ▼
📊 Dashboard — Server-Side Rendered

Every page is rendered from a single D1 read of stored data. The only client-side fetch is the Overview's live-price cell, which polls /api/quotes (see July 2026 additions).

Overview
Regime indicator · alerts panel · inventory by layer · news lean · signal disagreements
Ticker /ticker/:sym
Price chart · fundamentals · news · alerts · surprise history · analyst targets
Strategy
Backtest equity curve · variant comparison · knowledge lessons
Portfolio
Model positions · action log · thesis scorecard (mech vs news vs surprise)
Earnings
Upcoming dates · positioning risk · surprise track record · post-earnings revisions
Digest
Weekly narrative synthesis · archive of prior weeks
Health
Job heartbeat board · 7-day grid · freshness cross-checks · alert detail
📅 Automated Schedule

All times Eastern. Worker crons fire regardless of desktop state; Cowork tasks require the app to be open.

JobRunsTime (ET)Writes to
Price pullMon–Fri5:30 PMprice_snapshots
Daily supplementsMon–Fri5:30 PMmarket_cap_history, price_targets, estimate + PT snapshots
Earnings radarMon–Fri7:00 AMearnings_radar
FundamentalsSunday10:00 AMfundamentals_annual, analyst_history
Market cap historySunday10:00 AMmarket_cap_history
News scanMon–Fri7:31 AMnews
Deterioration scanMon–Fri6:01 PMalerts
Trade guidanceMonday6:30 PMlive_positions, live_actions, live_equity
Pre-earnings pingMon–Fri7:15 AM
Weekly digestSunday5:10 PMweekly_digests
Ops health reportDaily7:07 AMjob_runs
🔄 Daily Data Flow
1
Morning (7 AM ET) — Cowork news scan searches the web for each ticker, classifies each headline's lean relative to market expectations (the core thesis), and writes to news. Earnings radar refreshes upcoming report dates.
2
Market close (5:30 PM ET) — Worker cron pulls closing prices from FMP for all active universe members, computes RVOL and 52-week range position, upserts price_snapshots. Supplements pull market cap and price targets.
R
Post-supplement (5:30 PM ET) — After snapshot tables are written, computeEarningsRevisions scans all prints in earnings_surprises, finds the nearest forward fiscal period with matching pre/post snapshots (post ≥ print + 3 days, same fiscal_date only), computes EPS/revenue/PT revision %, and upserts earnings_revisions. Idempotent — refines as better-bracketing snapshots arrive. COMMODITY
3
Post-close (6:01 PM ET) — Deterioration scan reads fresh prices, flags names meeting any of four conditions: ≥4% single-day drop, heavy-volume selling (RVOL ≥1.8 + down), near 52-week low (range_pos ≤0.12), or ≥8% drawdown from prior snapshot. Writes to alerts.
4
Monday evening (6:30 PM ET) — Trade guidance runs the model portfolio rebalance: scores each name mechanically (momentum + valuation + trend), applies separate news and surprise adjustments, logs every action with bull/bear cases. Runs after price pull + deterioration scan — rebalances on Monday's close with alerts in hand.
5
Sunday (5:10 PM ET) — Weekly digest synthesizes the week's movers, alerts, news, earnings, and portfolio actions into a narrative. Fundamentals refresh pulls annual financials and market cap history.
🆕 July 2026 Additions

Three subsystems added after the June revisions/guidance work.

🔀 Split back-adjustment

FMP writes the current post-split price into price_snapshots daily but never rewrites history, so a split leaves an N× discontinuity in the series.

  • applyRecentSplits() runs at the end of pullPrices, checks the FMP split calendar (14-day lookback), and back-adjusts every pre-split row (price ÷ ratio, volume × ratio)
  • Idempotent via the splits_applied table — each split is applied exactly once
  • /add-symbol seeds splits_applied for a new name's recent splits so its already-adjusted backfill isn't re-divided
  • Motivating case: KLAC 10:1 on 2026-06-12
🔴 Live "right now" prices

The board is otherwise a single D1 read of stored closes; the Live column adds intraday quotes.

  • /api/quotes route — market-state aware (REGULAR / PRE / AH / CLOSED)
  • Per-symbol FMP calls (Starter tier — no batch endpoint)
  • Cached via the Cloudflare Cache API; the FMP_API_KEY stays server-side
  • Overview polls it client-side and fills one live cell per ticker, alongside the stored Last Close column
🔁 Supplement retry

One flaky FMP call used to fail the whole daily supplement run.

  • pullDailySupplements now uses fmpGetRetry with per-call isolation
  • A transient failure on one ticker no longer aborts the batch
  • Any ticker that still fails after retries is named in the run log
🔍 Monitoring & Self-Healing
💓 Heartbeat System
  • Every job writes to job_runs on completion
  • Records: status, rows written, duration, detail
  • 7-day retention with auto-pruning
Expected Schedule
  • Each job has expected days + UTC deadline
  • MISSED = expected today, past deadline, no run
  • PENDING = expected today, within window
🔬 Freshness Cross-Check
  • Catches "ran but wrote nothing" — a real failure class
  • Heartbeat success + stale data = WARN
  • Checks: price_snapshots, fundamentals, news, market_cap
📋 Daily Ops Report
  • Runs 7:07 AM ET daily (even weekends)
  • Reads job_runs + freshness, posts terse verdict
  • Green = one line + metrics; exceptions get detail
⚖️ Honesty Layer

Every page carries methodology badges and caveats. The system distinguishes three tiers of confidence:

VALIDATED
Backtested over one 4.5-year path. Momentum signal carried it; single-path, not proven across regimes.
COMMODITY
Earnings-surprise avoid-misses signal. Regime-stable but any screener can compute it — no proprietary edge.
UNPROVEN · LIVE
News-vs-expectations thesis. No historical validation possible (look-ahead-impossible). On trial live with separately logged scores.
🛠️ Technology Stack
Runtime
Cloudflare Workers (edge V8 isolates)
Database
Cloudflare D1 (distributed SQLite)
Rendering
Server-side HTML, no framework
Charts
Chart.js (CDN)
AI Agents
Claude (Sonnet/Haiku, task-matched)
Data Source
Financial Modeling Prep API
Scheduling
Cron triggers (Worker) + desktop tasks (Cowork)
Domain
Custom domain via Cloudflare
🗺️ System Diagram
EXTERNAL DATA SOURCES COMPUTE LAYER STORAGE PRESENTATION MONITORING & OBSERVABILITY 📡 FMP API prices · fundamentals · earnings 🔍 Web Search news · expectations context 📈 Market Data profiles · targets · estimates ⚙️ Cloudflare Worker → Daily price cron (5:30pm ET) → Weekly fundamentals (Sun) → Earnings radar (7am) → Backfill engine · Add-symbol → SSR dashboard (all pages) 🤖 Cowork AI Agents → News scan (expectations-aware) → Deterioration scan → Trade guidance (weekly) → Pre-earnings ping → Weekly digest · Ops health 🧠 Analysis Engine → Mechanical backtester → Earnings-surprise study → Knowledge repo (lessons) → Signal extraction Offline · point-in-time · 60d lag 🗄️ Cloudflare D1 — SQLite at the Edge companies · price_snapshots · fundamentals · news · alerts · earnings_radar · live_positions · backtest_* · kb_* · weekly_digests · job_runs ~20 tables Overview regime · alerts · news Ticker deep dive per name Strategy backtest explorer Portfolio positions · scorecard Earnings radar · surprise Digest weekly synthesis Health ops · heartbeats 💓 Heartbeat System every job → job_runs on complete status · rows · duration · detail ⏰ Schedule Watchdog expected days + deadline per job OK · WARN · MISSED · PENDING 🔬 Freshness Cross-Check heartbeat OK + stale data = WARN catches silent write failures 📋 Daily Ops Report 7:07 AM daily self-diagnosis terse verdict → chat notification Monitoring feedback loop Heartbeats + freshness checks feed back into the /health dashboard and daily ops report 7-day grid · status board · stale-data alerts · banner (all-green vs issues) pull search fetch write write write read SSR read
Stock Demon · Built with Claude Code + Cowork · Not investment advice