---
title: "1.6.1 Volatilidad EWMA, correlaciones móviles y drawdown"
description: "Volatilidad histórica frente a EWMA (λ = 0,94), cómo evaluarlas, correlaciones móviles y su ruido, drawdown y tiempo bajo el agua de dos índices."
url: "https://pythonparatrading.com/curso-python-trading/nivel-1/volatilidad-correlaciones-y-drawdown/"
lang: "es"
image: "https://pythonparatrading.com/og/curso-python-trading/nivel-1/volatilidad-correlaciones-y-drawdown.png"
---

# 1.6.1 · Rentabilidades, volatilidad, correlaciones móviles y drawdown

> La volatilidad no es una cifra, es una serie que cambia de régimen, y cada forma de estimarla llega a un régimen nuevo con un retraso distinto. Esta lección compara la ventana fija con la EWMA de RiskMetrics, mide qué correlaciones móviles son señal y cuáles ruido, y descompone el drawdown en profundidad y en tiempo bajo el agua.

- Curso: [Nivel 1: Datos financieros, mercados y análisis](https://pythonparatrading.com/curso-python-trading/nivel-1/)
- Módulo: 1.6 · Análisis exploratorio financiero
- Duración: 60 min
- Requisitos: [0.5.3 · Selección, filtrado, groupby, merge, pivot, resample y ventanas móviles](https://pythonparatrading.com/curso-python-trading/nivel-0/pandas-groupby-merge-resample-y-rolling/), [0.7.1 · Rentabilidades simples y logarítmicas, interés compuesto y estadística descriptiva](https://pythonparatrading.com/curso-python-trading/nivel-0/rentabilidades-y-estadistica-descriptiva/)

## Al terminar esta lección

- Calcular la volatilidad histórica con ventanas de distinto tamaño y la EWMA con λ = 0,94, a mano y con `ewm`, sin usar información del día que se estima.
- Evaluar estimadores de volatilidad como previsiones: error, QLIKE y rentabilidades estandarizadas.
- Calcular correlaciones móviles y distinguir el ruido de muestreo de un cambio real, también según la frecuencia de los datos.
- Descomponer el drawdown en episodios: profundidad, días hasta el mínimo, días hasta recuperar y tiempo bajo el agua.

## Dos índices, siete años

En el nivel 0 calculaste rentabilidades, la volatilidad de una ventana de 21 sesiones y el drawdown de un ETF ficticio
(lecciones 0.5.3 y 0.7.1). Esta lección parte de ahí y va a lo que importa para operar: cómo cambia la volatilidad,
con qué retraso la detecta cada estimador, cuánto se puede fiar uno de una correlación móvil y cómo es un drawdown por
dentro.

Los datos son dos índices ficticios del nivel 1, con las sesiones reales de la NYSE de 2019 a 2025: **ISX**, un índice
de rentabilidad total (`etf_indice_diario.csv`), y **FIX**, un índice de precios con futuros (`fix_indice_diario.csv`).
Los dos tienen episodios de volatilidad alta en 2020, 2022 y la primavera de 2025.

```python
import numpy as np
import pandas as pd

isx = pd.read_csv("etf_indice_diario.csv", parse_dates=["fecha"],
                  index_col="fecha")["indice"]
fix = pd.read_csv("fix_indice_diario.csv", parse_dates=["fecha"],
                  index_col="fecha")["indice"]
px = pd.DataFrame({"ISX": isx, "FIX": fix})
r = np.log(px).diff().dropna()   # rentabilidades logarítmicas
print(px.index[0].date(), "a", px.index[-1].date(), len(px), "sesiones")
anual = pd.DataFrame({
    "media_%": 100 * 252 * r.mean(),
    "vol_%": 100 * np.sqrt(252) * r.std(),
    "peor_dia_%": 100 * r.min(),
    "mejor_dia_%": 100 * r.max()})
anual.round(2)
```
```output
2019-01-02 a 2025-12-31 1760 sesiones
     media_%  vol_%  peor_dia_%  mejor_dia_%
ISX    12.83  20.87       -7.95         7.84
FIX    14.55  20.07       -8.98         8.15
```

Los dos tienen una volatilidad anual en torno al 20 %, peores días de −8 % y −9 %, mejores de +8 % y rentabilidades
medias del 12,8 y el 14,6 % (en log, anualizadas por 252). Una volatilidad de toda la muestra dice poco: es la media de años muy tranquilos y
meses muy agitados. Lo útil es la serie.

## Volatilidad de ventana fija

La volatilidad histórica de n sesiones es la desviación típica de las n últimas rentabilidades, anualizada por √252.
El tamaño de la ventana es un compromiso: corta, ruidosa y rápida; larga, estable y lenta.

```python
x = r["ISX"]
vol = pd.DataFrame({
    f"v{n}": x.rolling(n).std() * np.sqrt(252)
    for n in (21, 63, 252)})
(100 * vol.loc["2020-02-14":"2020-05-29"].iloc[::10]).round(1)
```
```output
             v21   v63  v252
fecha
2020-02-14  10.6  12.1  11.4
2020-03-02  17.5  13.2  11.7
2020-03-16  22.7  17.9  13.1
2020-03-30  27.7  23.4  15.1
2020-04-14  34.3  26.1  16.7
2020-04-28  38.2  29.8  18.4
2020-05-12  45.5  36.7  20.9
2020-05-27  37.2  38.6  21.7
```

A mediados de febrero de 2020 las tres ventanas ven un mercado tranquilo, en torno al 11-12 %. La de 21 sesiones
llega al 34,3 % a mediados de abril y al 45,5 % en mayo; la de 63, al 26,1 % y al 36,7 %; la de 252, que lleva un
año de días tranquilos dentro, no pasa del 21,7 % en todo el periodo. Una ventana rectangular pondera igual todos sus días: hasta que los días
tranquilos salen de ella, infravalora el régimen nuevo.

## EWMA: el peso decrece con la antigüedad

La **media móvil exponencial** (EWMA) de los cuadrados de las rentabilidades da a cada día un peso que decrece de forma
geométrica. Es la de RiskMetrics, la metodología de riesgo de J.P. Morgan de los noventa, que fijó λ = 0,94 para los
datos diarios y λ = 0,97 para los mensuales[^1]:

$$
\sigma^2_t = \lambda\,\sigma^2_{t-1} + (1-\lambda)\,r^2_{t-1}
$$

La rentabilidad de ayer pesa 1 − λ = 6 %; la de anteayer, 6 % × 0,94; la de hace k días, 0,06 × 0,94^(k−1). RiskMetrics
supone media cero, razonable con datos diarios, y por eso usa r² en lugar de (r − media)².

```python
lam = 0.94
k = np.arange(1, 253)
w = (1 - lam) * lam ** (k - 1)
print(f"Vida media: {np.log(0.5) / np.log(lam):.1f} sesiones")
for n in (10, 21, 63, 74):
    print(f"Peso de las {n} últimas: {w[:n].sum():.1%}")
```
```output
Vida media: 11.2 sesiones
Peso de las 10 últimas: 46.1%
Peso de las 21 últimas: 72.7%
Peso de las 63 últimas: 98.0%
Peso de las 74 últimas: 99.0%
```

*Fig. — Peso de cada rentabilidad pasada en la varianza de hoy: EWMA con λ = 0,94 (barras) frente a una ventana de 63 sesiones (línea).* Barras del peso de cada día en la EWMA, del 6 % para el día anterior y decreciendo de forma geométrica; las once primeras, destacadas, suman la mitad del peso. Una línea horizontal al 1,6 % hasta la sesión 63 y cero después representa la ventana rectangular.

La mitad del peso está en las once últimas sesiones y el 99 % en las 74 últimas (la cifra de corte que da el propio
documento de RiskMetrics para λ = 0,94). Una ventana de 63 sesiones da 1/63 = 1,6 % a cada día y 0 al 64.º: el día
que sale de la ventana provoca un salto en la estimación aunque no pase nada hoy.

La recursión se escribe en un bucle o con `ewm`. Con `adjust=False`, pandas aplica exactamente la recursión; con
`alpha = 1 − λ`:

```python
def ewma_var(x, lam=0.94, var0=None):
    """Varianza EWMA de cada día con datos hasta el día anterior."""
    v = np.empty(len(x))
    v[0] = np.var(x[:21]) if var0 is None else var0
    for t in range(1, len(x)):
        v[t] = lam * v[t - 1] + (1 - lam) * x[t - 1] ** 2
    return v

xa = x.to_numpy()
a_mano = ewma_var(xa)
# ewm(adjust=False) incluye el día t: se desplaza uno
con_ewm = (x.pow(2).ewm(alpha=0.06, adjust=False).mean()
           .shift(1).to_numpy())
dif = np.abs(np.sqrt(a_mano[300:]) - np.sqrt(con_ewm[300:]))
print(f"Diferencia máxima tras 300 sesiones: {dif.max():.2e}")
ewma = pd.Series(np.sqrt(252 * a_mano), index=x.index)
vol["ewma"] = ewma
(100 * vol.loc["2020-02-14":"2020-05-29"].iloc[::10]).round(1)
```
```output
Diferencia máxima tras 300 sesiones: 2.32e-11
             v21   v63  v252  ewma
fecha
2020-02-14  10.6  12.1  11.4  10.6
2020-03-02  17.5  13.2  11.7  17.4
2020-03-16  22.7  17.9  13.1  26.5
2020-03-30  27.7  23.4  15.1  34.5
2020-04-14  34.3  26.1  16.7  33.7
2020-04-28  38.2  29.8  18.4  37.4
2020-05-12  45.5  36.7  20.9  40.3
2020-05-27  37.2  38.6  21.7  37.7
```

Las dos versiones coinciden salvo por el valor inicial, cuyo efecto desaparece en unas semanas (0,94³⁰⁰ es
despreciable). Y la diferencia de timing está en la tabla: la EWMA pasa del 10,6 % al 34,5 % en seis semanas
y se estabiliza entre el 34 y el 40 % mientras la de 21 sesiones sigue subiendo hasta el 45,5 %.

La figura de la cabecera lo dibuja día a día con la ventana de 63 sesiones, las dos con datos hasta el día anterior.
¿Cuándo pasa cada una del 30 %?

```python
v63 = (x.rolling(63).std() * np.sqrt(252)).shift(1)
for nombre, serie in [("EWMA", ewma), ("Ventana 63", v63)]:
    s = serie.loc["2020"]
    print(f"{nombre:>10}: 30 % el {s[s >= 0.30].index[0].date()},"
          f" máximo {s.max():.1%} el {s.idxmax().date()}")
```
```output
      EWMA: 30 % el 2020-03-24, máximo 51.1% el 2020-06-16
Ventana 63: 30 % el 2020-04-30, máximo 45.1% el 2020-06-22
```

La EWMA cruza el 30 % el 24 de marzo; la ventana de 63 sesiones, el 30 de abril, cinco semanas después. Un sistema que
reduce la exposición cuando la volatilidad supera un umbral habría reaccionado con más de un mes de diferencia según el
estimador. A la salida pasa lo mismo al revés: la EWMA vuelve antes a niveles bajos y devuelve la exposición antes.

Un detalle de la celda importa más que el resto: la varianza del día t usa las rentabilidades **hasta t − 1**. Si la
volatilidad se usa para dimensionar la posición de hoy (*volatility targeting*, lección 0.7.3), el estimador no puede
incluir la rentabilidad de hoy, que aún no ha ocurrido cuando se decide. `rolling(...).std()` y `ewm(...).mean()`
incluyen el día t: en un backtest, siempre `shift(1)`.

```mermaid
flowchart LR
  R[r hasta t-1] --> S[σ estimada en t]
  S --> P[Posición en t]
  P --> G[Resultado r en t]
```

## Qué estimador prevé mejor

Un estimador de volatilidad es una previsión: dice cuánto se va a mover mañana. Se puede evaluar como cualquier
previsión, comparando la varianza estimada con el cuadrado de la rentabilidad del día siguiente. Dos medidas
habituales: el error cuadrático medio y la pérdida **QLIKE**, que penaliza más quedarse corto que pasarse y es robusta
al ruido de r²:

$$
\text{QLIKE} = \frac{r_t^2}{\sigma_t^2} - \ln\frac{r_t^2}{\sigma_t^2} - 1
$$

Otra forma, más intuitiva: dividir cada rentabilidad por la volatilidad prevista. Si el estimador es bueno, las
rentabilidades estandarizadas tienen desviación típica cercana a 1, la curtosis más baja posible y una proporción de
días por debajo de −2,33 desviaciones cercana a la que espera la normal (1 %).

```python
prev = pd.DataFrame({
    "v21": x.rolling(21).std(), "v63": x.rolling(63).std(),
    "v252": x.rolling(252).std(),
    "ewma94": np.sqrt(x.pow(2).ewm(alpha=0.06, adjust=False).mean()),
    "ewma97": np.sqrt(x.pow(2).ewm(alpha=0.03, adjust=False).mean()),
}).shift(1)                      # previsión para el día siguiente
d = prev.join(x.rename("r")).dropna()
filas = {}
for c in prev:
    s2, r2 = d[c] ** 2, d["r"] ** 2
    z = d["r"] / d[c]
    filas[c] = {"qlike": (r2 / s2 - np.log(r2 / s2) - 1).mean(),
                "z_desv": z.std(), "z_curtosis": z.kurt(),
                "bajo_-2,33_%": 100 * (z < -2.326).mean()}
pd.DataFrame(filas).T.round(3)
```
```output
        qlike  z_desv  z_curtosis  bajo_-2,33_%
v21     1.818   1.195      10.664         2.190
v63     1.827   1.122       9.979         2.057
v252    2.180   1.193      11.176         2.588
ewma94  1.696   1.088       7.326         1.924
ewma97  1.751   1.061       9.304         1.924
```

La EWMA con λ = 0,94 tiene la QLIKE más baja (1,696) y la curtosis más baja (7,3 frente a los 10-11 de las ventanas);
la de λ = 0,97 deja la desviación típica más cerca de 1 (1,06 frente a 1,09), y las dos empatan en días bajo −2,33
(1,9 %). Las ventanas quedan por detrás en todo. Ninguna llega al 1 % de días bajo −2,33: las colas siguen siendo más
gruesas que las de la normal incluso después de estandarizar (lección 1.6.2). La ventana de 252 sesiones es la peor en
QLIKE, curtosis y días bajo −2,33: una volatilidad «del último año» es una mala previsión de la de mañana.

<aside class="callout" data-kind="aviso">

Que la EWMA gane aquí no es una ley: estos datos salen de un modelo con agrupamiento de volatilidad (GJR-GARCH), que es
justo lo que la EWMA captura. En datos reales también suele ganar a las ventanas largas, pero el λ óptimo depende del
activo y del horizonte. Si vas a elegir λ con un backtest, hazlo fuera de la muestra (nivel 2).

</aside>

## Correlaciones móviles: señal y ruido

La correlación entre dos activos también cambia, y una cartera diversificada depende de ella. La correlación móvil de
63 sesiones entre ISX y FIX:

```python
rc = r["ISX"].rolling(63).corr(r["FIX"])
banda = 1.96 / np.sqrt(63)
print(f"Correlación de toda la muestra: {r.corr().iloc[0, 1]:.3f}")
print(rc.describe().round(3).to_string())
print(f"Banda del 95 % si la correlación real es 0: ±{banda:.3f}")
print(f"Fuera de la banda: {(rc.abs() > banda).mean():.1%}")
print("Máximo:", rc.idxmax().date(), round(rc.max(), 3))
```
```output
Correlación de toda la muestra: 0.066
count    1697.000
mean        0.010
std         0.155
min        -0.438
25%        -0.080
50%        -0.006
75%         0.099
max         0.511
Banda del 95 % si la correlación real es 0: ±0.247
Fuera de la banda: 10.1%
Máximo: 2025-04-23 0.511
```

*Fig. — Correlación móvil de 63 sesiones entre las rentabilidades diarias de ISX y FIX, 2019–2025 (último valor de cada semana), con la banda del 95 % para una correlación real nula.* Línea de la correlación móvil entre −0,44 y +0,51 alrededor de cero, casi siempre dentro de una banda sombreada de ±0,25 que marca el ruido esperable con 63 datos. Sale de la banda en algunos tramos; el máximo, destacado, es 0,51 en abril de 2025, durante la caída de los dos índices.

La correlación de toda la muestra es casi nula y la móvil oscila de −0,44 a +0,51. ¿Cambia la relación entre los dos
índices o es ruido? Con 63 datos y una correlación real de cero, el 95 % de las estimaciones cae dentro de ±0,247
(error típico ≈ 1/√n). Aquí cae fuera el 10,1 % del tiempo: el doble del 5 % que daría el azar, pero lejos de lo que
haría falta para leer cada pico como un cambio. El máximo, de 0,51, es del 23 de abril de 2025, en plena caída de los
dos índices, y el pico de marzo de 2020 llega casi a 0,50: los dos episodios de estrés son los dos picos.

Para comprobar cuánto oscila una correlación móvil sin ninguna relación, basta con simularla:

```python
rng = np.random.default_rng(7)
ind = pd.DataFrame(rng.standard_normal((len(r), 2)))
rc0 = ind[0].rolling(63).corr(ind[1])
print(f"Mínimo {rc0.min():.3f}, máximo {rc0.max():.3f}")
print(f"Fuera de la banda: {(rc0.abs() > banda).mean():.1%}")
```
```output
Mínimo -0.255, máximo 0.300
Fuera de la banda: 1.2%
```

Dos series sin ninguna relación producen una correlación móvil que va de −0,26 a +0,30. En esta simulación solo el
1,2 % del tiempo queda fuera de la banda: con ventanas solapadas, los valores de días seguidos no son independientes y
la fracción de un solo camino varía mucho alrededor del 5 %. Cualquier gráfico de correlación móvil hay que leerlo con
esa referencia al lado.

¿Y los periodos de estrés? En los mercados reales suele observarse que las correlaciones entre activos de riesgo
suben en las caídas, justo cuando la diversificación haría más falta. En estos datos hay una huella de eso, pero
viene de la frecuencia, no del día a día:

```python
for regla, nombre in [("W-FRI", "semanal"), ("ME", "mensual"),
                      ("QE", "trimestral")]:
    rr = np.log(px.resample(regla).last()).diff().dropna()
    print(f"{nombre:>10}: {rr.corr().iloc[0, 1]:.3f}"
          f"  ({len(rr)} datos)")
vol21 = r.rolling(21).std()
print(f"Correlación de las volatilidades de 21 sesiones: "
      f"{vol21['ISX'].corr(vol21['FIX']):.3f}")
```
```output
   semanal: 0.156  (365 datos)
   mensual: 0.453  (83 datos)
trimestral: 0.819  (27 datos)
Correlación de las volatilidades de 21 sesiones: 0.650
```

En diario la correlación es 0,06; en semanal, 0,16; en mensual, 0,45, y en trimestral, 0,82. Los dos índices
comparten las grandes tendencias del calendario (las caídas de 2020, 2022 y 2025 y las subidas posteriores), pero no
los movimientos de cada día, que en estos datos son independientes. Al agregar, el ruido diario se cancela y queda la
parte común. Y sus volatilidades sí van juntas (0,65): los regímenes de volatilidad alta son los mismos. Para una
cartera, la consecuencia es clara: la diversificación que se mide con datos diarios puede no existir en el horizonte
que de verdad importa, el de meses.

## Drawdown y tiempo bajo el agua

El drawdown de cada día es la caída desde el máximo anterior:

$$
DD_t = \frac{P_t}{\max_{s \le t} P_s} - 1
$$

Su mínimo es el drawdown máximo, la cifra que todo el mundo cita. Pero un drawdown tiene dos dimensiones: cuánto cae y
cuánto dura. Un **episodio bajo el agua** empieza el día en que el precio cae por debajo de su máximo y termina el día
en que lo supera de nuevo.

```mermaid
stateDiagram-v2
  [*] --> EnMaximo
  EnMaximo --> BajoElAgua: cae del máximo
  BajoElAgua --> BajoElAgua: sigue por debajo
  BajoElAgua --> EnMaximo: supera el máximo
```

```python
def episodios(precio):
    pico = precio.cummax()
    dd = precio / pico - 1
    bajo = dd < 0
    grupo = (~bajo).cumsum()         # un número por episodio
    filas = []
    for _, e in dd[bajo].groupby(grupo[bajo]):
        fin = e.index[-1]
        sig = precio.index.searchsorted(fin, side="right")
        recuperado = sig < len(precio)
        filas.append({
            "inicio": e.index[0].date(),
            "minimo": e.idxmin().date(),
            "recupera": precio.index[sig].date()
                        if recuperado else None,
            "profundidad_%": 100 * e.min(),
            "sesiones_hasta_minimo": e.index.get_loc(e.idxmin()) + 1,
            "sesiones_bajo_agua": len(e)})
    return pd.DataFrame(filas), dd

ep, dd_isx = episodios(px["ISX"])
print(f"Sesiones bajo el agua: {(dd_isx < 0).mean():.1%}")
print(f"Episodios: {len(ep)}")
ep.sort_values("profundidad_%").head(5).round(1)
```
```output
Sesiones bajo el agua: 92.9%
Episodios: 54
        inicio      minimo    recupera  profundidad_%  sesiones_hasta_minimo  sesiones_bajo_agua
22  2020-02-20  2020-04-21  2021-03-29          -43.2                     43                 278
31  2022-02-15  2022-05-25  2023-04-17          -28.9                     70                 292
41  2025-02-20  2025-04-04  2025-06-25          -28.0                     32                  86
35  2023-07-17  2024-01-02  2024-10-03          -18.6                    118                 307
36  2024-10-09  2024-11-26  2025-01-13           -7.2                     35                  64
```

*Fig. — Drawdown de ISX, 2019–2025 (peor valor de cada semana): el episodio más profundo no es el más largo.* Área del drawdown de ISX bajo cero. La caída de 2020 llega al −43,2 % en abril y se recupera en 278 sesiones; la de 2022 baja al −28,9 %; la de 2025, al −28,0 % y se recupera en 86. La franja destacada, de julio de 2023 a octubre de 2024, es el episodio más largo: 307 sesiones bajo el agua con una profundidad máxima de solo −18,6 %.

El 92,9 % de las sesiones ISX está por debajo de su máximo anterior: casi siempre se está «bajo el agua», aunque sea
por poco. Lo que distingue a un episodio es su profundidad y su duración, y no van juntas:

```python
ep.sort_values("sesiones_bajo_agua", ascending=False).head(4)[
    ["inicio", "recupera", "profundidad_%",
     "sesiones_hasta_minimo", "sesiones_bajo_agua"]].round(1)
```
```output
        inicio    recupera  profundidad_%  sesiones_hasta_minimo  sesiones_bajo_agua
35  2023-07-17  2024-10-03          -18.6                    118                 307
31  2022-02-15  2023-04-17          -28.9                     70                 292
22  2020-02-20  2021-03-29          -43.2                     43                 278
41  2025-02-20  2025-06-25          -28.0                     32                  86
```

El desplome de 2020 es el más profundo (−43,2 %) pero tarda 278 sesiones en recuperarse, menos que el episodio que
empieza en julio de 2023, con solo −18,6 % de profundidad y 307 sesiones bajo el agua: una caída moderada seguida de
una recuperación lenta. La caída de 2022 dura 292. Para quien sigue una estrategia, catorce meses sin un máximo nuevo
pesan tanto como una caída grande: es cuando se abandonan los sistemas. Por eso las métricas de riesgo del nivel 2
(lección 2.6.1) incluyen la duración del drawdown y el Ulcer Index, que combina profundidad y duración.

## Lo que esto cambia en un sistema

- **Volatilidad con `shift(1)`.** Toda estimación que alimente una decisión del día t usa datos hasta t − 1. Con
  rolling y ewm de pandas, el día t está dentro: desplázalo.
- **Elige el estimador por su uso.** Para dimensionar posiciones día a día, uno rápido (EWMA, λ = 0,94 o ventana
  corta); para comparar estrategias o fijar límites de riesgo, uno lento y estable.
- **Ninguna correlación sin su banda.** Con n datos, el ruido es del orden de ±2/√n. Y mide la correlación a la
  frecuencia de tu horizonte, no solo en diario.
- **Profundidad y duración.** Informa el drawdown máximo y el episodio más largo bajo el agua. Son riesgos distintos.

## Ejercicios

1. Repite la evaluación de estimadores con FIX y con λ = 0,90, 0,94 y 0,97. ¿Qué λ da la QLIKE más baja en cada
   índice?

**Solución.**

```python
def qlike(serie, lam):
    s2 = serie.pow(2).ewm(alpha=1 - lam, adjust=False).mean()
    dd = pd.DataFrame({"s2": s2.shift(1),
                       "r2": serie.pow(2)}).iloc[63:]
    dd = dd[dd["r2"] > 0]   # días sin variación: ln(0)
    q = dd["r2"] / dd["s2"]
    return (q - np.log(q) - 1).mean()

tabla = pd.DataFrame({ind: {lam: qlike(r[ind], lam)
                            for lam in (0.90, 0.94, 0.97)}
                      for ind in ["ISX", "FIX"]})
tabla.round(4)
```
```output
         ISX     FIX
0.90  1.6955  1.6794
0.94  1.6973  1.6746
0.97  1.7454  1.7173
```

Las diferencias son pequeñas y el λ óptimo depende del índice: en ISX gana 0,90 por dos milésimas; en FIX, 0,94. Con siete años de un solo activo, elegir λ por la QLIKE
es una optimización en la muestra: el 0,94 de RiskMetrics es un valor por defecto razonable precisamente porque no se
ajustó a tus datos.

2. Calcula la correlación EWMA (λ = 0,94) entre ISX y FIX y compárala con la de ventana de 63 sesiones: ¿cuál oscila
   más?

**Solución.**

```python
a = 0.06
cov = (r["ISX"] * r["FIX"]).ewm(alpha=a, adjust=False).mean()
var_i = r["ISX"].pow(2).ewm(alpha=a, adjust=False).mean()
var_f = r["FIX"].pow(2).ewm(alpha=a, adjust=False).mean()
corr_ewma = (cov / np.sqrt(var_i * var_f)).iloc[63:]
pd.DataFrame({"ventana_63": rc.iloc[63:].describe(),
              "ewma_094": corr_ewma.describe()}).round(3)
```
```output
       ventana_63  ewma_094
count    1696.000  1696.000
mean        0.010     0.020
std         0.155     0.182
min        -0.438    -0.517
25%        -0.080    -0.083
50%        -0.006     0.006
75%         0.099     0.110
max         0.511     0.699
```

La EWMA oscila más: su vida media de 11 sesiones equivale a una ventana mucho más corta que 63, y su ruido de muestreo
es mayor. Es la otra cara de reaccionar antes. Las primeras 63 sesiones se descartan porque la recursión arranca de
un solo dato y da correlaciones de ±1 al principio.

3. Una estrategia tiene un drawdown máximo del −15 % y otra del −25 %. ¿Qué más necesitas saber antes de decir cuál
   es menos arriesgada?

**Solución.**

La duración de sus episodios bajo el agua (el más largo y el típico), la volatilidad de cada una (un −15 % con una
volatilidad del 5 % es un evento de tres desviaciones; un −25 % con un 25 %, uno normal) y cuántos años cubre el
histórico: el drawdown máximo crece con la longitud de la muestra. También importa si el drawdown viene de un único
desplome o de una sangría lenta, porque se gestionan de forma distinta (stops frente a revisión del sistema).

[^1]: J.P. Morgan/Reuters, *RiskMetrics — Technical Document*, 4.ª edición, 1996: correlaciones y volatilidades con
    medias exponenciales y factores de decaimiento de 0,94 (datos diarios, «74 day cutoff 1%») y 0,97 (mensuales).

## Autoevaluación

1. Con λ = 0,94, ¿qué peso tiene en la EWMA la rentabilidad de ayer?

   - A. El 94 %
   - B. El 6 %: (1 − λ)
   - C. 1/63, como en una ventana de 63 sesiones
   - D. Depende del nivel de volatilidad

   *Respuesta B: El 6 %: (1 − λ).* σ²(t) = λ σ²(t−1) + (1 − λ) r²(t−1): la última rentabilidad pesa 1 − λ = 6 %, la anterior 6 % × 0,94, y así sucesivamente. La vida media del peso es ln 0,5 / ln 0,94 ≈ 11,2 sesiones.

2. En marzo de 2020, ¿por qué la volatilidad de ventana de 63 sesiones va por detrás de la EWMA?

   - A. Porque está mal calculada
   - B. Porque pondera igual los 63 días: los días tranquilos de enero y febrero pesan lo mismo que los del desplome
   - C. Porque usa rentabilidades simples
   - D. Porque la EWMA usa información futura

   *Respuesta B: Porque pondera igual los 63 días: los días tranquilos de enero y febrero pesan lo mismo que los del desplome.* Una ventana rectangular reparte el peso por igual. Hasta que los días tranquilos salen de la ventana, el estimador infravalora el régimen nuevo; la EWMA da más peso a lo reciente y reacciona antes. Ninguna de las dos usa el día que estima si se desplaza un día.

3. La correlación móvil de 63 sesiones entre dos índices oscila entre −0,44 y +0,51 con una media de 0,01. ¿Qué es lo más probable?

   - A. Que la relación entre los dos índices cambia de signo cada pocos meses
   - B. Que gran parte de la oscilación es ruido de muestreo: con 63 datos y correlación cero, el 95 % de las estimaciones cae entre ±0,25
   - C. Que hay un error en el cálculo
   - D. Que hay que usar una ventana de 5 sesiones

   *Respuesta B: Que gran parte de la oscilación es ruido de muestreo: con 63 datos y correlación cero, el 95 % de las estimaciones cae entre ±0,25.* El error típico de una correlación cercana a cero con n datos es aproximadamente 1/√n. Antes de interpretar un cambio de correlación hay que compararlo con esa banda.

4. La correlación diaria de ISX y FIX es 0,06 y la trimestral 0,82. ¿Cómo puede ser?

   - A. Por un error de redondeo
   - B. Porque los dos índices comparten las grandes tendencias (las caídas de 2020, 2022 y 2025) pero no los movimientos diarios: a frecuencias bajas domina la parte común
   - C. Porque la correlación trimestral siempre es mayor
   - D. Porque hay menos días festivos

   *Respuesta B: Porque los dos índices comparten las grandes tendencias (las caídas de 2020, 2022 y 2025) pero no los movimientos diarios: a frecuencias bajas domina la parte común.* La correlación depende de la frecuencia. Lo que domina el día a día de estos índices es ruido independiente; al agregar, ese ruido se cancela y queda la tendencia común. Con 27 trimestres, además, la estimación es muy imprecisa.

5. El drawdown más profundo de ISX es del −43,2 %, pero su episodio más largo bajo el agua no es ese. ¿Qué mide cada cosa?

   - A. Lo mismo
   - B. La profundidad mide cuánto se pierde desde el máximo; la duración, cuánto tiempo se tarda en volver a él. Una caída rápida con rebote rápido puede durar menos que una caída suave sin rebote
   - C. La duración solo cuenta días con pérdidas
   - D. El drawdown no se puede medir en días

   *Respuesta B: La profundidad mide cuánto se pierde desde el máximo; la duración, cuánto tiempo se tarda en volver a él. Una caída rápida con rebote rápido puede durar menos que una caída suave sin rebote.* En ISX, la caída de 2020 se recupera en 278 sesiones; el episodio de 2023-2024, con solo −18,6 % de profundidad, dura 307. Para quien vive la estrategia, las dos dimensiones duelen de forma distinta.

## Ideas clave

- Una ventana fija pondera igual todos sus días y llega tarde a los regímenes nuevos; la EWMA con λ = 0,94 (RiskMetrics, datos diarios) tiene una vida media de unas 11 sesiones.
- Para usar una volatilidad en el sizing de hoy, se estima con datos hasta ayer: `shift(1)`. Un estimador se evalúa como previsión, con QLIKE o con rentabilidades estandarizadas.
- Una correlación móvil de n datos tiene un ruido de en torno a ±2/√n: con 63 sesiones, ±0,25. Antes de leer un cambio, compáralo con esa banda.
- La correlación depende de la frecuencia: ISX y FIX tienen 0,06 en diario y 0,82 en trimestral.
- El drawdown tiene profundidad y duración. En ISX, el episodio más profundo (−43,2 %) no es el más largo (307 sesiones bajo el agua).

## Recursos

### Research

- [Estimadores de Volatilidad](https://pythonparatrading.com/estimadores-de-volatilidad-para-trading/) · Research-0002 · 4 min
- [Volatility Targeting en Python](https://pythonparatrading.com/volatility-targeting/) · Research-0004 · 8 min
- [Usos de la Volatilidad y Volatilidad Actual - VIX1D](https://pythonparatrading.com/usos-de-la-volatilidad/) · Research-0003 · 6 min

### Documentación

- [pandas: Series.ewm](https://pandas.pydata.org/docs/reference/api/pandas.Series.ewm.html) · pandas.pydata.org

### Libros

- [J.P. Morgan/Reuters: RiskMetrics Technical Document, 4.ª edición, 1996 (λ = 0,94 para datos diarios)](https://www.msci.com/documents/10199/5915b101-4206-4ba0-aee2-3449d5c7e95a) · msci.com

### Datos

- [Datos del nivel 1: índice ISX y ETFs, 2019-2025 (CSV)](https://pythonparatrading.com/curso/datos/nivel-1/etf_indice_diario.csv) · Descarga · etf_indice_diario.csv

Lección anterior: [1.5.2 · Datos macro, calendarios económicos, estimaciones y transcripciones](https://pythonparatrading.com/curso-python-trading/nivel-1/datos-macro-calendarios-y-estimaciones/)

Lección siguiente: [1.6.2 · Hechos estilizados: colas gruesas, agrupamiento, autocorrelación y apalancamiento](https://pythonparatrading.com/curso-python-trading/nivel-1/hechos-estilizados-de-los-mercados/)
