How the score
is actually built.
No black boxes. Every input is a public API call, every weight is stated, every gate is documented.
The formula
The rotation score is a weighted composite, bounded [0, 100]. It intentionally weights flow acceleration over raw momentum — flow leads price.
rotation_score(sector) =
0.35 · zscore(sector_momentum_7d, universe)
+ 0.30 · flow_acceleration(etf_flow, window=3d, baseline=20d)
+ 0.20 · rebalance_delta(index_constituents, lookback=14d)
+ 0.15 · qualitative_news_alignment(category ∈ {5, 6, 9})
crowdedness(sector) =
leaderboard_exposure(sector) / trailing_max_exposure(sector, 90d)
state = crowdedness < 0.45 ? "early"
: crowdedness < 0.60 ? "mid"
: "late"Input layers
Rotation universe · polled 15m for weight changes
SSI composition + history · detect rebalance-driven flow
Same-day institutional flow · macro backdrop
Flow acceleration · single strongest input
Categories 5/6/9 · qualitative confirmation + citations
Top-50 by 30d volume · positive PNL only
Per-sector aggregated exposure · crowdedness input
Volatility + depth · liquidity gate before showing
Crowdedness gate
The most-abused pattern in retail crypto is chasing a sector after positioning is already stretched. SectorPulse refuses to flag a signal 🟢 early if leaderboard exposure is above 60% of its trailing 90-day max — regardless of how strong the rotation score is.
Applied to discovery instead of personal history, this is the same "don't chase lucky whales" discipline as our Edgework Trade Check.
Risk controls
- Crowdedness gateAbove 60% flips green → yellow, disallowing "early" tag.
- Depth checkEvery ticket previews the SoDEX book depth it would actually hit.
- Read-only demoNo wallet connect. No execution without explicit user confirmation (Wave 3).
- Invalidator requiredEvery thesis names the specific condition that kills it.
- No hallucinated numbersEvery % in the thesis maps to a tool_result — not a prompt guess.