← Retour aux articles
July 11, 2026
5 min de lecture

GARCH asymétrique et à queues épaisses : EGARCH, GJR et Student-t

#volatility
#GARCH
#EGARCH
#risk
#VaR
#crypto
#algorithmic-trading

Dans la Partie 1 de cette série, nous avons construit le GARCH(1,1) depuis les fondations : l'intuition du clustering de volatilité, la récursion de variance conditionnelle, l'estimation par maximum de vraisemblance, la prévision, et les diagnostics de résidus standards avec la bibliothèque arch. Si vous ne l'avez pas lue, commencez par là — cet article suppose que vous savez déjà ajuster et interpréter un GARCH(1,1) simple et ne reviendra pas sur les bases.

Le GARCH(1,1) simple est une bonne base et une mauvaise réponse finale. Il présente deux défauts structurels qu'il est bon marché d'ignorer dans un backtest et coûteux d'ignorer avec du capital réel. Premièrement, il est symétrique : le modèle réagit à une journée à +5%+5\% exactement comme à une journée à 5%-5\%, car le choc n'entre dans la récursion de variance que via son carré, εt12\varepsilon_{t-1}^2. La mise au carré fait disparaître le signe. Deuxièmement, il suppose des innovations gaussiennes : même après que le GARCH a absorbé le clustering de volatilité, les résidus standardisés de BTC et ETH sont visiblement à queues épaisses, et une vraisemblance gaussienne sous-évalue systématiquement la queue. Une VaR à 99% GARCH(1,1)-Normale sera enfreinte bien plus souvent qu'une fois sur cent.

Cet article corrige les deux défauts. Nous ajoutons l'asymétrie avec GJR-GARCH et EGARCH, et des queues épaisses avec les innovations Student-tt et skew-tt de Hansen. Puis nous faisons la chose qui rapporte réellement : transformer la distribution conditionnelle ajustée en une prévision de Value-at-Risk et d'Expected Shortfall à un pas, et backtester honnêtement cette prévision avec les tests de Kupiec et Christoffersen. Un modèle de volatilité qu'on ne teste jamais en risque n'est qu'une décoration.

L'effet de levier, et pourquoi les cryptos sont plus désordonnées

En actions, l'asymétrie porte un nom et une histoire. L'effet de levier (Black, 1976) : quand l'action d'une entreprise chute, son ratio dette/fonds propres augmente, les fonds propres deviennent mécaniquement plus risqués, et la volatilité augmente. Une mauvaise nouvelle augmente la volatilité future davantage qu'une bonne nouvelle de même ampleur. Empiriquement, c'est l'un des faits stylisés les plus robustes de la littérature sur la volatilité des actions.

Les cryptos n'ont ni fonds propres ni levier de bilan au sens comptable, mais une asymétrie de type effet de levier apparaît quand même la plupart du temps — pilotée par le désendettement forcé plutôt que par la comptabilité. Quand le BTC chute fortement, les prêts surcollatéralisés sont liquidés, les positions longues sur futures perpétuels sont fermées de force, le funding s'inverse, et la cascade nourrit la volatilité. Le mécanisme diffère donc, mais le signe rejoint souvent celui des actions : les mouvements baissiers font davantage grimper la volatilité.

La mise en garde importante : les cryptos sont plus désordonnées, et il faut traiter l'asymétrie comme une question empirique plutôt que comme une loi. Des mouvements haussiers violents — short squeezes, melt-up alimenté par le levier, gap d'approbation d'un ETF — peuvent eux aussi faire grimper la volatilité réalisée. Selon l'actif et la fenêtre d'échantillonnage, l'asymétrie estimée peut être forte, faible, ou occasionnellement de signe "inattendu". La discipline que cet article impose : ajuster le modèle asymétrique, examiner si le paramètre d'asymétrie est statistiquement significatif et dans la direction attendue, et ne garder le paramètre supplémentaire que s'il justifie sa place. Ne pas supposer que l'histoire des actions se transpose ; la tester.

Tester l'asymétrie avant de la modéliser

Le principe ci-dessus dit de "traiter l'asymétrie comme empirique" — donc avant d'ajuster un modèle asymétrique, effectuons un test formel peu coûteux pour savoir si l'asymétrie est même présente. Les tests de biais de signe d'Engle-Ng (1993) font exactement cela. On ajuste d'abord un GARCH(1,1) symétrique, on prend ses résidus standardisés au carré zt2z_t^2, et on les régresse sur des indicateurs du signe et de la taille du choc précédent :

zt2=a0+a1St1+a2St1εt1+a3St1+εt1+utz_t^2 = a_0 + a_1 S_{t-1}^- + a_2 S_{t-1}^- \varepsilon_{t-1} + a_3 S_{t-1}^+ \varepsilon_{t-1} + u_t

St1=1{εt1<0}S_{t-1}^- = \mathbf{1}\{\varepsilon_{t-1} < 0\} et St1+=1St1S_{t-1}^+ = 1 - S_{t-1}^-. La logique : si le modèle symétrique a déjà capturé toute l'information pertinente, le signe et la taille du choc d'hier ne devraient pas prédire le résidu au carré d'aujourd'hui, donc a1=a2=a3=0a_1 = a_2 = a_3 = 0. Les tests tt individuels sont les tests de biais de signe (a1a_1), de biais de taille négative (a2a_2) et de biais de taille positive (a3a_3) ; un test FF joint sur les trois est le test omnibus. Un a1a_1 ou a2a_2 significatif indique que les chocs négatifs sont systématiquement mal évalués par le modèle symétrique — c'est le signal que GJR ou EGARCH aideront.

import statsmodels.api as sm

def sign_bias_test(symmetric_res):
    """Engle-Ng sign-bias tests on a fitted symmetric GARCH result."""
    z = symmetric_res.std_resid.dropna()
    z2 = (z ** 2).values[1:]
    eps_lag = z.values[:-1]                      # standardized shock proxy
    neg = (eps_lag < 0).astype(float)
    X = np.column_stack([
        np.ones_like(eps_lag),                   # intercept
        neg,                                     # sign bias
        neg * eps_lag,                           # negative size bias
        (1 - neg) * eps_lag,                     # positive size bias
    ])
    ols = sm.OLS(z2, X).fit()
    names = ["const", "sign_bias", "neg_size_bias", "pos_size_bias"]
    for nm, coef, t, p in zip(names, ols.params, ols.tvalues, ols.pvalues):
        print(f"{nm:16s} coef={coef:+.4f}  t={t:+.2f}  p={p:.3f}")
    print(f"Joint F p-value: {ols.f_pvalue:.4f}")
    return ols

sign_bias_test(models["GARCH-N"])

Si le test FF joint est non significatif, vous avez une licence empirique pour rester symétrique et économiser deux paramètres. S'il est significatif — le cas fréquent pour BTC/ETH — passez à GJR/EGARCH l'esprit tranquille, sachant que vous modélisez une caractéristique réelle et non du bruit. C'est la discipline empirique exigée plus haut : ne pas supposer l'histoire de l'effet de levier des actions, la tester.

GJR-GARCH : l'asymétrie via un terme de seuil

Le modèle de Glosten-Jagannathan-Runkle (1993) — parfois appelé TGARCH ou GARCH à seuil — est la plus petite modification possible du GARCH(1,1) permettant aux bonnes et mauvaises nouvelles d'avoir des effets différents. Rappelons la récursion de variance conditionnelle symétrique de la Partie 1 :

σt2=ω+αεt12+βσt12\sigma_t^2 = \omega + \alpha\,\varepsilon_{t-1}^2 + \beta\,\sigma_{t-1}^2

GJR ajoute un seul terme de seuil : une dose supplémentaire de variance qui s'active uniquement après un choc négatif.

σt2=ω+αεt12+γIt1εt12+βσt12\sigma_t^2 = \omega + \alpha\,\varepsilon_{t-1}^2 + \gamma\,I_{t-1}\,\varepsilon_{t-1}^2 + \beta\,\sigma_{t-1}^2

It1I_{t-1} est l'indicatrice

It1={1if εt1<00if εt10I_{t-1} = \begin{cases} 1 & \text{if } \varepsilon_{t-1} < 0 \\ 0 & \text{if } \varepsilon_{t-1} \geq 0 \end{cases}

Lisez la récursion cas par cas. Après un choc positif (εt10\varepsilon_{t-1} \geq 0), l'indicatrice vaut zéro et l'impact du choc au carré sur la variance de la période suivante est simplement α\alpha. Après un choc négatif, l'indicatrice vaut un et l'impact est α+γ\alpha + \gamma. Le paramètre γ\gamma résume à lui seul toute l'histoire de l'asymétrie :

  • γ>0\gamma > 0 : les chocs négatifs augmentent la volatilité plus que des chocs positifs de même ampleur. C'est l'effet de levier, et c'est ce qu'on s'attend à trouver sur BTC/ETH la plupart du temps.
  • γ=0\gamma = 0 : le modèle retombe sur le GARCH(1,1) symétrique. Un test du rapport de vraisemblance ou un test tt sur γ\gamma est donc un test direct de l'existence même de l'asymétrie.
  • γ<0\gamma < 0 : les chocs positifs augmentent davantage la volatilité — le régime occasionnel de melt-up crypto. Rare, mais à ne pas exclure a priori.

Positivité et stationnarité

Comme σt2\sigma_t^2 reste construit de façon additive, chaque terme doit rester non négatif. Les conditions de positivité suffisantes sont

ω>0,α0,α+γ0,β0.\omega > 0, \quad \alpha \geq 0, \quad \alpha + \gamma \geq 0, \quad \beta \geq 0.

Notez que γ\gamma lui-même peut être négatif tant que α+γ0\alpha + \gamma \geq 0, de sorte que l'impact après une mauvaise nouvelle ne devient jamais négatif.

Pour la stationnarité de covariance, supposons que les innovations zt=εt/σtz_t = \varepsilon_t/\sigma_t sont standardisées avec une distribution symétrique autour de zéro, de sorte que P(εt1<0)=1/2P(\varepsilon_{t-1} < 0) = 1/2 et que l'indicatrice contribue en moyenne γ/2\gamma/2. La condition de stationnarité devient

α+β+12γ<1.\alpha + \beta + \tfrac{1}{2}\gamma < 1.

La variance inconditionnelle (de long terme) est alors

σˉ2=ω1αβ12γ.\bar{\sigma}^2 = \frac{\omega}{1 - \alpha - \beta - \tfrac{1}{2}\gamma}.

C'est l'analogue GJR du résultat de la Partie 1, σˉ2=ω/(1αβ)\bar{\sigma}^2 = \omega/(1-\alpha-\beta), avec le terme supplémentaire 12γ\tfrac{1}{2}\gamma qui rend compte de la contribution moyenne de la demi-vie de l'effet de levier. Si votre distribution d'innovation est asymétrique (skew-tt de Hansen, ci-dessous), le 1/21/2 est remplacé par la probabilité réelle que zt<0z_t < 0, mais 1/21/2 reste la référence standard utilisée pour la persistance rapportée.

EGARCH : modéliser le log de la variance, sans contraintes de positivité

GJR vous maintient dans un carcan de positivité de la variance : chaque combinaison de paramètres doit être vérifiée par rapport à des contraintes d'inégalité, ce qui est gênant pendant l'optimisation et pire encore lors d'un ré-ajustement glissant, quand une fenêtre s'égare occasionnellement dans une région infaisable. L'Exponential GARCH de Nelson (1991) contourne complètement ce problème en modélisant le logarithme de la variance conditionnelle. Comme logσt2\log \sigma_t^2 peut prendre n'importe quelle valeur réelle, σt2=exp(logσt2)\sigma_t^2 = \exp(\log \sigma_t^2) est automatiquement positif quels que soient les paramètres. Aucune contrainte à imposer.

Écrivons la récursion en fonction de l'innovation standardisée zt1=εt1/σt1z_{t-1} = \varepsilon_{t-1}/\sigma_{t-1} :

logσt2=ω+βlogσt12+α(zt1Ezt1)+γzt1\log \sigma_t^2 = \omega + \beta \log \sigma_{t-1}^2 + \alpha\bigl(|z_{t-1}| - \mathbb{E}|z_{t-1}|\bigr) + \gamma\, z_{t-1}

Deux termes portent le choc, et les séparer est toute l'idée :

  • Le terme de magnitude α(zt1Ezt1)\alpha(|z_{t-1}| - \mathbb{E}|z_{t-1}|) répond à la taille du choc, signe retiré. Soustraire Ezt1\mathbb{E}|z_{t-1}| le centre de sorte qu'un choc de magnitude moyenne ne contribue en rien. Pour une loi normale standard, Ez=2/π0.7979\mathbb{E}|z| = \sqrt{2/\pi} \approx 0.7979 ; pour une Student-tt standardisée, la valeur absolue attendue est plus petite et dépend de ν\nu, mais arch gère cela en interne.
  • Le terme de signe γzt1\gamma\, z_{t-1} est l'asymétrie. Il est linéaire dans l'innovation signée, de sorte qu'un zt1z_{t-1} négatif pousse logσt2\log\sigma_t^2 dans la direction opposée à un zt1z_{t-1} positif.

La convention de signe compte et fait souvent trébucher. Dans cette paramétrisation, l'effet de levier (une mauvaise nouvelle augmente la volatilité) correspond à γ<0\gamma < 0 : un choc négatif zt1<0z_{t-1} < 0 rend alors γzt1>0\gamma z_{t-1} > 0, augmentant le log-variance. C'est le signe opposé du γ>0\gamma > 0 de GJR. Vérifiez toujours la documentation propre au modèle plutôt que de supposer la convention ; arch rapporte EGARCH avec son propre signe, et nous le vérifions ci-dessous à l'aide d'une courbe d'impact des nouvelles plutôt que de nous fier à notre mémoire.

Comme tout est additif en logarithmes, la persistance d'un EGARCH(1,1) est régie par le seul coefficient autorégressif β\beta sur logσt12\log\sigma_{t-1}^2 ; la stationnarité exige seulement β<1|\beta| < 1. C'est une condition bien plus propre que l'inégalité de GJR, et c'est un avantage pratique réel quand on ré-ajuste sur des fenêtres glissantes.

Une subtilité qui mérite d'être énoncée : la réponse d'EGARCH aux chocs est exponentielle dans l'innovation (on exponentie à la fin), alors que GJR est quadratique. EGARCH réagit donc plus violemment aux gros chocs — un atout en crypto, où les événements de queue sont ceux qui comptent, mais aussi une raison pour laquelle EGARCH peut occasionnellement produire des prévisions de variance implausiblement grandes après une journée atypique. Aucun des deux n'est universellement meilleur ; on choisit sur la base de l'ajustement hors échantillon et des backtests de risque, ce qui est tout l'objet de cette série.

La courbe d'impact des nouvelles

La façon la plus nette de voir la différence entre GARCH symétrique, GJR et EGARCH est la courbe d'impact des nouvelles (news impact curve, Engle et Ng, 1993) : on fixe σt1\sigma_{t-1} à son niveau de long terme et on trace la variance conditionnelle de la période suivante σt2\sigma_t^2 en fonction du dernier choc εt1\varepsilon_{t-1}. Elle répond à la question : "étant donné un choc de cette taille et de ce signe, de combien le modèle augmente-t-il la volatilité de demain ?"

  • Le GARCH symétrique produit une parabole symétrique centrée en zéro. Un choc de 5%-5\% et un choc de +5%+5\% atteignent la même hauteur. C'est précisément le défaut que nous corrigeons.
  • GJR produit une parabole avec un coude en zéro — plus raide à gauche (chocs négatifs) qu'à droite quand γ>0\gamma > 0. Les deux moitiés ont des courbures respectives α+γ\alpha+\gamma et α\alpha.
  • EGARCH produit un V asymétrique et exponentiel : les deux branches ont des pentes différentes à cause du terme γz\gamma z, et l'ensemble se courbe plus rapidement qu'une parabole à cause de l'exponentiation finale.

Nous traçons les trois courbes à partir des paramètres ajustés plus loin, dans la section implémentation — c'est le diagnostic le plus utile pour communiquer ce que l'asymétrie apporte.

Queues épaisses : innovations Student-t et skew-t

L'asymétrie corrige la réponse du modèle au signe des chocs. Elle ne change rien à la distribution des chocs eux-mêmes. Le GARCH simple suppose ztN(0,1)z_t \sim \mathcal{N}(0,1), et cette hypothèse est presque toujours fausse pour les cryptos. Même après que le GARCH a retiré le clustering de volatilité, les résidus standardisés zt=εt/σtz_t = \varepsilon_t / \sigma_t conservent un excès de kurtosis — ils sont à queues épaisses. Une vraisemblance gaussienne, qui s'ajuste sur les épaules de la distribution, sous-estime la fréquence réelle à laquelle survient une journée standardisée à 44, 55, ou 66 écarts-types.

La conséquence pour le risque est directe. Une VaR gaussienne à 99% utilise le quantile Φ1(0.01)2.326\Phi^{-1}(0.01) \approx -2.326, et prédit donc VaR0.992.326σt\text{VaR}_{0.99} \approx 2.326\,\sigma_t. Si la vraie distribution standardisée est une Student-tt avec, disons, ν=5\nu = 5 degrés de liberté, le vrai quantile à 1% est proche de 3.36-3.36 — la VaR gaussienne est optimiste d'environ 44%44\% à ce niveau de confiance. Vous la dépasserez bien plus souvent qu'une fois sur cent et serez systématiquement surpris par des journées "impossibles". Ce n'est pas une particularité des cryptos ; Bollerslev (1987) a introduit le tt-GARCH précisément parce que les résidus des actions et du FX montraient les mêmes queues épaisses. Les cryptos ne font qu'exacerber le même problème.

Student-t standardisée

La densité de Student-tt possède un paramètre de degrés de liberté ν>2\nu > 2 qui contrôle l'épaisseur des queues : un petit ν\nu signifie des queues épaisses, et quand ν\nu \to \infty la tt converge vers la loi gaussienne. Le piège est que la distribution tνt_\nu brute a une variance ν/(ν2)1\nu/(\nu-2) \neq 1, donc il faut la standardiser à variance unitaire avant de l'utiliser comme innovation — sinon le "σt\sigma_t" dans la récursion GARCH ne serait pas réellement l'écart-type conditionnel.

L'innovation Student-tt standardisée à variance unitaire a pour densité

f(z;ν)=Γ ⁣(ν+12)π(ν2)  Γ ⁣(ν2)(1+z2ν2)ν+12,ν>2.f(z;\nu) = \frac{\Gamma\!\left(\frac{\nu+1}{2}\right)}{\sqrt{\pi(\nu-2)}\;\Gamma\!\left(\frac{\nu}{2}\right)}\left(1 + \frac{z^2}{\nu-2}\right)^{-\frac{\nu+1}{2}}, \qquad \nu > 2.

Remarquez le (ν2)(\nu-2) à l'intérieur — c'est la standardisation, le redimensionnement qui assure Var(z)=1\mathrm{Var}(z)=1. La contribution à la log-vraisemblance d'une observation, étant donné la variance conditionnelle GARCH σt2\sigma_t^2 et zt=εt/σtz_t = \varepsilon_t/\sigma_t, est

t=logΓ ⁣(ν+12)logΓ ⁣(ν2)12log(π(ν2))12logσt2ν+12log ⁣(1+zt2ν2).\ell_t = \log\Gamma\!\left(\tfrac{\nu+1}{2}\right) - \log\Gamma\!\left(\tfrac{\nu}{2}\right) - \tfrac{1}{2}\log\bigl(\pi(\nu-2)\bigr) - \tfrac{1}{2}\log\sigma_t^2 - \frac{\nu+1}{2}\log\!\left(1 + \frac{z_t^2}{\nu-2}\right).

Le terme 12logσt2-\tfrac{1}{2}\log\sigma_t^2 est le jacobien de la transformation de εt\varepsilon_t vers ztz_t — le même terme que celui vu dans la vraisemblance GARCH gaussienne de la Partie 1. Seule la forme change. Maximiser tt\sum_t \ell_t conjointement sur les paramètres GARCH et ν\nu est exactement ce que fait arch quand vous passez dist='t'.

Le ν\nu estimé est lui-même informatif. Pour les rendements journaliers BTC/ETH, on se retrouve typiquement dans la plage ν36\nu \approx 3\text{–}6 — des queues épaisses, mais avec une variance finie (ce qui exige ν>2\nu > 2) et généralement une kurtosis finie (ce qui exige ν>4\nu > 4). Si votre ν\nu ajusté descend sous 4, sachez que la kurtosis d'échantillon est techniquement infinie dans le modèle et que certains estimateurs deviennent instables ; c'est un signal pour examiner de près les valeurs aberrantes et la qualité des données.

Skew-t de Hansen

La Student-tt est à queues épaisses mais reste symétrique — les queues gauche et droite sont également lourdes. Les résidus des rendements crypto sont souvent aussi asymétriques : la queue gauche (les krachs) est plus lourde que la droite. La skew-tt de Hansen (1994) généralise la tt standardisée avec un paramètre d'asymétrie λ(1,1)\lambda \in (-1, 1) en plus de ν\nu :

f(z;ν,λ)={bc(1+1ν2(bz+a1λ)2)ν+12z<a/bbc(1+1ν2(bz+a1+λ)2)ν+12za/bf(z;\nu,\lambda) = \begin{cases} b\,c\left(1 + \dfrac{1}{\nu-2}\left(\dfrac{bz+a}{1-\lambda}\right)^2\right)^{-\frac{\nu+1}{2}} & z < -a/b \\[2mm] b\,c\left(1 + \dfrac{1}{\nu-2}\left(\dfrac{bz+a}{1+\lambda}\right)^2\right)^{-\frac{\nu+1}{2}} & z \geq -a/b \end{cases}

où les constantes a=4λcν2ν1a = 4\lambda c\,\frac{\nu-2}{\nu-1}, b2=1+3λ2a2b^2 = 1 + 3\lambda^2 - a^2, et c=Γ(ν+12)π(ν2)Γ(ν2)c = \frac{\Gamma(\frac{\nu+1}{2})}{\sqrt{\pi(\nu-2)}\,\Gamma(\frac{\nu}{2})} sont choisies de sorte que zz ait une moyenne nulle et une variance unitaire pour tout (ν,λ)(\nu,\lambda) valide. La distribution se scinde en z=a/bz = -a/b, avec une mise à l'échelle différente dans chaque partie pour concentrer davantage de masse dans une queue.

Interprétation : λ<0\lambda < 0 donne une distribution asymétrique à gauche (partie basse plus lourde), ce qui est le résultat habituel pour les cryptos et ce qu'on s'attendrait à associer à un effet de levier. λ=0\lambda = 0 retrouve la Student-tt symétrique, donc un test de λ=0\lambda = 0 indique si le terme d'asymétrie apporte quelque chose. Dans arch, c'est dist='skewt', qui estime à la fois ν\nu et λ\lambda. Le bénéfice est une VaR dont le quantile de queue gauche est honnêtement plus lourd que celui de la queue droite — exactement ce que l'on veut quand les pertes que l'on cherche à survivre sont asymétriques. Cela rejoint directement l'asymétrie entre perte et profit dans les résultats de position : un drawdown de x%x\% nécessite plus de x%x\% pour se rétablir, donc mal modéliser la queue gauche coûte plus cher que mal modéliser la droite.

Implémentation en Python

Nous ajustons maintenant tout cela avec la bibliothèque arch. La mise en place reproduit celle de la Partie 1 : récupérer les rendements journaliers, multiplier par 100 pour le conditionnement numérique (les optimiseurs GARCH se comportent mal quand les rendements sont d'ordre O(0.01)O(0.01)), et ajuster avec une moyenne constante. Si vous voulez de l'intraday ou un modèle de moyenne différent, la mécanique est identique.

Configuration et données

import numpy as np
import pandas as pd
from arch import arch_model
from arch.univariate import GARCH, EGARCH, ConstantMean, StudentsT, SkewStudent
from scipy import stats

def fetch_returns(symbol="BTC-USD", start="2019-01-01", end="2025-12-31"):
    """Daily log returns, in percent (scaled x100 for the optimizer)."""
    import yfinance as yf
    px = yf.download(symbol, start=start, end=end)["Close"].dropna()
    ret = 100.0 * np.log(px / px.shift(1)).dropna()
    ret.name = symbol
    return ret

r = fetch_returns("BTC-USD")
print(f"{len(r)} daily observations, "
      f"annualized vol ~ {r.std() * np.sqrt(365):.0f}%")

Les cryptos se négocient 24h/24 et 7j/7, donc on annualise avec 365, pas 252 — une petite source de confusion récurrente quand on compare un Sharpe ou une vol crypto aux chiffres d'un desk actions.

Ajuster quatre modèles

Le schéma dans arch : vol='Garch' avec p=1, q=1 donne le GARCH symétrique ; ajouter o=1 active le terme de seuil GJR ; vol='EGARCH' bascule sur le modèle en log-variance. La distribution d'innovation se fixe avec dist : 'normal', 't', 'skewt'.

def fit(returns, vol="Garch", p=1, o=0, q=1, dist="normal"):
    am = arch_model(returns, mean="Constant",
                    vol=vol, p=p, o=o, q=q, dist=dist)
    res = am.fit(disp="off")
    return res

models = {
    "GARCH-N":    fit(r, vol="Garch",  o=0, dist="normal"),  # Part 1 baseline
    "GJR-t":      fit(r, vol="Garch",  o=1, dist="t"),        # asymmetry + fat tails
    "EGARCH-t":   fit(r, vol="EGARCH", o=1, dist="t"),        # log-variance asymmetry
    "GJR-skewt":  fit(r, vol="Garch",  o=1, dist="skewt"),    # + skew
}

for name, res in models.items():
    print(f"\n===== {name} =====")
    print(res.summary().tables[1])   # parameter table

Pour vol='EGARCH', l'argument o contrôle le terme asymétrique (γz\gamma z) et p/q contrôlent les termes de magnitude et de retard ; o=1, p=1, q=1 est l'EGARCH(1,1) standard. Un piège : les noms des paramètres EGARCH dans arch sont les mêmes lettres, mais la convention de signe sur le terme d'asymétrie est celle de Nelson, de sorte qu'une estimation négative correspond à l'effet de levier. Nous le vérifions à partir de la courbe d'impact des nouvelles plutôt que de nous fier à la mémoire.

Lire l'ajustement GJR

Un tableau de paramètres GJR-tt ressemble à peu près à ceci (valeurs illustratives, pas une expérience rapportée — réajustez sur vos propres données) :

                  coef    std err       t      P>|t|
omega           0.0480     0.017     2.82     0.005
alpha[1]        0.0620     0.018     3.44     0.001
gamma[1]        0.0910     0.028     3.25     0.001
beta[1]         0.8850     0.021    42.1      0.000
nu              4.30       0.55      7.82     0.000

Comment le lire :

  • gamma[1] = 0.091 avec une statistique tt supérieure à 3 est un effet de levier statistiquement significatif. Après un choc négatif, l'impact du choc au carré est α+γ=0.062+0.091=0.153\alpha + \gamma = 0.062 + 0.091 = 0.153 ; après un choc positif, il est simplement α=0.062\alpha = 0.062. Une mauvaise nouvelle fait bouger la volatilité de ce modèle environ 2.52.5 fois plus qu'une bonne nouvelle de même taille.
  • nu = 4.3 confirme des queues épaisses — loin de la loi gaussienne (ν\nu \to \infty), et assez bas pour que le quatrième moment soit à peine fini. Une VaR gaussienne sur cette série serait sérieusement optimiste.
  • La persistance est α+β+12γ=0.062+0.885+0.04550.993\alpha + \beta + \tfrac{1}{2}\gamma = 0.062 + 0.885 + 0.0455 \approx 0.993 — très élevée, comme d'habitude pour les cryptos journalières : les chocs se dissipent lentement et la volatilité est fortement groupée.

La ligne la plus importante à vérifier est celle de γ\gamma. Si sa pp-valeur est grande, le terme asymétrique ne justifie pas sa place sur cet actif et cette fenêtre, et il faut préférer le modèle symétrique plus simple. C'est une discipline de sélection de modèle, pas une décoration — voir plus loin.

Comparer les modèles par critères d'information

La log-vraisemblance s'améliore toujours quand on ajoute des paramètres, donc on ne peut pas sélectionner sur la seule log-vraisemblance. On utilise l'AIC/BIC, qui pénalisent le nombre de paramètres (le BIC plus agressivement) :

def compare(models: dict) -> pd.DataFrame:
    rows = []
    for name, res in models.items():
        rows.append({
            "model": name,
            "n_params": len(res.params),
            "loglik": res.loglikelihood,
            "AIC": res.aic,
            "BIC": res.bic,
        })
    df = pd.DataFrame(rows).set_index("model")
    return df.sort_values("BIC")

print(compare(models))

Règles empiriques d'interprétation : une amélioration du BIC de plus de ~6 par rapport à la base est une preuve solide que la structure supplémentaire est réelle ; une différence de 1 à 2 est du bruit. Si GJR-t bat GARCH-N de 30 points de BIC ou plus mais que GJR-skewt ne bat GJR-t que d'un point, gardez la tt et abandonnez l'asymétrie — le paramètre d'asymétrie ne se justifie pas sur ces données. Ne lisez pas l'AIC/BIC comme un substitut à la validation hors échantillon ; ils récompensent l'ajustement in-sample corrigé de la complexité, ce qui est nécessaire mais pas suffisant. Le vrai test est le backtest de VaR et, en définitive, l'évaluation walk-forward.

Tracer la courbe d'impact des nouvelles

C'est le graphique décisif — il rend l'asymétrie visible et vérifie la convention de signe d'EGARCH.

import matplotlib.pyplot as plt

def news_impact_curve(res, shock_grid):
    """
    Next-period conditional variance as a function of the last shock,
    holding sigma_{t-1} at the model's unconditional level.
    Works for symmetric GARCH, GJR (o=1), and EGARCH.
    """
    p = res.params
    vol_name = res.model.volatility.__class__.__name__
    sigma2_bar = np.mean(res.conditional_volatility ** 2)

    omega = p["omega"]
    alpha = p.get("alpha[1]", 0.0)
    gamma = p.get("gamma[1]", 0.0)
    beta  = p.get("beta[1]", 0.0)

    if vol_name == "EGARCH":
        sig_prev = np.sqrt(sigma2_bar)
        z = shock_grid / sig_prev
        E_abs = np.sqrt(2 / np.pi)   # approx; arch uses the fitted dist's E|z|
        log_s2 = (omega + beta * np.log(sigma2_bar)
                  + alpha * (np.abs(z) - E_abs) + gamma * z)
        return np.exp(log_s2)
    else:
        ind = (shock_grid < 0).astype(float)
        return omega + (alpha + gamma * ind) * shock_grid**2 + beta * sigma2_bar

shocks = np.linspace(-8, 8, 401)   # daily % shocks
plt.figure(figsize=(8, 5))
for name in ["GARCH-N", "GJR-t", "EGARCH-t"]:
    nic = news_impact_curve(models[name], shocks)
    plt.plot(shocks, nic, label=name, lw=2)
plt.axvline(0, color="gray", lw=0.8, ls="--")
plt.xlabel("Last shock  $\\varepsilon_{t-1}$  (daily %)")
plt.ylabel("Next-period conditional variance  $\\sigma_t^2$")
plt.title("News impact curve: symmetric vs GJR vs EGARCH (BTC)")
plt.legend()
plt.tight_layout()

Quand vous exécutez ceci, la courbe symétrique GARCH-N est une parabole propre centrée en zéro — un choc de 6%-6\% et de +6%+6\% donnent une variance identique. GJR-t est une parabole avec un coude à l'origine, plus haute sur la branche gauche. EGARCH-t est le V exponentiel, et si sa branche gauche se situe au-dessus de la droite, vous avez confirmé l'effet de levier et la convention de signe d'un seul coup d'œil. Si la branche gauche d'EGARCH se situe en dessous de la droite, soit γ\gamma a été estimé positif (un régime de vol haussière), soit vous avez le signe inversé — le graphique vous le dit sans qu'il soit besoin de deviner.

Une comparaison côte à côte des quatre modèles

Avant de passer au risque, il est utile de mettre les quatre modèles côte à côte. Chaque ligne est une décision de conception, et les colonnes montrent ce que cette décision coûte et apporte.

Property GARCH-N GJR-t EGARCH-t GJR-skewt
Asymétrie (signe du choc) aucune seuil γIε2\gamma I\varepsilon^2 signée γz\gamma z seuil γIε2\gamma I\varepsilon^2
Forme de queue de l'innovation gaussienne Student-tt Student-tt skew-tt
Asymétrie dans l'innovation non non non oui (λ\lambda)
Contraintes de positivité oui oui (α+γ0\alpha+\gamma\ge0) aucune (forme log) oui
Condition de stationnarité α+β<1\alpha+\beta<1 α+β+12γ<1\alpha+\beta+\tfrac12\gamma<1 β<1\lvert\beta\rvert<1 α+β+P(z<0)γ<1\alpha+\beta+P(z<0)\gamma<1
Paramètres supplémentaires vs base 0 γ,ν\gamma,\nu γ,ν\gamma,\nu γ,ν,λ\gamma,\nu,\lambda
Verdict crypto typique échoue au backtest VaR fort, robuste fort, robuste marginal par rapport à GJR-t

Le schéma à retenir : le saut de la colonne 1 à la colonne 2 — ajouter à la fois l'asymétrie et les queues épaisses en une fois — est là où réside presque toute l'amélioration du calibrage du risque. Les raffinements suivants (la forme fonctionnelle d'EGARCH, le terme d'asymétrie) sont réels mais de second ordre, et sur de nombreuses séries crypto ils se noient dans le bruit. Consacrez votre budget de modélisation au premier saut et restez sceptique sur le reste.

Application au risque : VaR et Expected Shortfall

Ajuster un modèle de volatilité plus sophistiqué ne vaut la peine que s'il améliore une décision. La décision la plus nette à améliorer est la prévision de risque de queue à un pas : à quel point demain peut-il être mauvais ? Nous produisons une Value-at-Risk et une Expected Shortfall (alias VaR conditionnelle, que le pipeline de portefeuille HRP/CVaR utilise comme objectif) à un jour directement à partir de la prévision GARCH-tt/skew-tt ajustée.

De la distribution conditionnelle à la VaR

La mécanique GARCH fournit une prévision à un pas de la moyenne conditionnelle μt+1\mu_{t+1} et de l'écart-type conditionnel σt+1\sigma_{t+1}. Le rendement est modélisé comme rt+1=μt+1+σt+1zt+1r_{t+1} = \mu_{t+1} + \sigma_{t+1} z_{t+1} avec zt+1z_{t+1} tiré de la distribution standardisée ajustée (gaussienne, tt, ou skew-tt). Le quantile α\alpha du rendement est donc simplement une transformation affine du quantile α\alpha de la distribution standardisée :

VaRα(t+1)=(μt+1+σt+1Fz1(1α))\text{VaR}_{\alpha}(t+1) = -\Bigl(\mu_{t+1} + \sigma_{t+1}\, F_z^{-1}(1-\alpha)\Bigr)

Fz1F_z^{-1} est le quantile (inverse de la CDF) de l'innovation standardisée et où le signe moins de tête suit la convention voulant que la VaR soit une perte exprimée en nombre positif. Pour une VaR à 99%, α=0.99\alpha = 0.99 et l'on injecte Fz1(0.01)F_z^{-1}(0.01). Tout le bénéfice de la tt/skew-tt apparaît ici : Fz1(0.01)F_z^{-1}(0.01) est plus négatif que le 2.326-2.326 gaussien, donc la VaR est honnêtement plus grande.

Expected Shortfall

La VaR donne le seuil ; elle ne dit rien de la gravité du dépassement quand il se produit. L'Expected Shortfall — la perte moyenne conditionnelle au fait de dépasser la VaR — le fait, et elle est cohérente (sous-additive), raison pour laquelle elle est la mesure de risque derrière l'optimisation CVaR et pourquoi Bâle y est passé. Pour un modèle de type location-scale,

ESα(t+1)=(μt+1+σt+1E ⁣[zzFz1(1α)]).\text{ES}_{\alpha}(t+1) = -\Bigl(\mu_{t+1} + \sigma_{t+1}\, \mathbb{E}\!\left[z \mid z \leq F_z^{-1}(1-\alpha)\right]\Bigr).

Le terme d'espérance de queue conditionnelle E[zzq]\mathbb{E}[z \mid z \le q] possède des formes closes pour les distributions standards. Pour la gaussienne, avec q=Φ1(1α)q = \Phi^{-1}(1-\alpha),

E[zzq]=ϕ(q)1α,\mathbb{E}[z \mid z \le q] = -\frac{\phi(q)}{1-\alpha},

ϕ\phi est la densité de la loi normale standard. Pour la Student-tt standardisée avec ν\nu degrés de liberté et q=tν1(1α)q = t_\nu^{-1}(1-\alpha) (sur l'échelle standardisée), l'espérance de queue est

E[zzq]=ν+q2ν1gν(q)1α,\mathbb{E}[z \mid z \le q] = -\frac{\nu + q^2}{\nu - 1}\cdot\frac{g_\nu(q)}{1-\alpha},

gνg_\nu est la densité de la tt standardisée. L'Expected Shortfall de la tt dépasse celle de la gaussienne davantage que ne le fait la VaR, parce que la queue de la tt n'est pas seulement plus éloignée — elle est plus épaisse, donc la perte moyenne au-delà du seuil est disproportionnellement grande. Cet écart supplémentaire est le chiffre qu'un modèle gaussien vous cache.

Calculer la VaR et l'ES à partir d'un modèle arch ajusté

Les distributions de arch exposent une méthode ppf (quantile), ce qui permet d'obtenir directement le quantile standardisé sans avoir à tout rederiver. Pour l'ES on intègre numériquement, ce qui est robuste et fonctionne uniformément entre normal/t/skewt.

from scipy import integrate

def var_es_forecast(res, alpha=0.99):
    """
    One-step-ahead VaR and ES at level alpha, on the same (x100) scale
    as the returns fed to the model. Divide by 100 for fractional units.
    """
    fc = res.forecast(horizon=1, reindex=False)
    mu = fc.mean.iloc[-1, 0]
    sigma = np.sqrt(fc.variance.iloc[-1, 0])

    dist = res.model.distribution          # StudentsT / SkewStudent / Normal
    dp = [res.params[k] for k in res.params.index
          if k in ("nu", "eta", "lambda", "lam")]

    z_q = dist.ppf(1 - alpha, dp) if dp else dist.ppf(1 - alpha)
    z_q = float(np.atleast_1d(z_q)[0])

    def pdf(z):
        arr = np.atleast_1d(z).astype(float)
        lp = dist.loglikelihood(dp, arr, np.ones_like(arr), individual=True) \
             if dp else dist.loglikelihood([], arr, np.ones_like(arr),
                                           individual=True)
        return np.exp(lp)

    num, _ = integrate.quad(lambda z: z * pdf(z), -30, z_q, limit=200)
    es_z = num / (1 - alpha)               # E[z | z <= z_q]

    var = -(mu + sigma * z_q)
    es  = -(mu + sigma * es_z)
    return {"mu": mu, "sigma": sigma, "z_q": z_q,
            "VaR": var, "ES": es}

for name in ["GARCH-N", "GJR-t", "GJR-skewt"]:
    out = var_es_forecast(models[name], alpha=0.99)
    print(f"{name:11s}  sigma={out['sigma']:.2f}%  "
          f"z_q={out['z_q']:+.2f}  "
          f"VaR99={out['VaR']:.2f}%  ES99={out['ES']:.2f}%")

La colonne z_q résume à elle seule toute l'histoire. Le modèle gaussien utilise zq2.33z_q \approx -2.33 ; la tt avec ν4.3\nu \approx 4.3 utilise quelque chose proche de 3.3-3.3 ; la skew-tt pousse le quantile gauche encore plus loin tout en resserrant le droit. Même σt+1\sigma_{t+1}, VaR nettement plus grande. Si vous avez fait tourner une VaR gaussienne sur des cryptos, voilà l'écart que vous absorbiez silencieusement.

Un pas versus plusieurs pas : une mise en garde

Tout ce qui précède est une prévision à un jour, et c'est là que la VaR GARCH est la plus nette. Deux éléments compliquent les horizons plus longs, et il faut les connaître avant d'extrapoler.

Premièrement, les prévisions de variance reviennent vers la moyenne. La variance conditionnelle à hh pas d'un GARCH stationnaire converge vers le niveau inconditionnel σˉ2\bar\sigma^2 quand hh croît, et la variance cumulée sur hh jours est la somme des prévisions à chaque pas — ce n'est pas h×σt+12h\times\sigma_{t+1}^2 sauf si la volatilité est à sa moyenne de long terme. La mise à l'échelle naïve en "racine carrée du temps" VaR(h)=hVaR(1)\text{VaR}(h) = \sqrt{h}\,\text{VaR}(1) ignore ce retour à la moyenne et se trompe précisément après un choc, quand on a le plus besoin du chiffre. Utilisez le chemin de variance multi-pas propre au modèle.

Deuxièmement, la distribution d'un rendement multi-jours n'a pas la même forme que l'innovation d'un seul jour. Sommer plusieurs chocs journaliers distribués selon une tt (à travers la récursion non linéaire du GARCH) ne redonne pas une distribution tt à l'horizon de hh jours ; il n'existe pas de forme close propre. Pour la VaR multi-jours, la voie honnête est la simulation : tirer des trajectoires d'innovations depuis la distribution standardisée ajustée, les faire passer dans la récursion GARCH pour obtenir des trajectoires de rendement simulées, les agréger en rendements à hh jours, et lire le quantile empirique. Cela gère aussi naturellement le cas skew-tt, pour lequel aucun quantile analytique multi-horizon n'existe. Les formules analytiques à un pas de cet article sont exactes ; traitez tout raccourci multi-pas comme une approximation à valider.

Backtester la VaR : Kupiec et Christoffersen

Une prévision de VaR est une affirmation probabiliste : "la perte dépassera ce seuil seulement (1α)(1-\alpha) des jours." On la teste en comptant les violations (jours où la perte réalisée dépasse la VaR prévue) sur une évaluation walk-forward et en vérifiant deux choses. D'abord, le taux de violation est-il correct ? Ensuite, les violations sont-elles indépendantes, ou se regroupent-elles (ce qui signifie que le modèle échoue précisément quand cela compte, pendant les pics de volatilité) ?

Soit It=1{pertet>VaRt}I_t = \mathbf{1}\{\text{perte}_t > \text{VaR}_t\} la séquence de violations, N=ItN = \sum I_t le nombre de violations sur TT jours, et π^=N/T\hat{\pi} = N/T le taux observé. Taux cible p=1αp = 1-\alpha.

Le test de couverture inconditionnelle de Kupiec (1995) vérifie que π^p\hat\pi \approx p via un rapport de vraisemblance :

LRuc=2log ⁣[pN(1p)TNπ^N(1π^)TN]    χ12.LR_{uc} = -2\log\!\left[\frac{p^{N}(1-p)^{T-N}}{\hat\pi^{N}(1-\hat\pi)^{T-N}}\right] \;\sim\; \chi^2_1.

Le test d'indépendance de Christoffersen (1998) vérifie qu'une violation aujourd'hui n'est pas prédite par une violation hier. Soit nijn_{ij} le nombre de transitions de l'état ii vers l'état jj dans la séquence de violations, π01=n01/(n00+n01)\pi_{01} = n_{01}/(n_{00}+n_{01}), π11=n11/(n10+n11)\pi_{11} = n_{11}/(n_{10}+n_{11}), et π=(n01+n11)/T\pi = (n_{01}+n_{11})/T. Alors

LRind=2log ⁣[(1π)n00+n10πn01+n11(1π01)n00π01n01(1π11)n10π11n11]    χ12.LR_{ind} = -2\log\!\left[\frac{(1-\pi)^{n_{00}+n_{10}}\,\pi^{\,n_{01}+n_{11}}}{(1-\pi_{01})^{n_{00}}\pi_{01}^{n_{01}}(1-\pi_{11})^{n_{10}}\pi_{11}^{n_{11}}}\right] \;\sim\; \chi^2_1.

Les deux se combinent en le test de couverture conditionnelle LRcc=LRuc+LRindχ22LR_{cc} = LR_{uc} + LR_{ind} \sim \chi^2_2, qui vérifie simultanément le bon taux et l'indépendance. Un modèle peut réussir Kupiec (bon nombre de violations) mais échouer à Christoffersen (elles se sont toutes regroupées sur une semaine de krach) — c'est le mode d'échec que l'on veut le plus capturer, car les violations groupées sont celles qui font sauter un compte.

from scipy.stats import chi2

def var_backtest(losses, var, p):
    """
    losses, var: 1D arrays, same length; loss>0 is a loss, var>0 threshold.
    p = 1 - alpha (target violation rate, e.g. 0.01 for 99% VaR).
    Returns Kupiec, Christoffersen-independence, and conditional-coverage LR.
    """
    losses = np.asarray(losses)
    var = np.asarray(var)
    I = (losses > var).astype(int)          # violation indicators
    T = len(I)
    N = int(I.sum())
    pi_hat = N / T

    eps = 1e-12
    ll_null = N * np.log(p + eps) + (T - N) * np.log(1 - p + eps)
    ll_alt  = N * np.log(pi_hat + eps) + (T - N) * np.log(1 - pi_hat + eps)
    LR_uc = -2 * (ll_null - ll_alt)
    p_uc = 1 - chi2.cdf(LR_uc, df=1)

    n00 = np.sum((I[:-1] == 0) & (I[1:] == 0))
    n01 = np.sum((I[:-1] == 0) & (I[1:] == 1))
    n10 = np.sum((I[:-1] == 1) & (I[1:] == 0))
    n11 = np.sum((I[:-1] == 1) & (I[1:] == 1))
    pi01 = n01 / (n00 + n01) if (n00 + n01) else 0.0
    pi11 = n11 / (n10 + n11) if (n10 + n11) else 0.0
    pi   = (n01 + n11) / (n00 + n01 + n10 + n11)

    def _ll(pi01, pi11, pi_pooled, use_pooled):
        if use_pooled:
            a = (n00 + n10) * np.log(1 - pi_pooled + eps)
            b = (n01 + n11) * np.log(pi_pooled + eps)
            return a + b
        return (n00 * np.log(1 - pi01 + eps) + n01 * np.log(pi01 + eps)
                + n10 * np.log(1 - pi11 + eps) + n11 * np.log(pi11 + eps))

    LR_ind = -2 * (_ll(pi01, pi11, pi, True) - _ll(pi01, pi11, pi, False))
    p_ind = 1 - chi2.cdf(LR_ind, df=1)

    LR_cc = LR_uc + LR_ind
    p_cc = 1 - chi2.cdf(LR_cc, df=2)

    return {
        "T": T, "violations": N,
        "obs_rate": pi_hat, "target_rate": p,
        "LR_uc": LR_uc, "p_uc": p_uc,
        "LR_ind": LR_ind, "p_ind": p_ind,
        "LR_cc": LR_cc, "p_cc": p_cc,
    }

Pour générer honnêtement les entrées losses/var, on réajuste (ou au minimum on re-prévoit) sur une fenêtre expansive ou glissante et on enregistre la VaR à un pas pour chaque jour hors échantillon, puis on la compare à la perte réalisée de ce jour-là. Ne jamais backtester la VaR in-sample — un modèle ajusté sur le krach même qu'on lui demande de prédire paraîtra bien meilleur qu'il ne l'est. C'est la même discipline que la parité backtest-live : l'évaluation ne doit utiliser que l'information disponible au moment de la décision.

def walk_forward_var(returns, alpha=0.99, start=750, refit_every=25,
                     vol="Garch", o=1, dist="t"):
    """
    Expanding-window one-step VaR. Refit every `refit_every` days
    (refitting daily is correct but slow; every ~25 days is a common
    compromise -- validate the shortcut on your data).
    """
    losses, vars_ = [], []
    res = None
    for t in range(start, len(returns)):
        if res is None or (t - start) % refit_every == 0:
            am = arch_model(returns.iloc[:t], mean="Constant",
                            vol=vol, p=1, o=o, q=1, dist=dist)
            res = am.fit(disp="off")
        fc = res.forecast(horizon=1, reindex=False)
        mu = fc.mean.iloc[-1, 0]
        sig = np.sqrt(fc.variance.iloc[-1, 0])
        dp = [res.params[k] for k in res.params.index
              if k in ("nu", "eta", "lambda", "lam")]
        z_q = float(np.atleast_1d(
            res.model.distribution.ppf(1 - alpha, dp) if dp
            else res.model.distribution.ppf(1 - alpha))[0])
        var_t = -(mu + sig * z_q)
        vars_.append(var_t)
        losses.append(-returns.iloc[t])     # realized loss for that day
    return np.array(losses), np.array(vars_)

losses, vars_ = walk_forward_var(r, alpha=0.99, dist="t")
print(var_backtest(losses, vars_, p=0.01))

Lecture : une VaR à 99% bien calibrée montre un taux observé proche de 1%, un Kupiec non significatif (p_uc élevé), et un Christoffersen non significatif (p_ind élevé) — pas de clustering. En pratique, le résultat honnête sur les cryptos est que GARCH-Normale échoue à Kupiec (trop de violations, p_uc minuscule) tandis que GJR-tt ou EGARCH-tt réussit ou s'en approche. Ce contraste est tout l'argument de cet article rendu sous forme de test d'hypothèse. Si même le modèle tt montre des violations groupées (p_ind petit), votre dynamique de volatilité est encore mal spécifiée — souvent le signe qu'il faut une mémoire plus longue (component/FIGARCH) ou une couche de régime, ce qui rejoint la détection de régime par HMM.

Classer les modèles par perte de queue, pas seulement par réussite/échec

Kupiec et Christoffersen donnent un verdict binaire — le modèle est ou n'est pas rejeté. C'est nécessaire mais grossier : deux modèles peuvent tous deux "réussir" alors que l'un est significativement plus précis. Pour classer des prévisions de VaR concurrentes, on les note avec une fonction de perte strictement cohérente pour le quantile, la perte pinball (de quantile) :

Lτ(r,q)=(τ1{r<q})(rq),τ=1α,L_\tau(r, q) = \bigl(\tau - \mathbf{1}\{r < q\}\bigr)\,(r - q), \qquad \tau = 1-\alpha,

qq est le quantile de VaR (signé) et rr le rendement réalisé. Moyennée sur les jours hors échantillon, une perte pinball moyenne plus basse signifie un quantile mieux calibré et plus précis ; comme la perte est cohérente pour le quantile τ\tau, la minimiser ne récompense pas un modèle pour être paresseusement large. Pour comparer formellement deux modèles, on injecte leurs différences de perte journalière dans un test de Diebold-Mariano.

def pinball_loss(returns, var, alpha=0.99):
    tau = 1 - alpha
    q = -np.asarray(var)               # VaR is a positive loss; quantile is negative
    r = np.asarray(returns)
    hit = (r < q).astype(float)
    return np.mean((tau - hit) * (r - q))

Pour l'Expected Shortfall en particulier, notez que l'ES n'est pas élicitable à elle seule (il n'existe pas de fonction de perte dont le minimiseur soit l'ES seule), ce qui est une véritable subtilité théorique : on évalue l'ES conjointement avec la VaR à l'aide des règles de notation de Fissler-Ziegel, ou l'on se rabat sur la pratique plus simple qui consiste à vérifier que l'ampleur moyenne des dépassements correspond à l'ES prédite par le modèle. Un contrôle grossier mais utile de l'ES : parmi les jours de violation de la VaR, comparer la perte moyenne réalisée à l'ES moyenne prévue ces jours-là — elles devraient être proches.

Le cadre réglementaire est l'approche du feu tricolore de Bâle (Basel traffic-light) : sur 250 jours de bourse, 0 à 4 violations d'une VaR à 99% relèvent du "vert" (acceptable), 5 à 9 du "jaune" (surveillance accrue), 10 ou plus du "rouge" (le modèle est rejeté et les multiplicateurs de capital augmentent). C'est un cousin plus grossier de Kupiec, mais c'est le langage que parlent réellement les comités de risque, et il vaut la peine de le rapporter aux côtés des statistiques LR.

Considérations pratiques

Quand les paramètres supplémentaires ne se justifient pas

Le réflexe honnête est le scepticisme envers la complexité. Chaque paramètre ajouté est un levier que l'optimiseur peut surajuster, et le GARCH asymétrique à queues épaisses en compte plusieurs. Recommandations concrètes :

  • Échantillons illiquides ou courts. Avec quelques centaines d'observations journalières, l'erreur type sur γ\gamma et λ\lambda sera grande, et vous allez "détecter" des asymétries qui ne sont que du bruit d'échantillonnage. Sur un altcoin nouveau ou peu liquide, un GARCH-tt symétrique est souvent le modèle le plus complexe que les données puissent supporter. Ajuster une EGARCH skew-tt sur 200 jours revient à se tromper soi-même.
  • Le terme d'asymétrie ne justifie fréquemment pas son coût. En pratique, passer de Normale à tt est une amélioration large et fiable (les queues épaisses sont réelles et fortes). Passer de tt à skew-tt est souvent marginal — un gain de BIC de 1 ou 2, parfois négatif. N'ajoutez l'asymétrie que quand les données la réclament clairement.
  • EGARCH contre GJR est généralement équivalent sur données journalières. Ils codent la même histoire qualitative sous des formes fonctionnelles différentes. Choisissez par backtest de VaR hors échantillon, pas par celui qui a la log-vraisemblance la plus belle in-sample.
  • La fréquence plus élevée change la réponse. Sur des barres horaires ou minute, la saisonnalité intraday et la microstructure dominent, et un GARCH de style journalier simple est mal spécifié quelle que soit l'asymétrie. Problème différent, outillage différent.

C'est la même leçon que l'évaluation honnête sans avantage robuste : un modèle plus complexe qui ne survit pas au test hors échantillon est pire que le modèle simple qu'il remplace, car il porte l'illusion de la précision. Rapportez le résultat négatif — "l'asymétrie n'a pas aidé sur ETH" — comme une conclusion réelle, et utilisez l'optimisation walk-forward comme arbitre, pas l'AIC in-sample.

Ce sont les marginales sur lesquelles tout le reste se construit

Les modèles présentés ici ne sont pas un aboutissement ; ils constituent le bloc de construction univarié de la mécanique de risque conjoint. L'article sur les modèles de copules pour le risque conjoint crypto utilise exactement EGARCH/GJR-tt comme marginales GARCH-EVT avant d'ajuster une copule vine — on ajuste un GARCH asymétrique à queues épaisses par actif, on extrait les résidus standardisés, et ce n'est qu'ensuite qu'on modélise la dépendance inter-actifs. Si votre marginale est un GARCH gaussien symétrique, la copule hérite de ses erreurs de queue, quelle que soit la qualité du modèle de dépendance. Marginales médiocres, VaR conjointe médiocre.

Pour le problème de la volatilité multivariée — des corrélations variables dans le temps plutôt que des variances par actif — voir la Partie 3, DCC-GARCH, qui superpose un modèle de corrélation dynamique à ces ajustements univariés. Et pour transformer une prévision de volatilité en dimensionnement de position et en backtest de trading, la Partie 4 sur le ciblage de volatilité utilise les prévisions σt+1\sigma_{t+1} de ces mêmes modèles pour ajuster l'exposition inversement au risque prédit.

Une alternative sans hypothèse de distribution

Toute la section risque repose sur une hypothèse paramétrique : que les résidus standardisés suivent une tt ou une skew-tt. Cette hypothèse est testable et généralement raisonnable, mais elle peut échouer. Si vous préférez ne pas vous engager du tout sur une forme de queue, la prédiction conforme donne des intervalles de prédiction sans hypothèse de distribution, avec des garanties de couverture à taille d'échantillon finie — une philosophie véritablement différente qui ne fait aucune affirmation sur la distribution de l'innovation. Les deux approches sont complémentaires : le GARCH-tt paramétrique donne une densité conditionnelle complète (et donc l'ES, que les intervalles conformes ne fournissent pas directement), tandis que l'approche conforme donne une couverture qui tient même quand la densité est fausse. En production, utiliser les deux comme contrôle croisé est une assurance bon marché.

Hygiène numérique et de workflow

  • Multipliez les rendements par 100. Les optimiseurs GARCH convergent bien plus fiablement sur des rendements en pourcentage que sur des rendements fractionnaires bruts. Pensez à annuler l'échelle de la VaR/ES si vous rapportez en unités fractionnaires.
  • Surveillez la persistance. Si α+β+12γ\alpha + \beta + \tfrac{1}{2}\gamma est estimé au-dessus de ~0.999, le modèle est proche de l'intégration (comportement IGARCH) ; les prévisions reviennent à la moyenne extrêmement lentement et les prévisions de variance à long horizon deviennent peu fiables. Pas nécessairement faux, mais à signaler.
  • Échecs de convergence sur fenêtres glissantes. La forme logarithmique d'EGARCH évite les contraintes de positivité mais peut quand même échouer à converger sur une fenêtre pathologique. Enveloppez fit() dans un try/except et retombez sur les paramètres de la fenêtre précédente plutôt que de faire planter un backtest en production.
  • Modèle de moyenne. Nous avons utilisé une moyenne constante tout du long. Pour la plupart des cryptos journalières, la moyenne conditionnelle est proche de zéro et noyée par la volatilité ; ne dépensez pas de complexité de modèle à essayer de la prévoir sans raison réelle.

Résumé

  • Le GARCH(1,1) simple présente deux défauts structurels : il est symétrique (réagit à +x%+x\% et x%-x\% de façon identique car les chocs entrent sous forme ε2\varepsilon^2) et il suppose des innovations gaussiennes (sous-évaluant les queues épaisses des cryptos). Les deux coûtent de l'argent réel via une VaR trop optimiste.
  • GJR-GARCH ajoute un terme de seuil γI(εt1<0)εt12\gamma\,I(\varepsilon_{t-1}<0)\,\varepsilon_{t-1}^2. Un γ>0\gamma > 0 significatif est l'effet de levier : une mauvaise nouvelle augmente davantage la volatilité. La positivité exige α+γ0\alpha+\gamma\ge0 ; la persistance est α+β+12γ\alpha+\beta+\tfrac12\gamma.
  • EGARCH modélise logσt2\log\sigma_t^2, donc aucune contrainte de positivité et la stationnarité se réduit à β<1|\beta|<1. L'asymétrie entre via un terme signé γzt1\gamma z_{t-1} (l'effet de levier correspond à γ<0\gamma<0 dans cette convention) séparé d'un terme de magnitude zt1|z_{t-1}|.
  • La courbe d'impact des nouvelles — variance de la période suivante en fonction du dernier choc — rend l'asymétrie visible et vérifie d'un coup d'œil la convention de signe d'EGARCH.
  • Les innovations Student-tt (dist='t') corrigent les queues via un degré de liberté ν\nu (typiquement 3 à 6 pour les cryptos) ; la skew-tt de Hansen (dist='skewt') ajoute une asymétrie λ\lambda pour une queue gauche plus lourde. Passer de Normale à tt est un gain large et fiable ; de tt à skew-tt est souvent marginal.
  • La VaR et l'ES découlent de la distribution conditionnelle ajustée : VaRα=(μt+1+σt+1Fz1(1α))\text{VaR}_\alpha = -(\mu_{t+1} + \sigma_{t+1}F_z^{-1}(1-\alpha)), le quantile à queue épaisse rendant le risque honnêtement plus grand que la version gaussienne. L'ES (cohérente, \approx CVaR) capture la perte moyenne au-delà de la VaR.
  • Backtestez avec Kupiec et Christoffersen. Kupiec vérifie le taux de violation ; Christoffersen vérifie que les violations ne sont pas groupées. Un modèle peut réussir l'un et échouer à l'autre — les violations groupées sont le mode d'échec dangereux. Backtestez strictement hors échantillon.
  • Discipline plutôt que complexité. N'ajoutez asymétrie/asymétrie de queue que si elle survit au BIC et à un backtest de VaR hors échantillon. Sur des séries courtes ou illiquides, le modèle plus simple gagne généralement.

References:

  • Nelson, D. B. (1991). Conditional heteroskedasticity in asset returns: A new approach. Econometrica, 59(2), 347-370. DOI
  • Glosten, L. R., Jagannathan, R., & Runkle, D. E. (1993). On the relation between the expected value and the volatility of the nominal excess return on stocks. Journal of Finance, 48(5), 1779-1801. DOI
  • Bollerslev, T. (1987). A conditionally heteroskedastic time series model for speculative prices and rates of return. Review of Economics and Statistics, 69(3), 542-547. DOI
  • Hansen, B. E. (1994). Autoregressive conditional density estimation. International Economic Review, 35(3), 705-730. DOI
  • Engle, R. F., & Ng, V. K. (1993). Measuring and testing the impact of news on volatility. Journal of Finance, 48(5), 1749-1778. DOI
  • Christoffersen, P. F. (1998). Evaluating interval forecasts. International Economic Review, 39(4), 841-862. DOI
  • Kupiec, P. H. (1995). Techniques for verifying the accuracy of risk measurement models. Journal of Derivatives, 3(2), 73-84. DOI
  • Black, F. (1976). Studies of stock price volatility changes. Proceedings of the American Statistical Association, Business and Economic Statistics Section, 177-181.
  • McNeil, A. J., Frey, R., & Embrechts, P. (2015). Quantitative Risk Management: Concepts, Techniques and Tools (2nd ed.). Princeton University Press.
  • Sheppard, K. (2023). arch: Autoregressive conditional heteroskedasticity models in Python. GitHub.
blog.disclaimer

MarketMaker.cc Team

Recherche quantitative et stratégie

Discuter sur Telegram
Newsletter

Gardez une longueur d'avance sur le marché

Abonnez-vous à notre newsletter pour des insights exclusifs sur le trading IA, des analyses de marché et des mises à jour de la plateforme.

Nous respectons votre vie privée. Désabonnement possible à tout moment.