Un límite de pérdida con un nivel de confianza
El Value at Risk responde: ¿cuánto puedo perder un mal día, pero no el peor? Un VaR a 1 día al 95 % del 2 % dice que 95 días de cada 100 la pérdida no debería superar el 2 %. El método histórico no necesita modelo. Se toman los rendimientos pasados, se ordenan y se lee la pérdida en el percentil 5: el VaR es menos ese cuantil. Reguladores y límites de riesgo lo usan en todas partes porque es un único número que un gestor puede comparar con un límite.
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 largerProbar un VaR: las superaciones
Un VaR es una predicción, así que puede comprobarse. Una superación es un día en que la pérdida excedió el VaR, return < -VaR. Con un VaR al 95 % se esperan en torno al 5 % de días de superación: muchas más significa que el modelo subestima el riesgo, muchas menos que es demasiado cauto. Los reguladores cuentan las superaciones en 250 días por esto mismo. Ojo con la desigualdad estricta: una pérdida igual al VaR no es una superación.
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 25Horizontes más largos, y como ocurrió
A menudo se exige un VaR a 10 días. Con rendimientos diarios independientes, la volatilidad crece con la raíz del tiempo, así que la regla de la raíz cuadrada del tiempo escala: VaR_T = VaR_1 * sqrt(T). Es una aproximación, más débil con colas gruesas y rendimientos autocorrelacionados. Los backtests honestos también respetan el tiempo: el VaR usado el día t solo puede emplear los rendimientos anteriores al día t, la misma disciplina que evitar la anticipación. Un VaR móvil lo hace con una ventana de los últimos n días.
# 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- El VaR histórico es menos el cuantil
(1 - confidence)de los rendimientos pasados (np.quantile): una fracción de pérdida positiva sin modelo. - Pruebe contando superaciones (
return < -VaR): alrededor de1 - confidencede los días; más significa un VaR demasiado bajo. - Escale a un horizonte con
var * sqrt(days); una ventana móvil usa solo días anteriores; el VaR da un umbral, no el tamaño de las pérdidas más allá.
A continuación: el VaR paramétrico, calcular el mismo umbral con una distribución normal en vez del historial en bruto.
Lab: qué se califica
- Leer la pérdida en el historial con
historical_var25 pts - Contar las superaciones con
var_exceptions25 pts - Alargar el horizonte con
scale_var25 pts - Estimarlo como ocurrió con
rolling_var25 pts