Project
Narrative Radar: Telling a Market Overreaction from a Real Problem
Narrative Radar is a private research desk for US swing trading, built with Claude Code. It watches the whole market for stocks that fell hard, works out in code whether each fall came with the stock’s group or alone on the company’s own news, has a language model read the evidence and argue both sides, and sends one short Telegram message per run naming up to three falls worth a look and three not to buy. The brief was to tell an emotional overreaction from a real problem without a person reading the news all day. It places no orders, uses only free public data, and claims no edge.
- Status
- Active · paper trading only · private
- Built with
- Python · GitHub Actions · Claude Code
- Stack
- Python 3.12 · uv · ruff · pydantic · Nasdaq listings · Daily bars · SEC 8-K filings · Company RSS · Earnings calendar · Language model · GitHub Actions · Telegram · Claude Code
How it runs · five checkpoints a weekday
- 01
Capture
GitHub ActionsPythonhttpxfeedparserFive times a weekday, on New York hours, a GitHub Actions run pulls the Nasdaq listing snapshot and the session’s largest falls, daily bars for every lead, the index and sector funds, SEC 8-K filings, company news feeds and the earnings calendar.
Decision · Every fetch goes to an allowlisted host and writes a SHA-256 receipt. A host that answers 429 is halted for the run rather than retried, and capture is bounded at nine minutes, so one slow source cannot take the run down.
- 02
Screen
PythonAn issuer down 8% in one or two sessions, or 12% in five, gets company evidence and a model view. Every other priced issuer stays listed.
Decision · The threshold is a rule in code, so the same fall is treated the same way on every run and nothing is picked by hand.
- 03
Discriminator
PythonpydanticPlain Python works out whether the fall came with the stock’s group, measured against the median of its Nasdaq industry, or alone; whether the company itself filed or announced anything; and sorts it into narrative, own news, alone or unclassified, with an overreaction rank.
Decision · Python decides prices, screens, arithmetic and state. The model never produces a number: it explains dated evidence and argues the other side.
- 04
Research
Language modelpydanticA language model reads the dated evidence for each screened issuer and returns Investigate, Wait or Avoid: the story behind the fall, the countercase, and what would invalidate the view.
Decision · The facts are published before any model call, so a model failure never blocks the numbers. A validator refuses any view that quotes a number not in the supplied facts, cites a source without quoting it, or states a probability.
- 05
Message
TelegramOne Telegram message per run, readable in five seconds: the indices, a mood line, up to three falls worth a look and up to three not to buy, each with how often similar falls won back half within two weeks since 2019.
Decision · Every model call and every send writes a reservation and a receipt first, and an uncertain outcome is never resent. Nothing arrives twice, and nothing is silently lost.
- 06
Evidence
PythonMarkdownAn event study over roughly 25,000 falls since 2019 with 2026 held out, ten shadow entry and exit rules scored against buying every fall at the next open, and a paper trial whose rules were frozen and hashed on the day it started.
Decision · Each study was registered in a commit before any result existed, and new ideas run as shadow arms scored only on later events, so nothing is tuned against published results.
What runs
- Five scheduled runs a weekday on GitHub Actions, with reports and state committed back to the repository
- Capture, screen and discriminator in Python, with a receipt for every fetch
- A source-bound model step whose output is validated against the facts it was given
- One Telegram message per run, with a reservation and a receipt around every send
- A pre-registered event study, shadow arms and a frozen paper trial
- A test suite that never sends a message, calls a model or writes live state
Stack
No broker, no paid data, no claimed edge. Everything with a number in it is decided in code; the model explains the fall and must cite the evidence it was given.