El riesgo en un solo número
La volatilidad es la desviación típica de los rendimientos, expresada anualmente para poder comparar activos: alrededor del 15 al 20 % en un índice bursátil, del 30 al 60 % en una acción concreta, cerca de 0 en efectivo. Sirve para dimensionar posiciones, valorar opciones y fijar límites de riesgo. La estimación más simple es la volatilidad realizada en una ventana: la desviación típica muestral de los rendimientos por sqrt(periodos por año). Trata igual todos los días de la ventana, lo que es a la vez su fuerza (estable) y su debilidad (lenta).
import math
import numpy as np
# Eight quiet days, one -3% shock, three more days
returns = np.array([0.004, -0.002, 0.001, 0.003, -0.004, 0.002, 0.006, -0.001, -0.030, 0.004, 0.002, -0.003])
print(round(returns[:8].std(ddof=1) * math.sqrt(252), 4)) # 0.0526 before the shock: 5.3% a year
print(round(returns.std(ddof=1) * math.sqrt(252), 4)) # 0.1505 with the shock: 15.1% a yearReaccionar más rápido: EWMA
La volatilidad se agrupa: los periodos tranquilos y los agitados duran un tiempo, así que el choque de ayer dice más sobre mañana que un día tranquilo de hace un mes. La media móvil exponencial (EWMA, popularizada por RiskMetrics) actualiza la varianza cada día: varianza_t = lam * varianza_(t-1) + (1 - lam) * rendimiento_t². Con lam = 0,94 el rendimiento más reciente pesa un 6 % y los antiguos se desvanecen geométricamente. La estimación salta con un choque y decae poco a poco, en lugar de seguir alta hasta que el choque sale de la ventana y caer de golpe.
lam = 0.94
variance = np.empty(len(returns))
variance[0] = returns[0] ** 2
for t in range(1, len(returns)):
variance[t] = lam * variance[t - 1] + (1 - lam) * returns[t] ** 2 # the recursion needs the previous value
ewma = np.sqrt(variance)
print(ewma.round(5).tolist())
# [0.004, 0.00391, 0.0038, 0.00375, 0.00377, 0.00369, 0.00387, 0.00376, 0.0082, 0.00801, 0.00778, 0.00758]
# ^ the shock doubles the estimate, then it fades
print(round(ewma[-1] * math.sqrt(252), 4)) # 0.1204 today's annualised estimateUsar el rango y fijar una volatilidad objetivo
Los precios de cierre ignoran lo ocurrido durante el día. El máximo y el mínimo diarios llevan más información: el estimador de Parkinson sqrt(mean(ln(high/low)²) / (4 ln 2)) es varias veces más eficiente que la estimación de cierre a cierre, es decir, alcanza la misma precisión con muchos menos días (supone que no hay grandes saltos entre días). Un uso práctico de cualquier estimación de volatilidad es el objetivo de volatilidad: si quieres un 10 % de riesgo y la volatilidad realizada es del 15 %, mantén 10 / 15 = 0,67 de la posición. El apalancamiento se reduce en la tormenta y crece en la calma.
high = np.array([101.5, 102.0, 103.2, 102.8, 104.0])
low = np.array([99.8, 100.9, 101.7, 101.1, 102.4])
parkinson = math.sqrt(np.mean(np.log(high / low) ** 2) / (4 * math.log(2)))
print(round(parkinson, 5)) # 0.00905 per-day volatility from the daily ranges
target = 0.10
realized = returns.std(ddof=1) * math.sqrt(252)
print(round(target / realized, 3)) # 0.664 hold two thirds of the position to run at 10% risk# Close-to-close versus range: the same five days
close = np.array([100.0, 101.2, 102.5, 101.9, 103.4])
print(round(float(np.diff(np.log(close)).std(ddof=1)), 5)) # 0.00955 from the closes only
print(round(parkinson, 5)) # 0.00905 from the high-low ranges of the same days- Volatilidad realizada: desviación típica muestral por
sqrt(periodos por año); estable pero lenta en reaccionar. - EWMA:
varianza_t = lam * varianza_(t-1) + (1 - lam) * rendimiento_t²; los choques recientes pesan más y se desvanecen geométricamente. - Parkinson usa el rango máximo/mínimo diario; el objetivo de volatilidad escala la posición por
objetivo / realizada.
A continuación: el ratio de Sharpe, la recompensa por unidad de riesgo, y hasta dónde fiarse de él.
Lab: qué se califica
- Medir la volatilidad anual con
realized_volatility25 pts - Dar más peso a los choques recientes con
ewma_volatility25 pts - Usar el rango diario con
parkinson_volatility25 pts - Dimensionar una posición a un presupuesto de riesgo con
volatility_target_leverage25 pts