Une limite de perte avec un niveau de confiance
La Value at Risk répond : combien puis-je perdre un mauvais jour, mais pas le pire ? Une VaR à 1 jour à 95 % de 2 % dit que, 95 jours sur 100, la perte ne devrait pas dépasser 2 %. La méthode historique n'exige aucun modèle. On prend les rendements passés, on les trie et on lit la perte au 5e centile : la VaR est l'opposé de ce quantile. Régulateurs et limites de risque l'utilisent partout parce que c'est un seul nombre qu'un gérant peut comparer à une limite.
import numpy as np
rng = np.random.default_rng(3)
returns = rng.normal(0.0004, 0.012, size=500) # two years of daily returns
var_95 = -np.quantile(returns, 0.05) # minus the 5th percentile
var_99 = -np.quantile(returns, 0.01)
print(round(float(var_95), 5), round(float(var_99), 5)) # 0.01928 0.027 the 99% loss limit is largerTester une VaR : les dépassements
Une VaR est une prévision, donc elle peut être vérifiée. Un dépassement est un jour où la perte a excédé la VaR, return < -VaR. Avec une VaR à 95 %, on attend environ 5 % de jours de dépassement : beaucoup plus signifie que le modèle sous-estime le risque, beaucoup moins qu'il est trop prudent. Les régulateurs comptent les dépassements sur 250 jours précisément pour cela. Notez l'inégalité stricte : une perte égale à la VaR n'est pas un dépassement.
import numpy as np
rng = np.random.default_rng(3)
returns = rng.normal(0.0004, 0.012, size=500)
var_95 = -np.quantile(returns, 0.05)
exceptions = int(np.sum(returns < -var_95))
print(exceptions, "exceptions in", len(returns), "days; expected about", int(0.05 * len(returns))) # 25 25Horizons plus longs, et comme cela s'est passé
Une VaR à 10 jours est souvent exigée. Avec des rendements quotidiens indépendants, la volatilité croît avec la racine du temps, donc la règle de la racine du temps met à l'échelle : VaR_T = VaR_1 * sqrt(T). C'est une approximation, plus faible avec des queues épaisses et des rendements autocorrélés. Les backtests honnêtes respectent aussi le temps : la VaR utilisée au jour t ne peut employer que les rendements avant le jour t, la même discipline que pour éviter l'anticipation. Une VaR glissante le fait avec une fenêtre des n derniers jours.
# The square-root-of-time rule for several horizons
import math
one_day = 0.0186
for days in (1, 5, 10, 20):
print(days, round(one_day * math.sqrt(days), 4)) # 1: 0.0186, 5: 0.0416, 10: 0.0588, 20: 0.0832import numpy as np
def historical_var(returns, confidence):
return float(-np.quantile(returns, 1 - confidence))
def rolling_var(returns, window, confidence):
out = np.full(len(returns), np.nan)
for t in range(window, len(returns)):
out[t] = historical_var(returns[t - window:t], confidence) # the days BEFORE day t
return out
rng = np.random.default_rng(3)
returns = rng.normal(0.0004, 0.012, size=500)
rolling = rolling_var(returns, 250, 0.99)
print(np.isnan(rolling[:250]).all(), round(float(rolling[250]), 5), round(float(rolling[-1]), 5))
exceptions = int(np.sum(returns[250:] < -rolling[250:]))
print(exceptions, "exceptions in", len(returns) - 250, "days (about 2 expected at 99%)")
print(round(historical_var(returns, 0.99) * np.sqrt(10), 5)) # a 10-day figure by the square-root rule- La VaR historique est l'opposé du quantile
(1 - confidence)des rendements passés (np.quantile) : une fraction de perte positive sans modèle. - Testez en comptant les dépassements (
return < -VaR) : environ1 - confidencedes jours ; davantage signifie une VaR trop basse. - Passez à un horizon avec
var * sqrt(days); une fenêtre glissante n'utilise que les jours antérieurs ; la VaR donne un seuil, pas l'ampleur des pertes au-delà.
À suivre : la VaR paramétrique, calculer le même seuil à partir d'une loi normale plutôt que de l'historique brut.
Lab : ce qui est noté
- Lire la perte dans l'historique avec
historical_var25 pts - Compter les dépassements avec
var_exceptions25 pts - Allonger l'horizon avec
scale_var25 pts - L'estimer comme elle s'est produite avec
rolling_var25 pts