GARCH asymétrique et à queues épaisses : EGARCH, GJR et Student-t
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 à exactement comme à une journée à , car le choc n'entre dans la récursion de variance que via son carré, . 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- et skew- 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é , et on les régresse sur des indicateurs du signe et de la taille du choc précédent :
où et . 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 . Les tests individuels sont les tests de biais de signe (), de biais de taille négative () et de biais de taille positive () ; un test joint sur les trois est le test omnibus. Un ou 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 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 :
GJR ajoute un seul terme de seuil : une dose supplémentaire de variance qui s'active uniquement après un choc négatif.
où est l'indicatrice
Lisez la récursion cas par cas. Après un choc positif (), l'indicatrice vaut zéro et l'impact du choc au carré sur la variance de la période suivante est simplement . Après un choc négatif, l'indicatrice vaut un et l'impact est . Le paramètre résume à lui seul toute l'histoire de l'asymétrie :
- : 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.
- : le modèle retombe sur le GARCH(1,1) symétrique. Un test du rapport de vraisemblance ou un test sur est donc un test direct de l'existence même de l'asymétrie.
- : 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 reste construit de façon additive, chaque terme doit rester non négatif. Les conditions de positivité suffisantes sont
Notez que lui-même peut être négatif tant que , de sorte que l'impact après une mauvaise nouvelle ne devient jamais négatif.
Pour la stationnarité de covariance, supposons que les innovations sont standardisées avec une distribution symétrique autour de zéro, de sorte que et que l'indicatrice contribue en moyenne . La condition de stationnarité devient
La variance inconditionnelle (de long terme) est alors
C'est l'analogue GJR du résultat de la Partie 1, , avec le terme supplémentaire 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- de Hansen, ci-dessous), le est remplacé par la probabilité réelle que , mais 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 peut prendre n'importe quelle valeur réelle, est automatiquement positif quels que soient les paramètres. Aucune contrainte à imposer.
Écrivons la récursion en fonction de l'innovation standardisée :
Deux termes portent le choc, et les séparer est toute l'idée :
- Le terme de magnitude répond à la taille du choc, signe retiré. Soustraire le centre de sorte qu'un choc de magnitude moyenne ne contribue en rien. Pour une loi normale standard, ; pour une Student- standardisée, la valeur absolue attendue est plus petite et dépend de , mais
archgère cela en interne. - Le terme de signe est l'asymétrie. Il est linéaire dans l'innovation signée, de sorte qu'un négatif pousse dans la direction opposée à un 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 à : un choc négatif rend alors , augmentant le log-variance. C'est le signe opposé du 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 sur ; la stationnarité exige seulement . 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 à son niveau de long terme et on trace la variance conditionnelle de la période suivante en fonction du dernier choc . 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 et un choc de 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 . Les deux moitiés ont des courbures respectives et .
- EGARCH produit un V asymétrique et exponentiel : les deux branches ont des pentes différentes à cause du terme , 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 , 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 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 à , , ou écarts-types.
La conséquence pour le risque est directe. Une VaR gaussienne à 99% utilise le quantile , et prédit donc . Si la vraie distribution standardisée est une Student- avec, disons, degrés de liberté, le vrai quantile à 1% est proche de — la VaR gaussienne est optimiste d'environ à 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 -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- possède un paramètre de degrés de liberté qui contrôle l'épaisseur des queues : un petit signifie des queues épaisses, et quand la converge vers la loi gaussienne. Le piège est que la distribution brute a une variance , donc il faut la standardiser à variance unitaire avant de l'utiliser comme innovation — sinon le "" dans la récursion GARCH ne serait pas réellement l'écart-type conditionnel.
L'innovation Student- standardisée à variance unitaire a pour densité
Remarquez le à l'intérieur — c'est la standardisation, le redimensionnement qui assure . La contribution à la log-vraisemblance d'une observation, étant donné la variance conditionnelle GARCH et , est
Le terme est le jacobien de la transformation de vers — le même terme que celui vu dans la vraisemblance GARCH gaussienne de la Partie 1. Seule la forme change. Maximiser conjointement sur les paramètres GARCH et est exactement ce que fait arch quand vous passez dist='t'.
Le estimé est lui-même informatif. Pour les rendements journaliers BTC/ETH, on se retrouve typiquement dans la plage — des queues épaisses, mais avec une variance finie (ce qui exige ) et généralement une kurtosis finie (ce qui exige ). Si votre 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- 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- de Hansen (1994) généralise la standardisée avec un paramètre d'asymétrie en plus de :
où les constantes , , et sont choisies de sorte que ait une moyenne nulle et une variance unitaire pour tout valide. La distribution se scinde en , avec une mise à l'échelle différente dans chaque partie pour concentrer davantage de masse dans une queue.
Interprétation : 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. retrouve la Student- symétrique, donc un test de indique si le terme d'asymétrie apporte quelque chose. Dans arch, c'est dist='skewt', qui estime à la fois et . 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 nécessite plus de 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 ), 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 () 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- 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.091avec une statistique supérieure à 3 est un effet de levier statistiquement significatif. Après un choc négatif, l'impact du choc au carré est ; après un choc positif, il est simplement . Une mauvaise nouvelle fait bouger la volatilité de ce modèle environ fois plus qu'une bonne nouvelle de même taille.nu = 4.3confirme des queues épaisses — loin de la loi gaussienne (), 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 — 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 . Si sa -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 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 et de 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 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 | signée | seuil |
| Forme de queue de l'innovation | gaussienne | Student- | Student- | skew- |
| Asymétrie dans l'innovation | non | non | non | oui () |
| Contraintes de positivité | oui | oui () | aucune (forme log) | oui |
| Condition de stationnarité | ||||
| Paramètres supplémentaires vs base | 0 | |||
| 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-/skew- ajustée.
De la distribution conditionnelle à la VaR
La mécanique GARCH fournit une prévision à un pas de la moyenne conditionnelle et de l'écart-type conditionnel . Le rendement est modélisé comme avec tiré de la distribution standardisée ajustée (gaussienne, , ou skew-). Le quantile du rendement est donc simplement une transformation affine du quantile de la distribution standardisée :
où 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%, et l'on injecte . Tout le bénéfice de la /skew- apparaît ici : est plus négatif que le 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,
Le terme d'espérance de queue conditionnelle possède des formes closes pour les distributions standards. Pour la gaussienne, avec ,
où est la densité de la loi normale standard. Pour la Student- standardisée avec degrés de liberté et (sur l'échelle standardisée), l'espérance de queue est
où est la densité de la standardisée. L'Expected Shortfall de la dépasse celle de la gaussienne davantage que ne le fait la VaR, parce que la queue de la 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 ; la avec utilise quelque chose proche de ; la skew- pousse le quantile gauche encore plus loin tout en resserrant le droit. Même , 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 à pas d'un GARCH stationnaire converge vers le niveau inconditionnel quand croît, et la variance cumulée sur jours est la somme des prévisions à chaque pas — ce n'est pas sauf si la volatilité est à sa moyenne de long terme. La mise à l'échelle naïve en "racine carrée du temps" 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 (à travers la récursion non linéaire du GARCH) ne redonne pas une distribution à l'horizon de 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 à jours, et lire le quantile empirique. Cela gère aussi naturellement le cas skew-, 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 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 la séquence de violations, le nombre de violations sur jours, et le taux observé. Taux cible .
Le test de couverture inconditionnelle de Kupiec (1995) vérifie que via un rapport de vraisemblance :
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 le nombre de transitions de l'état vers l'état dans la séquence de violations, , , et . Alors
Les deux se combinent en le test de couverture conditionnelle , 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- ou EGARCH- 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 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) :
où est le quantile de VaR (signé) et 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 , 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 et 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- symétrique est souvent le modèle le plus complexe que les données puissent supporter. Ajuster une EGARCH skew- 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 à est une amélioration large et fiable (les queues épaisses sont réelles et fortes). Passer de à skew- 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- 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 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 ou une skew-. 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- 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 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 à et de façon identique car les chocs entrent sous forme ) 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 . Un significatif est l'effet de levier : une mauvaise nouvelle augmente davantage la volatilité. La positivité exige ; la persistance est .
- EGARCH modélise , donc aucune contrainte de positivité et la stationnarité se réduit à . L'asymétrie entre via un terme signé (l'effet de levier correspond à dans cette convention) séparé d'un terme de magnitude .
- 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- (
dist='t') corrigent les queues via un degré de liberté (typiquement 3 à 6 pour les cryptos) ; la skew- de Hansen (dist='skewt') ajoute une asymétrie pour une queue gauche plus lourde. Passer de Normale à est un gain large et fiable ; de à skew- est souvent marginal. - La VaR et l'ES découlent de la distribution conditionnelle ajustée : , le quantile à queue épaisse rendant le risque honnêtement plus grand que la version gaussienne. L'ES (cohérente, 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.
MarketMaker.cc Team
Recherche quantitative et stratégie