| name | sector-rotation-rs-screener |
| description | Prescriptive sector-rotation screener that ranks sectors by relative strength, constituent breadth, and lifecycle stage, emitting a machine-readable FAVOR / ROTATING_IN / ROTATING_OUT / AVOID / NEUTRAL verdict per sector for both US and KR markets. Unlike the narrative sector-analyst skill, this produces a deterministic JSON snapshot (data/sector_rs_{market}.json) that the daily-briefing candidate discovery consumes to bias stock ranking toward sectors rotating in and away from sectors rotating out. Use when the user wants an actionable "which sectors to favor/avoid right now" answer, a sector leaderboard, sector relative-strength ranking, ์นํฐ ๋กํ
์ด์
, ์นํฐ ์๋๊ฐ๋, or which sectors are leading/lagging. |
Sector Rotation RS Screener
Overview
This skill turns each sector's price structure โ measured relative to the
market benchmark โ plus its constituent breadth into a prescriptive rotation
verdict and a 0โ100 score. It is the deterministic, machine-readable
counterpart to sector-analyst (which writes a narrative cycle-phase report).
Use this one when you want an actionable leaderboard and a JSON artifact that
downstream automation (the daily briefing's candidate discovery) can read.
All scoring lives in mcp-market-data/sector_rs.py (pure, never-raise). The
CLI command bin/stock-cli sector-rs fetches the data, builds the verdicts, and
optionally persists the snapshot.
When to Use This Skill
- "Which sectors should I favor / avoid right now?"
- "Rank the sectors by relative strength."
- "Is tech rotating in or out?"
- "์นํฐ ๋กํ
์ด์
์ ๊ฒํด์ค", "์ง๊ธ ์ด๋ค ์นํฐ๊ฐ ๊ฐํด?"
- Before logging individual-stock predictions, to gate by the parent sector.
For a qualitative market-cycle narrative (Early/Mid/Late cycle, scenario
probabilities), use sector-analyst instead โ the two are complementary.
The Three Axes
- Relative strength (RS)
rs_1m = sector_etf.return_1m โ benchmark.return_1m
rs_3m = a 63-bar (~3-month) close-return spread vs the benchmark.
- Breadth โ fraction of the sector's constituent basket whose latest close
is above its MA20 and whose 1-month return beats the benchmark's.
- Stage (lifecycle) โ from RSI14, distance to MA50, and overextension:
- EARLY = RSI14 โ [45, 65] AND price within ยฑ8% of MA50 AND
overextension NONE AND
rs_1m > 0 (constructive, not yet extended).
- LATE = overextension ELEVATED/EXTREME OR price >15% above MA50 OR
RSI14 > 70 (stretched / blow-off).
- MID = otherwise.
Verdict Map (prescriptive)
| Verdict | Condition | Action |
|---|
| FAVOR | rs_1m > 0 AND breadth โฅ 0.5 AND stage โ (EARLY, MID) | Overweight; prefer this sector's leaders. |
| ROTATING_IN | rs_1m > 0 AND rs_3m โค 0 AND stage == EARLY | Fresh leadership turning up โ accumulate early. |
| ROTATING_OUT | (rs_1m < 0 AND rs_3m > 0) OR (stage == LATE with weak breadth) | Trim; momentum rolling over. |
| AVOID | rs_1m < 0 AND breadth < 0.4 | Underweight; lagging with poor participation. |
| NEUTRAL | otherwise, or when the benchmark is missing | No edge; defer to bottom-up. |
score = 0.5*RS + 0.3*breadth + 0.2*stage, normalized to 0โ100. A missing
benchmark floors every sector to NEUTRAL (score 50) โ the screener never
certifies rotation against an unknown market.
Workflow
Step 1 โ Generate the snapshot
bin/stock-cli sector-rs --market US
bin/stock-cli sector-rs --market KR
bin/stock-cli sector-rs --market US --write
bin/stock-cli sector-rs --market KR --write
The output is JSON: a sectors list ranked by score descending, each with
verdict, stage, rs_1m, rs_3m, breadth_pct, score, the proxy etf,
and the constituents basket. --write is the only side effect; without it the
command is read-only.
- US sector ETFs and leader baskets are static inside
sector_rs.py
(US_SECTOR_ETFS / US_SECTOR_CONSTITUENTS), benchmark SPY.
- KR sectors come from
data/kr_sector_map.csv
(sector,proxy_etf,proxy_etf_name,constituents), benchmark 069500.
Step 2 โ Interpret the leaderboard
Read top-to-bottom: FAVOR/ROTATING_IN sectors at the top are where new long
ideas should concentrate; ROTATING_OUT/AVOID at the bottom are where to trim or
stay out. Cross-check rs_1m vs rs_3m: a positive rs_1m with a negative
rs_3m is the classic early rotation signature (ROTATING_IN).
Step 3 โ Apply per stock
When evaluating an individual ticker, look up its sector's verdict/stage and let
it gate the call: favor leaders in FAVOR/ROTATING_IN sectors; demote or skip
names in ROTATING_OUT/AVOID sectors.
How discovery consumes the snapshot
scheduler/candidate_discovery.py reads the persisted file via
_load_sector_verdicts(market) (never-raise: a missing or stale file โ {}),
which maps every constituent and proxy ETF ticker to its sector verdict.
apply_sector_boost(candidates, verdicts) then:
- stamps each candidate's
sector_verdict / sector_stage in place, and
- returns a bounded
{ticker: multiplier} map the ranking sort folds in:
| Sector state | Multiplier |
|---|
| FAVOR + EARLY | ร1.30 |
| ROTATING_IN (or FAVOR/MID) | ร1.15 |
| NEUTRAL / unknown | ร1.00 |
| ROTATING_OUT (non-LATE) | ร0.80 |
| AVOID / ROTATING_OUT+LATE | ร0.60 |
When no snapshot exists, every multiplier is exactly 1.0 and candidate fields
are left untouched โ discovery ranking is byte-identical to the pre-sector
behaviour (this no-op is covered by scheduler/tests/test_sector_boost.py).
Prerequisites
bin/stock-cli available in the project root.
- Network access for the price batch (yfinance for US, PyKRX for KR).
- No API key required.
Notes
- Pure scoring lives in
mcp-market-data/sector_rs.py; the CLI command is
cmd_sector_rs in stock_cli.py.
- The snapshot files
data/sector_rs_us.json / data/sector_rs_kr.json are
gitignored โ they are regenerated every run.
- Sector-cohort backtesting reuses
scheduler/asof_backtest.py; this skill does
not ship its own backtest harness.