Je voulais coder un truc concret en vue de stages d'été. Calculer la Value at Risk d'un portefeuille est un classique : peu d'imports, trois méthodes différentes pour la même question, et un résultat tangible. J'ai poussé le code sur GitHub : github.com/mehdisouissi/var-python.
Ce que mesure la VaR, en une phrase
La VaR répond à la question : quelle est la perte maximale que je peux subir sur N jours, avec un niveau de confiance donné ? Quand on dit "VaR 95 % à 1 jour = 2 %", ça veut dire que dans 95 % des cas, la perte sur une journée ne dépassera pas 2 %. Dans 5 % des cas, par contre, elle peut être pire. Et la VaR ne dit pas combien pire. C'est sa principale limite, mais on y reviendra.
Pour les exemples, je prends un mini-portefeuille équipondéré : Apple, Microsoft, Total. Données récupérées avec yfinance sur les 3 dernières années.
import yfinance as yf
import numpy as np
import pandas as pd
tickers = ["AAPL", "MSFT", "TTE.PA"]
data = yf.download(tickers, period="3y")["Close"]
returns = data.pct_change().dropna()
weights = np.array([1/3, 1/3, 1/3])
port_returns = returns @ weights
À partir de là, trois méthodes.
1. VaR paramétrique (variance-covariance)
L'approche la plus rapide. On suppose que les rendements suivent une loi normale, on calcule la moyenne et l'écart-type du portefeuille, et on en déduit la VaR avec un quantile gaussien.
from scipy.stats import norm
mu = port_returns.mean()
sigma = port_returns.std()
alpha = 0.05 # niveau 95%
VaR_param = -(mu + sigma * norm.ppf(alpha))
print(f"VaR paramétrique 95% : {VaR_param:.4%}")
Avantage : c'est instantané. Inconvénient majeur : les rendements de marché ne sont pas normaux. Ils ont des queues épaisses (fat tails). Les vraies grosses pertes arrivent plus souvent que ne le prévoit une loi normale. Donc cette VaR sous-estime presque toujours le risque dans les périodes turbulentes.
2. VaR historique
Là on ne suppose rien sur la distribution. On regarde simplement les rendements passés, on les classe, et on prend le quantile à 5 %.
VaR_hist = -np.percentile(port_returns, 5)
print(f"VaR historique 95% : {VaR_hist:.4%}")
Plus honnête que la paramétrique parce qu'on n'impose pas de forme de distribution. Limite évidente : ça ne marche que si le passé est représentatif. Si on calibre sur 2017-2019, on rate complètement le COVID. Si on calibre sur 2020-2025, on a déjà un choc dans l'historique, ce qui est mieux mais ça reste fragile.
3. VaR Monte Carlo
La méthode la plus flexible. On simule N scénarios de rendements à partir d'un modèle, et on regarde la distribution simulée. Ici je reste simple en gardant une hypothèse multivariée gaussienne, mais la force du Monte Carlo c'est qu'on peut plugger un modèle plus complexe (Student, GARCH, copules) à la place.
n_sim = 100_000
mu_vec = returns.mean().values
cov_mat = returns.cov().values
sim = np.random.multivariate_normal(mu_vec, cov_mat, n_sim)
sim_port = sim @ weights
VaR_mc = -np.percentile(sim_port, 5)
print(f"VaR Monte Carlo 95% : {VaR_mc:.4%}")
Sur mon portefeuille, j'obtiens des valeurs très proches entre paramétrique et Monte Carlo (logique, je suis sous la même hypothèse gaussienne dans les deux). La VaR historique sort un peu plus élevée, parce que les données réelles ont des queues plus épaisses que ce que la gaussienne capture.
Ce que ça m'a appris
Trois trucs qui ne sortaient pas clairement de mes cours :
Premier, la VaR est une convention, pas une vérité. Selon la méthode et la fenêtre temporelle, on peut sortir des valeurs très différentes pour le même portefeuille. Quand un risk manager te donne une VaR, la première question à poser c'est "calculée comment ?".
Deuxième, la VaR ne dit rien sur ce qui se passe au-delà du seuil. C'est pour ça qu'on lui préfère souvent l'Expected Shortfall (ou CVaR) qui mesure la perte moyenne dans les 5 % de cas les pires. J'en ferai un article séparé.
Troisième, plus pratique : les hypothèses gaussiennes sous-estiment le risque de façon presque systématique. Sur un environnement comme aujourd'hui, avec inflation qui réaccélère et nouvelle Fed, c'est exactement le moment où tu ne veux pas te baser uniquement sur de la VaR paramétrique.
Le repo GitHub contient les trois fonctions, un notebook Jupyter avec les graphiques, et un script pour tester sur n'importe quel ticker. Si tu veux contribuer ou pointer des erreurs, ouvre une issue.