# Macro Regime 3layer

> Detect the current US equity market regime (BULL / SIDEWAYS / BEAR) by combining three independent signals: ADX trend strength, market breadth, and the VIX-vs-realized-volatility ratio. Use this skill when a user wants to know "what regime is the market in", needs a macro filter to gate trading strategies, asks whether to allow long entries, or wants to understand whether trends are real or volatility-driven noise. Triggers include: "current market regime", "is this a trend or chop", "macro filter", "should I deploy momentum strategy now", "is the market trending", "bull or bear", "what's the regime", "market regime detector", or any request to classify the broad macro environment for strategy gating.

- Skill: `doertail/macro-regime-3layer` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add doertail/macro-regime-3layer`
- Raw SKILL.md: https://api.skillmd.com/api/skills/doertail/macro-regime-3layer/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: doertail (https://skillmd.com/u/doertail)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/doertail/macro-regime-3layer

---


# Macro Regime 3-Layer Detector

Classify the US equity market regime as **BULL / SIDEWAYS / BEAR** using a 2-of-3 majority vote
across three independent, mathematically uncorrelated signals.

Most regime detectors collapse to a single signal (e.g. "is index above its MA200?"). That
makes them brittle — a single bad data point flips the regime. A three-signal vote is more
robust: a regime call only changes when at least two layers agree.

**Note**: Not financial advice. Historical backtests do not guarantee future results.

---

## The three layers

| Layer | Signal | Bull vote when | Bear vote when | Sideways vote when |
|---|---|---|---|---|
| **1. Trend** | QQQ ADX(14) + DI± | ADX ≥ 25 and DI+ > DI- | ADX ≥ 25 and DI+ < DI- | ADX < 20 |
| **2. Breadth** | % of S&P 500 above MA200 | breadth > 60% | breadth < 40% | 40% ≤ breadth ≤ 60% |
| **3. Volatility** | VIX / 20-day realized vol of S&P 500 | ratio outside [0.8, 1.2] and QQQ > MA200 | ratio outside [0.8, 1.2] and QQQ ≤ MA200 | 0.8 ≤ ratio ≤ 1.2 |

Each layer votes independently. **Final regime = 2-of-3 majority.** Sideways takes priority on tie
(two sideways votes → SIDEWAYS overall).

### Why three signals

- **ADX** measures trend strength but not direction reliability when weak.
- **Breadth** measures whether the rally is participatory or led by a few mega-caps.
- **VIX/RV** measures whether implied fear matches realized turbulence — divergence often
  precedes regime shifts.

Any single signal can mislead. Two agreeing signals is much harder to fake.

---

## Step 1: Ensure dependencies

```python
import subprocess, sys
for pkg in ("yfinance", "pandas", "numpy"):
    try:
        __import__(pkg)
    except ImportError:
        subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", pkg])
```

## Step 2: Run the detector

```python
from macro_regime import detect_market_regime

result = detect_market_regime()
# {
#   "regime": "BULL" | "SIDEWAYS" | "BEAR",
#   "votes": ["BULL", "BULL", "SIDEWAYS"],
#   "layers": {
#       "1_trend":      {"vote": "BULL",     "adx": 28.4, "plus_di": 24.1, "minus_di": 18.3},
#       "2_breadth":    {"vote": "BULL",     "breadth_pct": 64.2},
#       "3_volatility": {"vote": "SIDEWAYS", "vix": 17.2, "realized_vol": 18.1, "ratio": 0.95},
#   },
#   "context": {"qqq_close": 540.1, "qqq_ma200": 510.4, "qqq_above_ma200": True}
# }
```

Default fetches:
- QQQ + ^VIX + S&P 500 sample (50 large caps for breadth — fast, ~10–20 seconds).
- For higher accuracy use `detect_market_regime(use_full_sp500=True)` — downloads the full
  S&P 500 universe (~3–5 minutes).

## Step 3: Use the result as a STRATEGY ROUTER (not a gate)

The naive use — "only trade longs in BULL regimes, stay flat in BEAR" — turns out to
*destroy* mean-reversion edge. An 8-year, 843-signal backtest shows BEAR-regime
mean-reversion signals actually outperform BULL-regime ones:

| Regime | Mean 5d | Win rate (5d) |
|---|---|---|
| BULL | +0.80% | 55.5% |
| SIDEWAYS | **+2.07%** | **67.7%** |
| BEAR | **+2.26%** | **65.6%** |

So treat the regime as a router, not a gate:

```python
result = detect_market_regime()
regime = result["regime"]

if regime == "BULL":
    enable_momentum_breakout()       # trend-following needs a trending tape
elif regime == "SIDEWAYS":
    enable_mean_reversion()          # chop is mean-reversion's home turf
else:  # BEAR
    enable_mean_reversion()          # deepest oversold = strongest snap-back
    # Staying flat in BEAR is a risk-tolerance choice, not a signal-quality one.
```

See [README.md](./README.md) for the full backtest table and reasoning.

## Step 4: Respond to the user

Present the breakdown so the user understands *why* the regime is what it is. Don't just say
"BULL" — show which layers agreed.

> **Current regime: BULL** (2-of-3 vote)
>
> | Layer | Signal | Vote |
> |---|---|---|
> | 1. Trend (ADX 28.4 / DI+ 24.1 > DI- 18.3) | Strong uptrend | 🟢 BULL |
> | 2. Breadth (64.2% of S&P 500 above MA200) | Broad participation | 🟢 BULL |
> | 3. Volatility (VIX 17.2 / RV 18.1 = 0.95) | Implied ≈ realized | 🟡 SIDEWAYS |
>
> Layer 3 disagrees but the trend + breadth majority drives the call. Momentum strategies are
> currently allowed.

### Caveats to mention
- This is a **macro filter**, not a single-stock signal. It tells you the environment, not
  what to buy.
- Thresholds (25/20 for ADX, 60/40 for breadth, 0.8/1.2 for VIX/RV) are calibrated for US
  equities and may need adjustment for other markets.
- The sample-of-50 breadth is a reasonable proxy; full S&P 500 is more accurate but slower.

---

## Real-world example

This skill was extracted from the [quant-scanner](https://github.com/doertail/quant-scanner) project
where it is the top-level macro gate: BULL allows mean-reversion + momentum, SIDEWAYS allows
mean-reversion only, BEAR blocks all new long entries. Combined with the
[vix-regime](../vix-regime) skill for VIX-band overlay, it forms a two-stage macro filter.

