daybreak — Pre-Market Portfolio Intelligence
A scheduled pipeline that collects news, SEC filings, Fed and macro data, and quantified sentiment for one specific portfolio each morning, ranks every story against the holdings, and emails a narrated pre-market brief before the open.
Private Repo — Request AccessCase Study
How it was built
Problem
A swing trader's edge decays fast on stale, generic market news. General feeds bury the handful of stories that actually touch a specific book — an 8-K on a holding, a Fed print, a sector move — under everything else, and checking a dozen sources by hand before the open does not scale to a daily habit.
Approach
Built a scheduled pipeline: five fail-soft adapters normalize news, filings, macro series, and quantified sentiment into one content-hashed record type; a pure ranker buckets and scores every story against the portfolio; a gauge z-scores the day's mood against a 30-day baseline; and a headless LLM narrates the ranked context into a sectioned brief emailed before the open. Every source failure is soft and reported, so the run always completes.
Key Decision
Kept every analytical stage — collection, ranking, deduplication, and the gauge — deterministic and in Python, and handed the language model only the final narration. Ranking takes the clock as an injected parameter, so it is unit-tested against fixed timestamps and never invents a number; the model rephrases what the context document already contains, nothing more. A wrong figure in the brief is a failing test, not a mystery buried in prose.
Result
A strictly typed, tested pipeline that emails a portfolio-specific pre-market brief every weekday morning, with a sentiment read that positions today's news flow against its own history. It was hardened by an eight-finding self-review before it shipped — the biggest catch was month-old macro prints silently decaying out of the brief, exactly the kind of story it exists to surface.
Results
Key metrics
5
Fail-Soft Data Sources
6
Relevance Buckets
30-Day
Sentiment Baseline
Zero
Type Suppressions (Strict)
Approach
Technical overview
Fail-Soft Source Adapters
Five adapters implement one source protocol and normalize news, filings, macro series, and sentiment into a frozen, content-hashed Item, so downstream stages never know which upstream produced a record. Each retries transport failures and returns an explicit success-or-error value rather than raising — a dead feed becomes a coverage note, never a failed run. Alpha Vantage's ticker parameter turned out to be AND-semantics (two symbols returned results, ten returned none), so the adapter fetches one request per ticker inside the free tier's 25-per-day budget and degrades to partial coverage when it runs out.
Pure, Deterministic Relevance Ranking
Items in, ranked items out, with no I/O in the ranking layer. Each story is classified into one of six buckets — held positions, watchlist, sectors, Fed and macro, filings, and general market — by ticker, company-name, and keyword matching, then scored by bucket weight times recency decay times sentiment magnitude. Near-duplicates of the same story from different outlets collapse by token-set Jaccard similarity. The clock is passed in as a parameter, so the entire ranker is unit-tested against fixed timestamps.
Quantified Sentiment Gauge
Alpha Vantage returns a per-article sentiment score in [-1, 1]; the gauge averages the day's scored articles and z-scores that mean against a rolling 30-day baseline persisted in SQLite, so the brief can state that news flow is unusually bearish for this book with a number behind it. Macro observations are exempt from recency decay — otherwise a monthly CPI print would decay to near zero and drop out of the section that exists to show it.
LLM Narration Under a Hard Contract
Every analytical stage stays in Python; the language model only writes prose over a deterministic context document it cannot exceed. The ranked context, gauge, and coverage note are archived, then a headless Claude Code call renders a sectioned Markdown brief that is converted to HTML and delivered over SMTP. When a live run showed the model inventing its own section headings, the fix was to move the output contract into the document itself rather than trust a prompt flag. A Windows scheduled task runs the whole pipeline before the open each weekday.
Gallery
Output & visualizations



Narrated Briefing Email — The delivered pre-market brief — TL;DR and per-position notes, each claim linked to its source
Relevance-Ranked Context — The deterministic document the model narrates from — every item bucketed, scored, sentiment-tagged, and deduped
Sentiment Gauge & Coverage — Aggregate news-flow sentiment with its baseline caveat, and per-source health for the run
Stack