Skip to content

CormacmacmCormac/crowd-fade

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

crowd-fade

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).


The one idea that matters

This system makes two distinct predictions, and conflating them is the classic way this kind of project fails:

  1. 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)
  2. 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.


Architecture

                    ┌──────────────────────────────────────────────┐
  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/               │
                    └──────────────────────────────────────────────┘

Why two layers (fallacies and psychology)?

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.


The 13 fallacy agents

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.


Install

cd crowd-fade
python -m venv .venv && source .venv/bin/activate   # optional
pip install -r requirements.txt

For live runs, add your key (mock runs need no key):

cp .env.example .env      # then edit .env to add ANTHROPIC_API_KEY

Usage

# 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-fallacies

run 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.


Reading the output

  #  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).
  • stanceFADE (overreaction regime → expect mean reversion) or FOLLOW (no attention spike → bias may persist), or NO 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).

Configuration

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.


Honest limitations

  • 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.
  • --mock is illustrative. It fabricates agent verdicts deterministically from the news features so you can see the pipeline; it is not a prediction.

Roadmap (to make it a real predictor, not just a crowd model)

  1. 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.
  2. Money-% / ticket-% splits for sports (the actual fade-the-public signal).
  3. Calibration of agent outputs and psych weights against realized outcomes (replace hand-set multipliers with fitted ones).
  4. Distill the LLM swarm into cheap classifiers once verdicts are trusted (the "hybrid" path).
  5. GKG via BigQuery for richer per-article tone/emotion (GCAM) at scale.

Project layout

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

About

Predict where news-driven crowd biases will misprice a market, then fade them: GDELT news -> swarm of cognitive-bias LLM agents -> behavioral signal scores.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages