Cómo se calcula el value at risk: 3 métodos
Conozca los métodos histórico, paramétrico y Monte Carlo para calcular el VaR sobre una serie de rendimientos de SPY, además del expected shortfall que el VaR omite.
El value at risk, o VaR, se calcula fijando un horizonte, estableciendo un nivel de confianza y obteniendo después un percentil de una serie de rendimientos. Un VaR a 1 día y con un nivel de confianza del 99% de 2% significaría que la pérdida se mantiene por debajo de 2% en 99 de cada 100 sesiones y supera ese nivel en la centésima. Tres métodos estándar responden a esa pregunta con los mismos datos de entrada, pero sus resultados difieren más de lo que la mayoría espera.
Qué mide realmente el valor en riesgo
El VaR es un cuantil de una distribución de pérdidas. Ordene todos los rendimientos diarios de una muestra, del peor al mejor. Avance 1% desde el extremo negativo. El rendimiento en ese punto, expresado como una pérdida positiva, es el VaR histórico a 1 día y 99% de confianza. Esta construcción no promete un peor caso. Marca el límite de la zona que la estimación deja de describir.
Esta es la propiedad que los lectores suelen interpretar mal. Un VaR de 99% indica que el peor 1% de los días se encuentra más allá del umbral. No dice hasta dónde. Máxima caída responde a otra pregunta: la pérdida real desde el máximo hasta el mínimo que experimentó una cartera. Por eso, ambas métricas pueden clasificar en orden inverso al mismo par de carteras.
Todas las cifras siguientes se basan en una sola serie: los cierres diarios de SPY desde comienzos de 2010 hasta finales de 2025, convertidos en variaciones porcentuales de cierre a cierre. La ventana está fija, no es móvil. Cada panel reconstruye la serie con esas mismas fechas. Así, las cifras no cambian entre ejecuciones.
El SQL exacto detrás de cada cifra
WITH
px AS
(
SELECT date, max(toFloat64(close)) AS close_px
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= '2009-12-01'
AND date < '2026-01-01'
GROUP BY date
),
rets AS
(
SELECT date, 100 * (close_px / prev_close - 1) AS ret_pct
FROM
(
SELECT date, close_px,
lagInFrame(close_px, 1) OVER (ORDER BY date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_close
FROM px
)
WHERE date >= '2010-01-01' AND prev_close > 0
)
SELECT
toString(toYear(date)) AS year,
count() AS sessions,
round(avg(ret_pct), 3) AS mean_return_pct,
round(stddevSamp(ret_pct), 2) AS daily_sigma_pct
FROM rets
GROUP BY year
ORDER BY yearLa serie abarca 16 años calendario y 252 sesiones solo en 2010. Dos características son relevantes para todo lo que sigue. El promedio por sesión es casi irrelevante en este horizonte: 0.054% en 2010, frente a una desviación estándar diaria, sigma, de 1.13%. Además, sigma no es constante. 2020 registró 2.11% por día, mientras que 2017 registró 0.43%. Una sola sigma no puede describir ambos periodos.
Cómo se calcula el value at risk: tres métodos
VaR histórica: leer el percentil a partir de lo ocurrido
Ordene los rendimientos observados y tome el percentil correspondiente. No se presupone ninguna distribución, y esa es su principal ventaja. El supuesto es que la muestra ya contiene el tipo de sesión que la estimación pretende cubrir. Si el nivel de confianza se lleva suficientemente lejos, la respuesta queda determinada por las pocas peores sesiones de toda la ventana.
VaR paramétrica: media menos z multiplicado por sigma
Resuma la serie con su media y su sigma, y suponga que los rendimientos siguen una distribución normal. La VaR es z multiplicado por sigma menos la media, donde z es el cuantil de la distribución normal estándar: 1.645 al 95%, 2.326 al 99% y 3.090 al 99.9%. El cálculo es inmediato, pero el supuesto falla en una dirección específica. Los rendimientos diarios de las acciones se concentran más en la zona central que una curva normal y alcanzan valores mucho más extremos en las colas. Aquí, sigma es el denominador que también aparece en el Sharpe ratio, por lo que introduce el mismo punto ciego frente a datos con colas pesadas.
VaR de Monte Carlo: simular con la semilla fijada
Genere una muestra sintética grande a partir de un proceso supuesto y lea el percentil de los valores simulados. El panel siguiente utiliza 40,000 observaciones normales estándar generadas mediante la transformación de Box-Muller a partir de una secuencia uniforme con semilla basada en un hash, escalada a la media y sigma de la serie. La semilla está en el SQL, por lo que las observaciones son idénticas en cada nueva ejecución. La simulación aporta flexibilidad, dependencia de la trayectoria y correlación entre múltiples activos, pero no realismo: si se le proporciona una distribución normal, devuelve la respuesta paramétrica con ruido de muestreo adicional. Si, en cambio, se remuestrean los rendimientos observados, la técnica que sustenta los intervalos de confianza bootstrap mantiene activa la cola real.
El SQL exacto detrás de cada cifra
WITH
px AS
(
SELECT date, max(toFloat64(close)) AS close_px
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= '2009-12-01'
AND date < '2026-01-01'
GROUP BY date
),
rets AS
(
SELECT date, 100 * (close_px / prev_close - 1) AS ret_pct
FROM
(
SELECT date, close_px,
lagInFrame(close_px, 1) OVER (ORDER BY date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_close
FROM px
)
WHERE date >= '2010-01-01' AND prev_close > 0
),
emp AS
(
SELECT
avg(ret_pct) AS mu,
stddevSamp(ret_pct) AS sd,
quantileExact(0.100)(ret_pct) AS h90,
quantileExact(0.050)(ret_pct) AS h95,
quantileExact(0.025)(ret_pct) AS h975,
quantileExact(0.010)(ret_pct) AS h99,
quantileExact(0.005)(ret_pct) AS h995,
quantileExact(0.001)(ret_pct) AS h999
FROM rets
),
draws AS
(
SELECT
quantileExact(0.100)(z) AS z90,
quantileExact(0.050)(z) AS z95,
quantileExact(0.025)(z) AS z975,
quantileExact(0.010)(z) AS z99,
quantileExact(0.005)(z) AS z995,
quantileExact(0.001)(z) AS z999
FROM
(
SELECT sqrt(-2 * log(u1)) * cos(2 * pi() * u2) AS z
FROM
(
SELECT
(cityHash64('var-seed-u1', i) % 999999937 + 1) / 999999938.0 AS u1,
(cityHash64('var-seed-u2', i) % 999999937 + 1) / 999999938.0 AS u2
FROM (SELECT arrayJoin(range(40000)) AS i)
)
)
)
SELECT
tupleElement(lvl, 1) AS confidence,
round(-1 * tupleElement(lvl, 2), 2) AS historical_var_pct,
round(tupleElement(lvl, 3) * sd - mu, 2) AS parametric_var_pct,
round(-1 * (mu + sd * tupleElement(lvl, 4)), 2) AS monte_carlo_var_pct,
round(-1 * tupleElement(lvl, 2) - (tupleElement(lvl, 3) * sd - mu), 2) AS method_spread
FROM
(
SELECT
mu,
sd,
arrayJoin([
('90.0%', h90, 1.281552, z90, 1),
('95.0%', h95, 1.644854, z95, 2),
('97.5%', h975, 1.959964, z975, 3),
('99.0%', h99, 2.326348, z99, 4),
('99.5%', h995, 2.575829, z995, 5),
('99.9%', h999, 3.090232, z999, 6)
]) AS lvl
FROM emp
CROSS JOIN draws
)
ORDER BY tupleElement(lvl, 5)En el nivel 95.0%, los tres métodos quedan a menos de un punto entre sí: 1.66% histórica, 1.74% paramétrica y 1.71% simulada. En 99.9% se separan: 5.85% histórica frente a 3.31% paramétrica, una diferencia de 2.54 puntos porcentuales con datos idénticos. La columna simulada se mantiene junto a la paramétrica en todos los niveles. Esa es la conclusión, no un defecto. Una simulación reproduce cualquier distribución que se le proporcione.
Lea el panel por columnas y cada aumento del nivel de confianza amplía el umbral. Léalo por filas y la elección del método apenas importa en la zona central de la distribución, pero domina en la cola. Un límite de VaR presentado sin indicar el método y la ventana no es una cifra que otra persona pueda reproducir.
Lo que el VaR no indica: expected shortfall
El expected shortfall, también llamado VaR condicional, calcula el promedio de las pérdidas en los días que superan el VaR. El VaR señala dónde comienza la cola. El expected shortfall mide qué ocurre dentro de ella.
El SQL exacto detrás de cada cifra
WITH
px AS
(
SELECT date, max(toFloat64(close)) AS close_px
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= '2009-12-01'
AND date < '2026-01-01'
GROUP BY date
),
rets AS
(
SELECT date, 100 * (close_px / prev_close - 1) AS ret_pct
FROM
(
SELECT date, close_px,
lagInFrame(close_px, 1) OVER (ORDER BY date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_close
FROM px
)
WHERE date >= '2010-01-01' AND prev_close > 0
),
qs AS
(
SELECT
quantileExact(0.100)(ret_pct) AS q90,
quantileExact(0.050)(ret_pct) AS q95,
quantileExact(0.025)(ret_pct) AS q975,
quantileExact(0.010)(ret_pct) AS q99,
quantileExact(0.005)(ret_pct) AS q995,
quantileExact(0.001)(ret_pct) AS q999
FROM rets
),
tails AS
(
SELECT
any(q90) AS var90,
any(q95) AS var95,
any(q975) AS var975,
any(q99) AS var99,
any(q995) AS var995,
any(q999) AS var999,
avgIf(ret_pct, ret_pct <= q90) AS es90,
avgIf(ret_pct, ret_pct <= q95) AS es95,
avgIf(ret_pct, ret_pct <= q975) AS es975,
avgIf(ret_pct, ret_pct <= q99) AS es99,
avgIf(ret_pct, ret_pct <= q995) AS es995,
avgIf(ret_pct, ret_pct <= q999) AS es999
FROM rets
CROSS JOIN qs
HAVING countIf(ret_pct <= q999) > 0
)
SELECT
tupleElement(lvl, 1) AS confidence,
round(-1 * tupleElement(lvl, 2), 2) AS historical_var_pct,
round(-1 * tupleElement(lvl, 3), 2) AS expected_shortfall_pct,
round(tupleElement(lvl, 3) / tupleElement(lvl, 2), 2) AS es_to_var_ratio
FROM
(
SELECT
arrayJoin([
('90.0%', var90, es90, 1),
('95.0%', var95, es95, 2),
('97.5%', var975, es975, 3),
('99.0%', var99, es99, 4),
('99.5%', var995, es995, 5),
('99.9%', var999, es999, 6)
]) AS lvl
FROM tails
)
ORDER BY tupleElement(lvl, 4)En 99.0%, el VaR de esta serie es 3.09% y el expected shortfall es 4.43%, o 1.44 veces el umbral. Con una distribución normal, esa ratio se situaría cerca de 1.15 en el mismo nivel. Incluso en 99.9%, cuando el umbral ya alcanzó 5.85%, el promedio de los días que superaron el umbral es 8.14%. Un límite basado únicamente en el VaR trata cada superación como si fuera el mismo evento. La columna de la ratio muestra hasta qué punto esa suposición es incorrecta.
¿El VaR de un día al 99% significa lo mismo para una institución y para un operador?
No. La diferencia se debe principalmente al horizonte temporal. Un operador que cierra todas sus posiciones antes del cierre mantiene el riesgo durante horas. Por eso, un umbral de una sesión se aproxima a su periodo de tenencia, aunque la trayectoria intradía puede superar ampliamente una cifra calculada entre cierres. Una institución que financia pasivos de largo plazo mantiene posiciones durante años. Su exposición se extiende a lo largo de trimestres. Por tanto, su cifra de VaR de un día al 99% funciona como una referencia para capital y monitoreo, no como una descripción del riesgo que asume. Durante años, las normas de capital bancario se basaron en un VaR de un día al 99%. Más adelante, el marco de riesgo de mercado de Basilea sustituyó esta medida por un expected shortfall del 97.5%.
La forma estándar de conectar distintos horizontes es escalar mediante la raíz cuadrada del tiempo. Se multiplica la cifra de una sesión por la raíz cuadrada del horizonte expresado en sesiones. Este paso supone que los rendimientos son independientes y que sigma es constante. La columna de sigma año por año que aparece arriba ya muestra que este supuesto falla.
El SQL exacto detrás de cada cifra
WITH
px AS
(
SELECT date, max(toFloat64(close)) AS close_px
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= '2009-11-01'
AND date < '2026-01-01'
GROUP BY date
),
multi AS
(
SELECT
date,
100 * (close_px / p1 - 1) AS r1,
100 * (close_px / p5 - 1) AS r5,
100 * (close_px / p10 - 1) AS r10,
100 * (close_px / p20 - 1) AS r20
FROM
(
SELECT
date,
close_px,
lagInFrame(close_px, 1) OVER (ORDER BY date ROWS BETWEEN 20 PRECEDING AND CURRENT ROW) AS p1,
lagInFrame(close_px, 5) OVER (ORDER BY date ROWS BETWEEN 20 PRECEDING AND CURRENT ROW) AS p5,
lagInFrame(close_px, 10) OVER (ORDER BY date ROWS BETWEEN 20 PRECEDING AND CURRENT ROW) AS p10,
lagInFrame(close_px, 20) OVER (ORDER BY date ROWS BETWEEN 20 PRECEDING AND CURRENT ROW) AS p20
FROM px
)
WHERE date >= '2010-01-01' AND p20 > 0
),
q AS
(
SELECT
quantileExact(0.01)(r1) AS q1,
quantileExact(0.01)(r5) AS q5,
quantileExact(0.01)(r10) AS q10,
quantileExact(0.01)(r20) AS q20
FROM multi
)
SELECT
tupleElement(h, 1) AS horizon,
round(-1 * tupleElement(h, 3), 2) AS actual_var_pct,
round(-1 * q1 * sqrt(tupleElement(h, 2)), 2) AS sqrt_scaled_var_pct,
round(tupleElement(h, 3) / (q1 * sqrt(tupleElement(h, 2))), 2) AS actual_to_scaled_ratio
FROM
(
SELECT
q1,
arrayJoin([
('1 session', 1.0, q1, 1),
('5 sessions', 5.0, q5, 2),
('10 sessions', 10.0, q10, 3),
('20 sessions', 20.0, q20, 4)
]) AS h
FROM q
)
ORDER BY tupleElement(h, 4)La primera fila es una comprobación de identidad: en 1 session, la cifra escalada coincide con la cifra medida, con una razón de 1. En 20 sessions, ambas se separan, y no en la dirección que normalmente se señala como advertencia: escalar la cifra de una sesión da 13.8%, mientras que los rendimientos medidos durante ese horizonte registran 10.7%, con una razón de 0.78. En esta ventana, la cifra escalada queda por encima de la cola medida para varias sesiones. Aquí operan dos patrones contrapuestos. Una distribución de una sola sesión con colas pesadas se vuelve menos extrema al sumar rendimientos, por lo que el cuantil del 99% agregado se amplía más lentamente que la raíz cuadrada del horizonte. La agrupación de la volatilidad actúa en sentido contrario al concentrar sesiones muy violentas dentro de una misma ventana. En esta serie, el primer patrón tiene mayor peso. Ninguna de las dos direcciones está garantizada en otra ventana o en otro activo. Ese es el punto: el multiplicador es un supuesto, no una medición. La agrupación de la volatilidad también es la propiedad en la que se apoya el ajuste de la exposición a la volatilidad al redimensionar las posiciones.
Hay un límite adicional que conviene expresar con claridad. Todo lo anterior es un VaR de un solo activo aplicado a un fondo indexado amplio. Una cartera con diez nombres correlacionados tiene riesgo de concentración, que un VaR de cartera incorpora mediante una estimación de correlación. Además, las correlaciones suelen moverse más precisamente cuando la estimación resulta relevante.
Notas metodológicas y convenciones
- Los percentiles provienen de un cuantil exacto y no de una estimación muestral. Los sorteos de Monte Carlo proceden de una secuencia uniforme con semilla basada en un hash, escrita directamente en SQL. Por eso, cada cifra se recalcula con el mismo valor.
- Los rendimientos son variaciones del precio entre cierres, sin reinversión de dividendos. Esta es la convención habitual para un VaR de una sesión.
- El panel de horizontes utiliza ventanas superpuestas: los rendimientos consecutivos de 20 sesiones comparten 19 días. Por ello, su cola se basa en muchas menos observaciones independientes de las que sugiere el número de filas.
Preguntas frecuentes
¿Qué es un VaR de 1 día al 99%?
Es el nivel de pérdida que se supera en el peor 1 de cada 100 días de trading, medido durante una sola sesión. En la serie anterior, la estimación histórica es 3.09%. La cifra define un umbral y no dice nada sobre el tamaño de las pérdidas que lo superan.
¿Qué método de cálculo del VaR es más preciso?
Ninguno de los tres es preciso en términos abstractos, porque cada uno responde a la pregunta bajo supuestos diferentes. El VaR histórico refleja fielmente la muestra utilizada y no se pronuncia sobre cualquier evento que la muestra no incluya. El VaR paramétrico es barato, pero subestima las colas de la distribución de las acciones. El método de Monte Carlo solo es tan bueno como la distribución que se le proporcione.
¿Cuál es la diferencia entre el VaR y la pérdida esperada?
El VaR es el umbral correspondiente a un nivel de confianza determinado. La pérdida esperada calcula el promedio de las pérdidas en los días que superan ese umbral. En esta serie, la pérdida esperada al nivel del 99% equivale a 1.44 veces el VaR, frente a aproximadamente 1.15 veces en una distribución normal.
¿Se puede convertir un VaR de 1 día en un VaR de 10 días?
Multiplicar por la raíz cuadrada de 10 es el atajo estándar. Supone que los rendimientos son independientes y que la volatilidad es constante. El panel de horizontes mide la diferencia: en 20 sesiones, la cifra escalada fue 13.8%, frente a 10.7% medida.
Cada panel anterior incluye el SQL que lo generó. Para ejecutar los mismos tres cálculos con otro ticker o periodo, solicítalo en inglés sencillo en la terminal de Strasmore.