Theme scoring methodology¶
Overview¶
The scoring system reads five dimensions from ETL output raw_market.json and combines them into a weighted theme score from 0 to 100.
Dimensions¶
| Dimension | Default weight | Source | Calculation |
|---|---|---|---|
fundamental |
0.30 | Theme market performance | _scale(perf, midpoint=1.0, sensitivity=40) |
valuation |
0.25 | Average P/E | _inverse_ratio_score(pe, baseline=35, sensitivity=90) |
sentiment |
0.20 | Cboe Put/Call and AAII | Z-score, tanh compression, then mapping to 0–100 |
liquidity |
0.15 | Average P/S | _inverse_ratio_score(ps, baseline=8, sensitivity=70) |
event |
0.10 | Configured constants | Fixed constants: AI 70, Magnificent 7 68, BTC 65 |
Scoring functions¶
_scale(value, midpoint, sensitivity)¶
Linear mapping to 0–100:
score = 50 + (value - midpoint) * sensitivity
The result is clamped to [0, 100].
_inverse_ratio_score(value, baseline, sensitivity)¶
For valuation metrics such as P/E and P/S, lower values score better:
_scale(baseline / value, midpoint=1.0, sensitivity)
Sentiment aggregation (sentiment.aggregate)¶
- Put/Call ratio: calculate a z-score from the log ratio, invert it (panic is contrarian bullish), then apply
tanhcompression. - AAII bull-bear spread: calculate a z-score and invert it (extreme optimism is contrarian bearish), then apply
tanhcompression. - Combine components as
50 + 50 * mean(component_scores)and clamp to[0, 100].
History retains up to 252 Put/Call observations and 104 AAII observations.
Weight configuration¶
config/weights.yml supports per-theme overrides of the defaults:
weights:
default:
fundamental: 0.30
valuation: 0.25
sentiment: 0.20
liquidity: 0.15
event: 0.10
theme_ai:
fundamental: 0.30
valuation: 0.15
sentiment: 0.25
liquidity: 0.20
event: 0.10
theme_btc:
fundamental: 0.10
valuation: 0.15
sentiment: 0.30
liquidity: 0.30
event: 0.15
Thresholds and actions¶
| Key | Default | Meaning |
|---|---|---|
action_add |
75 | A total score at or above this value raises the attention level |
action_trim |
45 | A total score at or below this value lowers the attention level |
Fallback behavior¶
When ETL fails or data is missing:
- Missing dimensions use the neutral value
50or a historical cache. scores.json.degradedis set totrue.- The daily report marks delayed data in its title and cards.
- A dimension with
fallback: trueindicates that a fallback value was used.
Updating the configuration¶
When changing config/weights.yml:
- Update
versionandchanged_at. - Run
pytest -k contractto check contract tests. - Update expected values in
tests/test_scoring.py.
Actual meanings of compatibility keys¶
These are descriptive heuristics, not out-of-sample validated predictions.
AI fundamental measures market performance; Magnificent 7 measures aggregate
market cap. Both equity liquidity keys measure P/S valuation, not trading
liquidity or fund flow. BTC uses ETF net inflow. Event scores are fixed constants
(AI 70, Magnificent 7 68, BTC 65), not measured event intensity.
breakdown_detail includes the actual metric, display label, evidence level
and limitations. See Agent access and score semantics.