Predict where news-driven crowd biases will misprice a market — then fade them.
crowd-fade pulls live news from GDELT, runs a
swarm of LLM agents (one specialized per logical fallacy) over each watched
entity, aggregates their verdicts through an explicit behavioral-psychology
layer, and emits ranked "the crowd will misprice this" signals with rationale.
It is domain-agnostic at the core with two adapters shipped: equities (stocks the retail crowd trades) and sports (teams the public bets on).
Status: a working thin slice — real GDELT ingest, real agent swarm, real aggregation, ranked output. Validation/backtesting is intentionally not wired up yet (see Honest limitations).
This system makes two distinct predictions, and conflating them is the classic way this kind of project fails:
- Crowd behavior — given this news, will the crowd be biased, which direction, how hard? (the fallacy agents + psychology layer — this is what crowd-fade does today)
- Mispricing — does that bias actually move the price away from fair value? You can only measure this against an efficient baseline (a sharp book like Pinnacle; analyst/consensus), and only validate it with ground-truth outcomes (closing-line movement; forward returns).
crowd-fade fully implements (1) and frames its output as a prediction about the crowd, not a claim about market truth. (2) is the roadmap.
┌──────────────────────────────────────────────┐
GDELT DOC 2.0 ───▶│ INGEST (ingest/gdelt.py) │
(free, no key) │ per entity: headlines + tone now/baseline │
│ + coverage-volume spike. Rate-limited+cached │
└───────────────────────┬──────────────────────┘
│ NewsSnapshot
▼
┌──────────────────────────────────────────────┐
│ FALLACY AGENT SWARM (agents/fallacies+llm.py) │
│ 1 LLM agent per fallacy. Each answers: │
│ does the crowd commit THIS bias here, which │
│ way, how hard? → direction/magnitude/conf │
└───────────────────────┬──────────────────────┘
│ [FallacyAssessment]
▼
┌──────────────────────────────────────────────┐
│ PSYCHOLOGY AGGREGATION (agents/psych.py) │
│ salience · affect · surprise · herding │
│ cascade · loss-aversion asymmetry · │
│ overreaction-vs-underreaction regime │
└───────────────────────┬──────────────────────┘
│ CrowdSignal
▼
┌──────────────────────────────────────────────┐
│ DOMAIN + REPORT (domains/*, report.py) │
│ rank by conviction → actionable phrasing → │
│ terminal report + JSON in out/ │
└──────────────────────────────────────────────┘
They operate at different levels, and keeping them separate is the point:
- Fallacy agents detect individual reasoning errors in how the news reads. Each is an LLM with a single lens (recency bias, anchoring, gambler's fallacy, …). One agent, one fallacy — exactly as specified.
- The psychology layer models how those errors aggregate into crowd action and mispricing, using behavioral-finance dynamics that live at the crowd level: attention/salience (a coverage spike amplifies bias), affect (emotional tone intensifies reaction), herding cascade (consensus compounds conviction), loss-aversion asymmetry (panic on bad news is stronger and stickier — prospect theory), and an overreaction-vs-underreaction regime switch (a loud emotional spike tends to mean-revert → fade; a quiet persistent bias tends to drift → follow).
This layer is deliberately deterministic and inspectable — every knob is in
agents/psych.py and config.yaml, not hidden inside a model.
python -m crowdfade.cli list-fallacies prints them. Currently:
recency bias · availability heuristic · confirmation bias · gambler's fallacy · hot-hand fallacy · anchoring · base-rate neglect · narrative/halo · bandwagon / social proof · authority bias · overconfidence · framing effect · sunk-cost / disposition.
Adding one is a single dict in agents/fallacies.py — the swarm scales
automatically.
cd crowd-fade
python -m venv .venv && source .venv/bin/activate # optional
pip install -r requirements.txtFor live runs, add your key (mock runs need no key):
cp .env.example .env # then edit .env to add ANTHROPIC_API_KEY# Offline demo — deterministic agents, no API key. Still pulls real GDELT news.
python -m crowdfade.cli run --mock
# One entity only (handy: GDELT allows ~1 request/5s, so each entity ≈ 17s)
python -m crowdfade.cli run --mock --limit-entities 1 --timespan 72h
# Sports instead of equities
python -m crowdfade.cli run --domain sports --mock
# LIVE (needs ANTHROPIC_API_KEY) — both domains, top 8
python -m crowdfade.cli run --domain all --top 8
# Inspect the agent roster
python -m crowdfade.cli list-fallaciesrun options: --domain equities|sports|all|<comma-list> · --mock ·
--top N · --limit-entities N · --timespan 24h|72h|… · --config · --env.
Every run also writes the full structured result (all agent verdicts, modifiers,
evidence) to out/signals-<timestamp>.json.
# ENTITY CONVICTION STANCE BIAS
1 GameStop (GME) ███████░░░ 0.71 FADE (contrarian) crowd ↑ over-favors (+0.62)
- conviction — how strong/coherent the predicted crowd reaction is (0–1).
- stance —
FADE(overreaction regime → expect mean reversion) orFOLLOW(no attention spike → bias may persist), orNO EDGE. - crowd bias — signed:
+the crowd is pushed to over-favor/buy/back the entity;−over-fade/sell/against. - mispricing — the crowd-level distortion implied (OVER/UNDER-valued).
- play — domain-specific actionable phrasing (e.g. "take the other side of the spread; expect closing-line value against X").
- Each card lists the top fallacies driving the call with their rationale, the psych factors applied, and the evidence (tone, volume spike, sample headlines).
Everything lives in config.yaml: watchlists per domain, the LLM model/effort,
the psychology thresholds and per-fallacy weights, and GDELT ingest settings.
See the inline comments there.
Model choice & cost. The default is claude-opus-4-8. This swarm makes one
call per fallacy per entity (13 × entities), so for high-volume use you may set
llm.model: claude-haiku-4-5 to cut cost ~5× — that tradeoff is yours to make.
- No validation/backtesting yet. crowd-fade predicts crowd behavior. It does not yet measure whether that behavior creates exploitable mispricing — that needs an efficient baseline and ground-truth outcomes (see Roadmap). Treat output as hypotheses, not bets.
- GDELT is noisy. Tone is a coarse signal; entity↔news attribution via a text query is imperfect; coverage volume ≠ betting/▢trading volume.
- The crowd-mispricing link is assumed, not proven, in this slice. The psych layer encodes plausible, literature-backed dynamics, but the weights are hand-set, not fit to data.
- "Fade the public" edges are real but thin and competed. In sports the true signal is the money %/ticket % split vs a sharp line, not news tone alone.
--mockis illustrative. It fabricates agent verdicts deterministically from the news features so you can see the pipeline; it is not a prediction.
- Ground truth + baseline → backtest. Sports: capture open vs closing line (Pinnacle as the efficient benchmark) and grade signals by closing-line value / ROI. Equities: forward returns vs a factor/consensus baseline.
- Money-% / ticket-% splits for sports (the actual fade-the-public signal).
- Calibration of agent outputs and psych weights against realized outcomes (replace hand-set multipliers with fitted ones).
- Distill the LLM swarm into cheap classifiers once verdicts are trusted (the "hybrid" path).
- GKG via BigQuery for richer per-article tone/emotion (GCAM) at scale.
crowd-fade/
config.yaml watchlists, model, psych knobs, GDELT settings
run.py convenience entrypoint
crowdfade/
cli.py argparse CLI
engine.py orchestration: ingest → swarm → aggregate → rank
schemas.py dataclasses passed between stages
config.py config.yaml + .env loading
report.py terminal report
ingest/gdelt.py GDELT DOC 2.0 client (rate limit + cache)
agents/
fallacies.py the roster (1 dict per agent) + prompts + JSON schema
llm.py async Anthropic swarm + deterministic mock
psych.py behavioral-psychology aggregation layer
domains/
base.py Domain abstraction + registry
equities.py stocks adapter
sports.py sports-betting adapter