# M5 -- HMM Regime-Switching HAR: Volatility Regime Detection + Conditional Forecasting

**Status:** COMPLETE (Cycle 25 Wave 3, po-2024 Track C2).

## Why

M3 established HAR as the gold-standard baseline for crypto RV forecasting. M3b showed
asymmetric semivariance benefits BTC. M4 showed DLinear beats HAR on BTC at all horizons.
A natural extension: can regime-switching models, where different HAR coefficients apply
in different volatility regimes (low-vol vs high-vol), improve on the single HAR model?

The economic intuition: volatility dynamics may differ between calm and turbulent periods.
A model that adapts its coefficients to the current regime could capture this asymmetry.

## Model

**Classic HAR (Corsi 2009):**
```
log RV_{t+h} = b0 + b_d*rv_d + b_w*rv_w + b_m*rv_m + e
```

**Regime-Switching HAR (this work):**
```
log RV_{t+h} = b0 + b_d*rv_d + b_w*rv_w + b_m*rv_m
             + g0 * I(regime=high)
             + g_d * rv_d * I(regime=high)
             + g_w * rv_w * I(regime=high)
             + g_m * rv_m * I(regime=high)
             + e
```

Where:
- Regime decoded by K=2 Gaussian HMM (Viterbi) on log-RV
- 8 OLS coefficients (4 base + 4 regime interaction terms)
- At prediction time, HMM decodes current regime, selecting the interaction term values

## Methodology

- K=2 Gaussian HMM (hmmlearn) on log-RV, Viterbi-decoded
- Regime-switching HAR with interaction terms (8 coefficients)
- Walk-forward 5-fold expanding window, refit every 22 days
- 4 seeds (0, 7, 42, 99) for HMM initialization
- 2 coins (BTC-USD, ETH-USD), 3 horizons (h=1, 5, 10)
- Diebold-Mariano HAC test vs classic HAR baseline (`loss_fn="mse"` — perte de précision, jamais `linear`)
- Aggregate verdict (machine 4 états unifiée `#14388`): `BEATS` (4/4 seeds BEATS + `dm_p_median < 0.05`),
  `NO BEATS` (4/4 seeds BEATEN + `dm_p_median < 0.05`), `refuted-de-biased` (4/4 BEATS sur la jambe
  parente uniquement), `INCONCLUSIVE` (le reste, dont 3/4 d'un côté ou l'autre). La jambe brute et
  la jambe hors biais partagent la même machine (`_aggregate_state` dans `scripts/hmm_regime_vol.py`).
- Jambe hors biais (ajoutée 2026-09-02) : décomposition `MSE = biais² + variance` par modèle, edge
  contre baseline dé-biaisée, et DM sur erreurs recentrées des deux côtés

## Files

| File | Role |
|------|------|
| `scripts/hmm_regime_vol.py` | HMM regime-switching HAR model + walk-forward runner + instrumentation de biais |
| `scripts/tests/test_hmm_regime_vol.py` | Tests du contrat de sortie, de la jambe recentrée et de la machine d'états agrégée (45 tests) |
| `scripts/results/m5_hmm_regime.json` | Full results (609s runtime) |
| `docs/M5_HMM_REGIME.md` | This document |

Le runner expose un CLI (`--coins`, `--horizons`, `--seeds`, `--out`, `--dump-series`). Les séries de
prévision alignées ne sont écrites que sur `--dump-series` (CSV séparé) : l'artefact JSON reste léger
et ne porte que des agrégats et des décompositions, sur le modèle de #12745.

## Results (BTC+ETH, 4 seeds, 609s runtime)

### DM verdict summary

| Verdict | Count | Configs |
|---------|-------|---------|
| **BEATS** | 1/6 | ETH h=1 (4/4 seeds) |
| INCONCLUSIVE | 4/6 | BTC h=1 (3/4 BEATS), BTC h=5/h=10 + ETH h=5 (3/4 BEATEN + 1 INCONCLUSIVE) |
| **NO BEATS** | 1/6 | ETH h=10 (4/4 seeds BEATEN) |

### Per-coin results (aggregated over 4 seeds)

| Coin | Horizon | Regime MSE | Classic MSE | Reduction | DM p-value | Verdict brut |
|------|---------|------------|-------------|-----------|------------|--------------|
| BTC-USD | 1 | 0.825 | 0.888 | +7.0% | 3/4 seeds BEATS, 1 INCONCLUSIVE | INCONCLUSIVE |
| BTC-USD | 5 | 0.580 | 0.522 | -11.1% | 3/4 BEATEN, 1 INCONCLUSIVE | INCONCLUSIVE |
| BTC-USD | 10 | 0.732 | 0.571 | -28.3% | 3/4 BEATEN, 1 INCONCLUSIVE | INCONCLUSIVE |
| ETH-USD | 1 | 0.619 | 0.684 | +9.6% | 4/4 p<0.005 | **BEATS** |
| ETH-USD | 5 | 0.441 | 0.374 | -17.9% | 3/4 BEATEN, 1 INCONCLUSIVE | INCONCLUSIVE |
| ETH-USD | 10 | 0.573 | 0.375 | -53.0% | 4/4 BEATEN | **NO BEATS** |

### MSE reduction vs classic HAR (regime - classic, positive = regime wins)

| Coin | h=1 | h=5 | h=10 |
|------|-----|-----|------|
| BTC-USD | +7.0%* | -11.1% | -28.3% |
| ETH-USD | **+9.6%** | -17.9% | -53.0% |

(*3/4 seeds significant, not all 4)

## Re-validation hors biais (2026-09-02, Epic #1454)

Les résultats ci-dessus comparent deux MSE **bruts**. Or `MSE = biais² + variance` : un écart de MSE
peut être entièrement la **mauvaise calibration de la baseline**, et non un gain de précision du
modèle. C'est ce que #10938 a levé sur M4, ce que #12684/#12734 ont formalisé, et ce que
`pr-review-discipline` §C exige depuis (rapport de biais par modèle, DM sur une perte de précision).

Le harnais persiste désormais, par seed et par config : le biais OOS signé des **deux** modèles, la
décomposition `MSE = biais² + variance`, l'écart contre une baseline **dé-biaisée**, et un DM sur
**erreurs recentrées** (`e − mean(e)` de chaque côté — le centrage annule le biais, le DM ne compare
plus que les variances). Aucune valeur publiée ci-dessus n'a été modifiée : les jambes brutes sont
recalculées à l'identique et les colonnes ci-dessous s'y ajoutent.

| Coin | h | edge brut | edge vs classic **dé-biaisée** | σ cross-seed | edge/σ | seeds BEATS (rec.) | seeds BEATEN (rec.) | dm_p_median (rec.) | Verdict hors biais |
|------|---|----------:|-------------------------------:|-------------:|-------:|:------------------:|:-------------------:|-------------------:|--------------------|
| BTC-USD | 1  |  +7,0 % |  **+1,3 %** |  4,04 pt | **0,3σ** | 3/4 | 0/4 | 1,47e-03 | **INCONCLUSIVE** |
| BTC-USD | 5  | −11,1 % | **−43,5 %** |  9,37 pt | 4,6σ | 0/4 | 4/4 | 6,21e-06 | **NO BEATS** |
| BTC-USD | 10 | −28,3 % | **−99,0 %** | 21,18 pt | 4,7σ | 0/4 | 4/4 | 1,75e-09 | **NO BEATS** |
| ETH-USD | 1  |  +9,6 % |  **+8,7 %** |  2,11 pt | **4,1σ** | 4/4 | 0/4 | 1,14e-05 | **BEATS** |
| ETH-USD | 5  | −17,9 % | **−23,4 %** |  3,85 pt | 6,1σ | 0/4 | 4/4 | 6,16e-04 | **NO BEATS** |
| ETH-USD | 10 | −53,0 % | **−66,2 %** | 14,70 pt | 4,5σ | 0/4 | 4/4 | 4,10e-05 | **NO BEATS** |

La colonne « Verdict hors biais » **est** le champ `aggregate_verdict_debiased` de l'artefact JSON, et
non une lecture faite à la main par-dessus : les six lignes ci-dessus sont rejouées depuis
`_aggregate_state` dans `scripts/tests/test_hmm_regime_vol.py`. La machine a quatre états —

| État | Condition | Sens |
|------|-----------|------|
| `BEATS` | 4/4 seeds BEATS sur la jambe recentrée **et** `dm_p_median < 0,05` | l'edge survit au contrôle de précision |
| `NO BEATS` | 4/4 seeds BEATEN **et** `dm_p_median < 0,05` | le modèle perd, significativement |
| `refuted-de-biased` | la jambe **brute** était 4/4 BEATS, la recentrée ne confirme pas | l'edge n'existait que contre une ligne de base mal calibrée (formulation #12788) |
| `INCONCLUSIVE` | tout le reste (dont 3/4 d'un côté ou l'autre) | pas d'unanimité |

`NO BEATS` l'emporte sur `refuted-de-biased` quand les deux s'appliquent : « réfuté » dit qu'une
prétention n'est pas confirmée, la mesure dit que le modèle perd — et la réfutation reste lisible
puisque chaque ligne imprime le verdict brut à côté du recentré. Le décompte des pertes est persisté
(`n_beaten_seeds_centered`), donc la colonne « seeds BEATEN (rec.) » se relit depuis l'artefact.

Le champ `aggregate_verdict` (jambe **brute**) partage désormais la même machine d'états à quatre
états que la jambe hors biais (#14388). Avant l'unification, la jambe brute n'avait que deux états
(`BEATS` exigeant 4/4 seeds, sinon `INCONCLUSIVE`) — les configs en 0/4 BEATS étaient
codées `INCONCLUSIVE`, et `m5_hmm_regime_research.ipynb` en dérivait sa lecture `DEGRADE` à la
main. La machine unifiée `_aggregate_state` (script `hmm_regime_vol.py`) fait sortir `NO BEATS`
directement du verdict brut ; l'artefact `m5_hmm_regime.json` a été re-généré et le notebook
ré-exécuté pour aligner les counts publiés.

**Subtilité #14388** : la convention unanimité stricte accepte comme INCONCLUSIVE les configurations
où 3/4 graines sont BEATEN mais la 4ᵉ est INCONCLUSIVE (DM p ≥ 0.05 pour cette graine). BTC h=5,
BTC h=10 et ETH h=5 sont dans ce cas (la 4ᵉ graine n'atteint pas le seuil de significativité) et
restent `INCONCLUSIVE` même si la tendance dominante est la perte. Seul **ETH h=10** a ses 4 graines
unanimes BEATEN et bascule en `NO BEATS` sur la jambe brute. Conséquence sur les counts publiés :
la jambe brute passe de **1 BEATS / 5 INCONCLUSIVE** (Cycle 25) à **1 BEATS / 1 NO BEATS / 4 INCONCLUSIVE** (#14388).

La jambe hors biais, elle, tranche 4 NO BEATS parce que les 4 graines **sont** unanimes BEATEN sur
la jambe centrée (`dm_centered_pvalue` < 0.05 pour les 4). La mesure de biais² décompose l'écart :
sur la jambe centrée, l'inégalité `mean(rec.) > 0` ne dépend plus du biais, donc les 4 graines
arrivent à des verdicts nets.

**Rapport de biais signé, par modèle (contrôle §C(7))** — le biais est celui du log-RV OOS :

| Coin | h | biais régime | biais classic | biais²(classic) en % de MSE(classic) |
|------|---|-------------:|--------------:|-------------------------------------:|
| BTC-USD | 1  | −0,1811 | −0,2266 |  **5,8 %** |
| BTC-USD | 5  | −0,2728 | −0,3432 | **22,6 %** |
| BTC-USD | 10 | −0,3624 | −0,4502 | **35,5 %** |
| ETH-USD | 1  | −0,0718 | −0,0810 |  **1,0 %** |
| ETH-USD | 5  | −0,1091 | −0,1290 |  **4,5 %** |
| ETH-USD | 10 | −0,1519 | −0,1727 |  **8,0 %** |

Les deux modèles sous-prévoient le log-RV partout (biais négatif), le régime un peu moins que la
baseline. La part de biais² dans le MSE de la baseline **croît fortement avec l'horizon** : à
BTC h=10, plus du tiers du MSE de la HAR classique est du biais pur, pas de l'imprécision.

### Ce que la relecture hors biais change

1. **ETH h=1 survit — c'est un vrai gain de précision.** L'edge passe de +9,6 % à **+8,7 %** une fois
   la baseline dé-biaisée : seulement 0,9 pt de l'écart venait du biais. La conjonction §C est
   complète — 4/4 seeds BEATS sur la jambe recentrée, `dm_p_median` = 1,14e-05 < 0,05, et
   **4,1σ ≥ 2σ** de dispersion cross-seed. Le seul BEATS de M5 **tient hors biais**.

2. **BTC h=1 tombe, et pour une raison mesurée.** L'edge brut +7,0 % se réduit à **+1,3 %** : environ
   **82 % de l'écart apparent était la mauvaise calibration de la HAR**, dont le biais² pèse 5,8 % de
   son MSE. Le verdict brut le disait déjà INCONCLUSIVE, mais en imputant l'échec à la seule graine 7
   (« HMM initialization sensitivity »). La mesure est plus dure : à **0,3σ**, l'edge dé-biaisé est
   trois fois plus petit que la dispersion entre graines. Ce n'est pas une graine aberrante, c'est un
   effet qui n'existe pas.

3. **Le biais de la baseline masquait l'ampleur de la dégradation aux horizons longs.** Dé-biaiser la
   HAR classique la rend meilleure, donc creuse l'écart : BTC h=10 passe de −28,3 % à **−99,0 %**,
   BTC h=5 de −11,1 % à −43,5 %. Les quatre configs longues sont **4/4 seeds BEATEN** sur la jambe de
   précision. La conclusion d'origine (« le modèle de régime est nuisible à h≥5 ») est confirmée et
   renforcée, pas infirmée.

4. **L'asymétrie BTC/ETH à h=1 est une propriété de la baseline, pas du modèle de régime.** Le même
   modèle, le même instrument : la HAR BTC porte 5,8 % de biais², la HAR ETH seulement 1,0 %. C'est
   pourquoi l'edge BTC était à 82 % du biais et l'edge ETH à 9 % seulement. Ce que M5 « gagnait » sur
   BTC h=1, c'était surtout de corriger une baseline mal calée.

**Note de comparabilité** — la HAR classique de ce harnais et la baseline HAR de M4 sont le **même
objet** : `hmm_regime_vol.py` et la chaîne `btc_vol.py → dlinear_vol.py` importent toutes deux
l'unique `har_model.HARModel`. Le biais OOS BTC mesuré ici (−0,2265869503892514 / −0,34317822065868814 /
−0,45022101989096786 pour h=1/5/10) est **bit-identique** à `har_bias_oos` de l'artefact #12745. Ce
n'est donc pas une corroboration indépendante — c'est le même calcul — mais cela vérifie que
l'instrumentation de biais ajoutée ici est câblée comme celle de la famille, et cela rend les edges
M5 et M4 directement comparables sur BTC.

## Revalidation cluster 7 actifs appariée par origine (2026-10-04, port #18190)

La grille #14359 n'auditait que BTC/ETH. Le protocole #18190 (initié M17, porté M4 #18650, M15
#18664, M12 #16009) est ici appliqué à M5 sur l'univers cluster **7 actifs appariés par origine** :
BTC (Bitstamp local), ETH (Binance local), SOL/LTC/XRP/ADA/DOT (yfinance) — la même liste que
#18650/#18664, les verdicts se lisent ligne à ligne. Grille 7×3×4 = 84 walk-forwards, checkpoint
par combo, 622 s CPU.

**Spécificité M5 du port** : les deux jambes (HAR à commutation de régime et HAR classique)
sortent de la **même boucle** walk-forward, donc le join par date attendu est l'**identité** —
la garde fail-closed de `joined_pair_errors` n'y corrige rien, elle est la **preuve** que le
harnais n'a jamais comparé positionnellement. Sur chaque cellule : `dm_n_aligned == n_preds`
partout, `dm_target_gap_max = 0.0`, **zéro** `TARGET_MISMATCH` (test dédié
`test_hmm_regime_cluster_origin_pairing.py`, 6 tests).

### Verdicts (mse, refit 22, HMM K=2, 4 seeds — brut / dé-biaisé)

| Actif | h=1 | h=5 | h=10 |
|---|---|---|---|
| BTC | INCONCLUSIVE / INCONCLUSIVE | INCONCLUSIVE / NO BEATS | INCONCLUSIVE / NO BEATS (−99,0 % ; brut −28,3 %) |
| ETH | **BEATS / BEATS (+8,7 %)** | INCONCLUSIVE / NO BEATS | NO BEATS / NO BEATS (−66,2 %) |
| SOL | INCONCLUSIVE / **BEATS (+5,7 %)** | INCONCLUSIVE / INCONCLUSIVE | NO BEATS / NO BEATS |
| LTC | **BEATS / BEATS (+11,7 %)** | INCONCLUSIVE / INCONCLUSIVE | NO BEATS / NO BEATS |
| XRP | **BEATS / BEATS (+11,8 %)** | INCONCLUSIVE / INCONCLUSIVE | NO BEATS / NO BEATS (−100,9 %) |
| ADA | **BEATS / BEATS (+11,3 %)** | INCONCLUSIVE / INCONCLUSIVE | NO BEATS / NO BEATS |
| DOT | **BEATS / BEATS (+10,1 %)** | INCONCLUSIVE / INCONCLUSIVE | NO BEATS / NO BEATS |

Lecture en trois lignes :

1. **h=1 : 6/7 BEATS après dé-biais** (ETH, SOL, LTC, XRP, ADA, DOT, gains +5,7 % à +11,8 %).
   BTC reste INCONCLUSIVE — cohérent avec l'analyse de biais ci-dessus : la HAR BTC porte le
   biais OOS le plus fort du cluster (−0,227 à h=1, −0,450 à h=10), l'edge brut y était porté
   par la correction de cette baseline mal calée. SOL bascule INCONCLUSIVE → BEATS sur la jambe
   de précision : son modèle de régime est *plus* biaisé que sa baseline (+0,115 vs +0,071),
   et le recentrage rend l'avantage de précision significatif.
2. **h=5 : uniformément INCONCLUSIVE** (7/7, sauf BTC/ETH dé-biaisés NO BEATS qui amorcent la
   dégradation longue). Aucun actif ne paie le modèle de régime à cet horizon.
3. **h=10 : NO BEATS uniforme (7/7), dégradations −42,9 % à −100,9 %** après dé-biais. La
   conclusion « le modèle de régime est nuisible aux horizons longs » n'était pas un artefact
   BTC/ETH : elle est **structurelle sur l'univers cluster**.

**Rapport de biais** (biais OOS moyen par cellule, modèle vs baseline) : BTC est le seul actif
où le régime réduit le biais (−0,181 vs −0,227 à h=1) ; sur les 5 actifs yfinance le modèle de
régime est systématiquement *plus* biaisé que sa baseline (ex. SOL +0,218 vs +0,163 à h=10) —
leurs edges h=1 sont donc portés par la **précision**, pas par le biais, ce que la jambe
recentrée confirme (dm_centered_p < 0,012 sur toutes les cellules BEATS).

**Artefacts** — manifeste compact in-repo `scripts/results/m5_hmm_regime_cluster_aligned.json`
(verdicts, alignement, SHA-256 par cellule) ; JSON complet et séries par
observation hors dépôt : `G:\Mon Drive\MyIA\Dev\Trading\ML-Training-Pipeline\m5_hmm_regime_cluster_full.json`
(+ `m5_hmm_regime_series.csv`), précédent #18664.

## Key findings

*(Lecture d'origine, Cycle 25, sur MSE bruts. Conservée telle quelle ; la section « Re-validation
hors biais » ci-dessus précise les points 1 et 2 et confirme le point 3.)*

1. **ETH h=1: only significant win.** The regime-switching HAR beats classic HAR by 9.6%
   (4/4 seeds, p<0.005). ETH's shorter data history (1495 RV days) with more pronounced
   regime shifts benefits from the conditional model at the shortest horizon.

2. **BTC h=1: promising but not conclusive.** 3/4 seeds show 8-10% improvement (p<10^-5),
   but seed 7 produces near-zero improvement (0.1%). The aggregate verdict is INCONCLUSIVE.
   The HMM initialization sensitivity is a concern.

3. **Longer horizons: regime model is harmful.** At h=5 and h=10, the regime-switching
   model is significantly WORSE than classic HAR for both coins. The MSE degradation grows
   with horizon: BTC h=10 sees 28% worse, ETH h=10 sees 53% worse. The interaction terms
   introduce noise that compounds over multi-step forecasts.

4. **HMM initialization sensitivity is severe.** Different seeds produce wildly different
   regime decompositions. Seed 0 and 99 might classify 60%/40% low/high, while seed 7
   might produce 80%/20%. This variance translates directly into prediction instability.

5. **The regime interaction approach has a fundamental flaw at longer horizons.** The
   iterative h-step prediction uses a single regime indicator R for ALL forecast steps.
   But the regime may switch during the forecast window. The model cannot adapt mid-forecast,
   leading to compounding errors.

## Conclusion

**Verdict hors biais (2026-09-02, Epic #1454) : `confirmed` sur ETH h=1, `NO BEATS` 4/6, INCONCLUSIVE
1/6.** Le seul BEATS de M5 tient une fois la baseline dé-biaisée (+8,7 %, 4/4 seeds, 4,1σ,
`dm_p_median` 1,14e-05) — contrairement à M15, réfuté par le même instrument (`refuted-de-biased`
3/3, #11041). Le verdict brut ci-dessous reste exact et n'est pas révisé ; la relecture hors biais
le **précise** : BTC h=1 n'était pas « prometteur mais sensible aux graines », son edge était à 82 %
le biais de la HAR ; et la dégradation à h≥5 est plus sévère qu'elle ne le paraissait.

**M5 verdict (brut, machine 4 états #14388) : 1/6 BEATS (ETH h=1), 1/6 NO BEATS (ETH h=10),
4/6 INCONCLUSIVE (BTC h=1 + BTC/ETH h=5/h=10).** La convention antérieure (Cycle 25) « 1/6 BEATS,
5/6 INCONCLUSIVE » est remplacée par la machine unifiée `_aggregate_state` ; la convention
unanimité stricte fait que seules les configurations à **4/4 d'un seul côté avec `dm_p_median < 0.05`**
basculent en BEATS ou NO BEATS — les 3 configs à 3/4 BEATEN + 1 INCONCLUSIVE restent INCONCLUSIVE.
La lecture dérivée `DEGRADE` est supprimée du notebook (la machine unifiée la fait sortir
automatiquement quand les 4 graines sont unanimes BEATEN).

The HMM regime-switching HAR provides marginal improvement at h=1 for some configurations
but is actively harmful at h>=5. The approach adds complexity (8 coefficients + HMM
decoding) without consistent benefit. The classic 3-parameter HAR remains the better
default for most use cases.

Compared to M3b (asymmetric HAR, 3/21 BEATS, BTC-only) and M4 (DLinear, 5/21 BEATS),
the HMM regime approach (1/6 BEATS) is the weakest extension. The DLinear model, which
learns optimal temporal weights without explicit regime decomposition, is strictly superior.

## References

- Hamilton, J.D. (1989) "A New Approach to the Economic Analysis of Nonstationary
  Time Series and the Business Cycle", Econometrica 57, 357-384.
- Corsi, F. (2009) "A Simple Approximate Long-Memory Model of Realized Volatility",
  Journal of Financial Econometrics 7, 174-196.
