σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft AcademyRutas
Ctrl K
AO
+1,2 k estudiantes
Iniciar sesiónUnirse ↗
Rutas
AO
+1,2 k estudiantes
Iniciar sesión
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Ruta de Python›Módulo 7 · Investigación de alfa y riesgo›Tema 7.4·~50 minAvanzado

VaR histórico

Posición en la rutaMódulo 7 de 11 · Tema 4 de 9
7.4 VaR histórico
—Puntuación del lab— / 100XP total—Racha—

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 larger

Probar 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 25

Horizontes 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.0832
import 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
Lo que el VaR no te diceEl VaR es un umbral, no un peor caso: no dice nada sobre lo graves que son las pérdidas más allá, por eso los siguientes temas miran el expected shortfall y las pruebas de estrés. El método histórico vale lo que vale su ventana: dos años tranquilos dan un VaR pequeño justo antes de una crisis, y la cifra al 99 % se apoya en un puñado de observaciones.
  • 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 de 1 - confidence de 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
Explorador · lab-96-1
▾ lab-96-1
…
bash · en el navegador
learner@quantcraft:~/lab-96-1$
Python aún no cargadoPythonLn 1, Col 1Spaces: 4UTF-8

¿Restablecer este tema?

Todo lo que hay en lab-96-1 vuelve a los archivos iniciales y se limpia el terminal. Tu solución actual se perderá: no se puede deshacer.

Se restablecerá
  • main.py → código inicial
  • Historial del terminal y salida de pruebas
  • Cambios sin enviar
Se conservará
  • Mejor puntuación del lab
  • Tu XP y tu racha
  • Progreso de la lección y notas

Inicia sesión para ejecutar tu código.

Todas las clases se pueden leer gratis. Crea una cuenta o inicia sesión para ejecutar código, lanzar las pruebas y enviar este lab.

  • IDE en el navegador con terminal bash — sin instalar nada
  • Corrección instantánea, XP y tu lugar en la ruta
Crear una cuentaIniciar sesión
O
Continuar con GitHub