---
title: "4.2.2 Criterio de Kelly y volatility targeting"
description: "Kelly completo y fraccional con error de estimación, el coste de apostar de más y el volatility targeting medido con su peor episodio en los datos."
url: "https://pythonparatrading.com/curso-python-trading/nivel-4/kelly-y-volatility-targeting/"
lang: "es"
image: "https://pythonparatrading.com/og/curso-python-trading/nivel-4/kelly-y-volatility-targeting.png"
---

# 4.2.2 · Criterio de Kelly y volatility targeting: cuánto arriesgar

> Kelly dice qué fracción del capital maximiza el crecimiento a largo plazo; el volatility targeting mantiene constante el riesgo de la posición. Esta lección deriva los dos, los aplica a las estrategias y al universo del nivel y los mide con lo que cuestan: el crecimiento que se pierde por estimar mal la media, las caídas de Kelly completo y el día en que el control de volatilidad tenía la exposición más alta justo antes del golpe.

- Curso: [Nivel 4: Carteras, riesgo, ejecución y trading en real](https://pythonparatrading.com/curso-python-trading/nivel-4/)
- Módulo: 4.2 · Gestión del riesgo y tamaño de posición
- Duración: 70 min
- Requisitos: [2.1.4 · Modelos de volatilidad: ARCH, GARCH, EGARCH y GJR con la librería arch](https://pythonparatrading.com/curso-python-trading/nivel-2/volatilidad-arch-garch-egarch-gjr/), [2.2.2 · Universo, señal, filtro, entrada, salida, sizing y gestión del riesgo](https://pythonparatrading.com/curso-python-trading/nivel-2/universo-senal-filtro-entrada-salida-y-sizing/), [2.5.4 · Deflated Sharpe Ratio y Probability of Backtest Overfitting (PBO)](https://pythonparatrading.com/curso-python-trading/nivel-2/deflated-sharpe-ratio-y-pbo/), [2.6.1 · CAGR, Sharpe, Sortino, Calmar, Omega, drawdown y Ulcer Index](https://pythonparatrading.com/curso-python-trading/nivel-2/metricas-de-rentabilidad-y-riesgo/), [4.2.1 · Riesgo por operación, stops y riesgo de ruina](https://pythonparatrading.com/curso-python-trading/nivel-4/riesgo-por-operacion-stops-y-riesgo-de-ruina/)

## Al terminar esta lección

- Derivar la fracción de Kelly en una apuesta binaria y en el caso continuo (`f* = μ/σ²`) y explicar por qué la volatilidad de Kelly es igual al Sharpe.
- Cuantificar el crecimiento, la volatilidad y la probabilidad de caída de Kelly fraccional, y el coste de apostar el doble de Kelly.
- Medir cuánto crecimiento se pierde por el error de estimación de la media y calcular la fracción que lo compensa según la longitud de la muestra.
- Implementar un volatility targeting sin anticipación, con tope, banda y costes, y explicar cuándo mejora el Sharpe y cuándo no.
- Presentar cada regla con su peor episodio en los datos y detectar la anticipación en una implementación con `shift` negativo.

## Kelly: cuánto apostar cuando se tiene ventaja

La lección 2.2.2 repartía el riesgo entre mercados con un objetivo de volatilidad fijado a mano, y la 4.2.1 limita lo
que se arriesga en cada operación. Falta la pregunta de arriba: **cuánto riesgo total** conviene tomar con una
ventaja dada. John L. Kelly la contestó en 1956 para un jugador que apuesta repetidamente una fracción $f$ de su
capital: la que maximiza el **crecimiento logarítmico esperado**, que es la tasa a la que crece el capital a largo
plazo. Para una apuesta que gana $b$ por unidad con probabilidad $p$ y pierde la unidad con $q = 1 - p$:

$$
g(f) = p\,\ln(1 + f b) + q\,\ln(1 - f), \qquad f^* = p - \frac{q}{b}.
$$

Una moneda con un 55 % de acierto y pago 1 a 1 da $f^* = 0{,}10$: apostar el 10 % del capital en cada tirada.

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

p, b = 0.55, 1.0      # probabilidad de ganar y pago por unidad
f_kelly = p - (1 - p) / b
print(f"Fracción de Kelly: {f_kelly:.2f}")


def g(f):
    """Crecimiento logarítmico esperado por apuesta."""
    return p * np.log1p(f * b) + (1 - p) * np.log1p(-f)


fracciones = [0.025, 0.05, 0.10, 0.15, 0.20, 0.30]
pd.Series({f: g(f) for f in fracciones}, name="g").round(5)
```
```output
Fracción de Kelly: 0.10
0.025    0.00219
0.050    0.00375
0.100    0.00501
0.150    0.00374
0.200   -0.00014
0.300   -0.01620
Name: g, dtype: float64
```

El crecimiento por apuesta es máximo en $f = 0{,}10$ (0,00501 en logaritmo) y casi simétrico alrededor: con 0,05 y con
0,15 se obtiene lo mismo (0,00375 y 0,00374). Con 0,20, el **doble de Kelly**, el crecimiento es ya negativo
(−0,00014): se juega con ventaja y, aun así, el capital tiende a menguar. Con 0,30 el capital se desvanece. Una media
no lo muestra; mil apuestas repetidas por 4.000 jugadores, sí:

```python
rng = np.random.default_rng(7)
gana = rng.random((4000, 1000)) < p     # 4.000 caminos de 1.000

filas = {}
for f in (0.05, 0.10, 0.20, 0.30):
    paso = np.where(gana, np.log1p(f * b), np.log1p(-f))
    lw = np.cumsum(paso, axis=1)                # log de la riqueza
    pico = np.maximum.accumulate(np.maximum(lw, 0), axis=1)
    caida = np.exp(lw - pico) - 1
    filas[f] = {"mediana_final": np.exp(np.median(lw[:, -1])),
                "p_pierde": (lw[:, -1] < 0).mean(),
                "p_mitad_inicial": (lw.min(axis=1)
                                    <= np.log(0.5)).mean(),
                "p_caida_50": (caida.min(axis=1) <= -0.5).mean(),
                "p_caida_80": (caida.min(axis=1) <= -0.8).mean()}
pd.DataFrame(filas).T.round(3)
```
```output
      mediana_final  p_pierde  p_mitad_inicial  p_caida_50  p_caida_80
0.05         42.632     0.009            0.116       0.854       0.064
0.10        149.660     0.061            0.483       1.000       0.850
0.20          0.871     0.514            0.911       1.000       1.000
0.30          0.000     0.954            0.997       1.000       1.000
```

Con Kelly (0,10) la mediana de los jugadores multiplica su capital por 150, pero el 6,1 % termina perdiendo, el 48,3 %
toca alguna vez la mitad del capital inicial y todos sufren una caída del 50 % desde un máximo. Con medio Kelly
(0,05) la mediana multiplica por 43, solo pierde el 0,9 %, el 11,6 % toca la mitad del capital inicial y el 6,4 % sufre
una caída del 80 %, frente al 85 % con Kelly. Con el doble de Kelly (0,20) la mitad de los jugadores pierde
dinero con una moneda a su favor.

### En continuo: la volatilidad óptima es el Sharpe

Para una estrategia con exceso esperado $\mu$ y volatilidad $\sigma$ (anuales), apalancada $f$ veces y rebalanceada a
menudo, el crecimiento logarítmico del exceso es $g(f) = f\mu - \tfrac{1}{2}f^2\sigma^2$, una parábola. Su máximo:

$$
f^* = \frac{\mu}{\sigma^2}, \qquad g^* = \frac{1}{2}\,\mathrm{SR}^2, \qquad f^*\sigma = \frac{\mu}{\sigma} = \mathrm{SR}.
$$

La tercera igualdad es la más útil: **a Kelly, la volatilidad de la cuenta es igual al Sharpe**. Una estrategia de
Sharpe 0,5 pide un 50 % de volatilidad anual, sea cual sea su volatilidad propia. Con una fracción $c$ de Kelly, el
crecimiento es $g^*(2c - c^2)$ y la volatilidad $c\cdot\mathrm{SR}$. El logaritmo del capital es entonces un
movimiento browniano con deriva $\nu = \mathrm{SR}^2(c - c^2/2)$ y varianza $s^2 = c^2\mathrm{SR}^2$, y la
probabilidad de que caiga alguna vez hasta una fracción $x$ del capital inicial es
$x^{2\nu/s^2} = x^{2/c - 1}$ (la de tocar una barrera inferior, con parámetros conocidos y horizonte infinito):

```python
c = np.array([0.25, 0.5, 0.75, 1.0, 1.5, 2.0])
expo = 2 / c - 1          # P(caer alguna vez a x) = x ** expo
pd.DataFrame({"crecimiento_vs_max": 2 * c - c**2,
              "vol_en_sharpes": c,
              "p_caer_a_la_mitad": 0.5 ** expo,
              "p_caer_al_20": 0.2 ** expo},
             index=pd.Index(c, name="fraccion")).round(3)
```
```output
          crecimiento_vs_max  vol_en_sharpes  p_caer_a_la_mitad  p_caer_al_20
fraccion
0.25                   0.438            0.25              0.008         0.000
0.50                   0.750            0.50              0.125         0.008
0.75                   0.938            0.75              0.315         0.068
1.00                   1.000            1.00              0.500         0.200
1.50                   0.750            1.50              0.794         0.585
2.00                   0.000            2.00              1.000         1.000
```

La figura de la cabecera dibuja esas dos curvas. El crecimiento es plano cerca del máximo y la probabilidad de caída
no: pasar de Kelly a medio Kelly cuesta un 25 % del crecimiento y divide por cuatro la probabilidad de perder la
mitad (del 50 % al 12,5 %); un cuarto de Kelly conserva el 44 % del crecimiento con un 0,8 %. Por encima de Kelly
todo empeora a la vez: con 1,5 veces Kelly el crecimiento es el mismo que con medio Kelly (0,75) y la probabilidad de
perder la mitad, del 79 %. La simulación de la moneda coincide con la fórmula (0,116 y 0,483 frente a 0,125 y 0,5).
El error no es simétrico: apostar de menos cuesta poco; apostar de más, mucho.

## Kelly en las estrategias del nivel

Las diez estrategias de `estrategias4_diarias.parquet` son rendimientos diarios simples en exceso del tipo libre,
2006-2025, con una media verdadera conocida (`exceso_anual_esperado` en `estrategias4_verdad.csv`). La lección deja
fuera `degradada`, que deja de funcionar en 2019 y es el caso de la lección 4.2.5. Además de $\mu/\sigma^2$, la celda
calcula la Kelly «exacta» de los datos (la $f$ que maximiza la media de $\ln(1 + f r_t)$ con los rendimientos diarios
reales, colas incluidas) y el apalancamiento que arruina la cuenta en el peor día de la muestra:

```python
from scipy.optimize import minimize_scalar

est = pd.read_parquet("estrategias4_diarias.parquet")
est = est.set_index("fecha").drop(columns="degradada")
verdad = pd.read_csv("estrategias4_verdad.csv",
                     index_col="estrategia").reindex(est.columns)


def kelly_log(r):
    """f que maximiza la media de log(1 + f·r) de los datos."""
    tope = 0.999 / abs(r.min())          # más allá, ruina
    res = minimize_scalar(lambda f: -np.log1p(f * r).mean(),
                          bounds=(0, tope), method="bounded")
    return res.x


mu, var = est.mean() * 252, est.var() * 252
tabla = pd.DataFrame({
    "mu": mu, "vol": np.sqrt(var),
    "kelly": mu / var,
    "kelly_verdad": verdad["exceso_anual_esperado"] / var,
    "kelly_log": est.apply(kelly_log),
    "ruina": 1 / est.min().abs()})
tabla.round(2)
```
```output
                     mu   vol  kelly  kelly_verdad  kelly_log  ruina
tendencia_futuros  0.06  0.11   4.97          4.30       4.94  20.25
carry_futuros      0.03  0.08   5.06          5.63       5.02  31.35
carry_divisas      0.05  0.09   5.81          3.81       5.73  21.78
venta_puts         0.04  0.12   2.56          2.82       2.54  15.25
pares              0.02  0.06   6.72          8.43       6.61  25.65
momentum_acciones  0.05  0.12   3.19          2.83       3.12  12.44
valor_acciones     0.02  0.09   3.01          3.06       3.01  31.49
venta_volatilidad  0.04  0.16   1.55          2.61       1.47   5.19
reversion_corto    0.03  0.07   6.41          5.61       6.36  24.95
```

Tres lecturas:

- **Las Kelly son grandes**: de 1,5 a 6,7 veces el capital para estrategias sueltas con volatilidades del 6 al 16 %.
  Es la consecuencia de $f^*\sigma = \mathrm{SR}$: con un Sharpe de 0,4, Kelly pide un 40 % de volatilidad.
- **La media muestral se aleja de la verdadera** aunque haya 20 años: en `carry_divisas` la Kelly muestral es 5,81 y
  la verdadera 3,81; en `venta_volatilidad`, 1,55 frente a 2,61. Con la media de la muestra se apuesta un 50 % de
  más en la primera y un 40 % de menos en la segunda.
- **Las colas mandan en la venta de volatilidad.** Su Kelly exacta (1,47) es menor que la de la fórmula, y el
  apalancamiento de ruina, 5,19 veces, está a solo dos veces de la Kelly verdadera: el peor día de la muestra pierde
  un 19,3 %. En las demás, la ruina queda a 12-31 veces el capital y la fórmula y la Kelly exacta casi coinciden.

Con nueve estrategias poco correlacionadas, la cartera equiponderada tiene un Sharpe mayor y una volatilidad mucho
menor, y Kelly se dispara:

```python
cartera = est.mean(axis=1)          # equiponderada, rend. simples
k_cartera = cartera.mean() / cartera.var()
print(f"Kelly de la cartera: {k_cartera:.1f} veces el capital")
print(f"Volatilidad a Kelly: {k_cartera * cartera.std() * 252**.5:.0%}")


def resultado(r):
    w = (1 + r).cumprod()
    años = len(r) / 252
    return {"cagr": w.iloc[-1] ** (1 / años) - 1
            if w.iloc[-1] > 0 else -1.0,
            "max_caida": (w / w.cummax() - 1).min(),
            "peor_dia": r.min(),
            "ruina": bool((w <= 0).any())}


fr = {c: resultado(c * k_cartera * cartera)
      for c in (0.125, 0.25, 0.5, 1.0, 2.0)}
print("Peor día:", cartera.idxmin().date())
pd.DataFrame(fr).T.astype(float).round(3)
```
```output
Kelly de la cartera: 18.8 veces el capital
Volatilidad a Kelly: 84%
Peor día: 2018-02-05
        cagr  max_caida  peor_dia  ruina
0.125  0.086     -0.315    -0.053    0.0
0.250  0.167     -0.544    -0.106    0.0
0.500  0.303     -0.816    -0.213    0.0
1.000  0.417     -0.979    -0.426    0.0
2.000 -0.081     -1.000    -0.851    0.0
```

*Fig. — Cartera equiponderada de las nueve estrategias del nivel con apalancamiento constante, en fracciones de su Kelly estimado con toda la muestra (18,8 veces el capital), 2006-2025.* Barras por fracción de Kelly con la máxima caída a la izquierda y la rentabilidad anual compuesta a la derecha. 1/8: CAGR +8,6 %, caída −31,5 %; 1/4: CAGR +16,7 %, caída −54,4 %; 1/2: CAGR +30,3 %, caída −81,6 %; Kelly: CAGR +41,7 %, caída −97,9 %; 2× Kelly: CAGR −8,1 %, caída −100,0 %. Kelly completo (destacado) multiplica el CAGR por cinco respecto a un octavo, pero su caída máxima casi borra la cuenta.

Kelly pide 18,8 veces el capital y un 84 % de volatilidad. Con la Kelly de toda la muestra (que usa la media de
20 años desde el primer día: anticipación) el resultado es el de la teoría con un matiz: Kelly completo da el mayor
CAGR (41,7 %), pero con una caída máxima del −97,9 % y un día, el 5 de febrero de 2018, en que pierde el 42,6 % del
capital. Un octavo de Kelly (2,3 veces) da un 8,6 % con una caída del −31,5 %. El doble de Kelly pierde un 8,1 % al año y
se queda con una caída del 100 % (redondeada). Ninguna fracción llega a la ruina estricta (la cuenta no
pasa de cero porque el peor día de la cartera pierde un 2,3 %), pero una caída del 98 % es una ruina a efectos
prácticos.

Con lo que se sabía cada día (media y varianza desde el inicio, con tres años de arranque y sin posiciones cortas),
la Kelly de la cartera empieza en cero en 2009, porque la crisis de 2008 dejó la media de la muestra en negativo, y
sube a 5,9 en 2013, 14,6 en 2017 y 18,7 en 2025:

```python
mu_t = cartera.expanding(756).mean().shift(1)
var_t = cartera.expanding(756).var().shift(1)
k_t = (mu_t / var_t).clip(lower=0)       # sin posiciones cortas
print(k_t.resample("YE").last().loc["2009":"2025":4].round(1))
pd.DataFrame({c: resultado((c * k_t * cartera).dropna())
              for c in (0.25, 0.5, 1.0)}).T.astype(float).round(3)
```
```output
fecha
2009-12-31     0.0
2013-12-31     5.9
2017-12-31    14.6
2021-12-31    16.2
2025-12-31    18.7
Freq: 4YE-DEC, dtype: float64
       cagr  max_caida  peor_dia  ruina
0.25  0.129     -0.346    -0.084    0.0
0.50  0.251     -0.581    -0.168    0.0
1.00  0.450     -0.839    -0.337    0.0
```

El CAGR de Kelly completo sale incluso mayor (45,0 %) porque llegó tarde a la estrategia y con poco apalancamiento a
las caídas de 2009-2012; la caída máxima, del −83,9 %, y el peor día, del −33,7 %, siguen siendo los de una cuenta que
nadie mantendría. La suerte del calendario decide aquí más que la regla.

## El error de estimación

Kelly supone que $\mu$ y $\sigma$ se conocen. La volatilidad se estima bien con pocos datos; la media, no. Con
$T$ años de datos, la media muestral tiene un error típico de $\sigma/\sqrt{T}$, así que la Kelly estimada es
$\hat f = f^*\,u$ con $u \sim N\!\left(1, \tfrac{1}{\mathrm{SR}^2 T}\right)$. Apostar una fracción $c$ de la Kelly
estimada da un crecimiento esperado, relativo al de la Kelly verdadera, de

$$\frac{\mathrm{E}[g]}{g^*} = 2c - c^2\left(1 + \frac{1}{\mathrm{SR}^2 T}\right), \qquad
c^{\text{opt}} = \frac{\mathrm{SR}^2 T}{1 + \mathrm{SR}^2 T}.$$

El término $1/(\mathrm{SR}^2 T)$ es la varianza relativa de la media estimada: un Sharpe de 0,4 medido con 5 años
tiene un estadístico t de $0{,}4\sqrt{5} = 0{,}89$, y la Kelly estimada puede ser cualquier cosa entre cero y el
doble de la verdadera. La celda lo comprueba por simulación:

```python
rng = np.random.default_rng(11)
sr = 0.4                               # Sharpe anual verdadero
filas = {}
for años in (3, 5, 10, 20):
    # f estimada / f verdadera = media estimada / media verdadera
    u = rng.normal(1, 1 / (sr * np.sqrt(años)), 200_000)
    for c in (0.25, 0.5, 0.75, 1.0):
        rel = 2 * c * u - (c * u) ** 2     # g / g máximo
        filas[(años, c)] = {"g_rel_media": rel.mean(),
                            "p_g_negativo": (rel < 0).mean()}
res = pd.DataFrame(filas).T
res.index.names = ["años", "fraccion"]
c_opt = {a: sr**2 * a / (1 + sr**2 * a) for a in (3, 5, 10, 20)}
print("Fracción óptima:", {a: round(v, 2) for a, v in c_opt.items()})
res.unstack("fraccion")["g_rel_media"].round(2)
```
```output
Fracción óptima: {3: 0.32, 5: 0.44, 10: 0.62, 20: 0.76}
fraccion  0.25  0.50  0.75  1.00
años
3         0.31  0.23 -0.23 -1.08
5         0.36  0.44  0.24 -0.24
10        0.40  0.59  0.59  0.38
20        0.42  0.67  0.76  0.69
```

*Fig. — Crecimiento esperado, en % del que daría la Kelly verdadera, al apostar una fracción c de la Kelly estimada con 3, 5, 10 o 20 años de datos de una estrategia de Sharpe 0,4.* Cuatro parábolas, una por longitud de la muestra. Con 20 años el máximo, 76 %, se alcanza con c = 0,76; con 10 años, 62 % con c = 0,62; con 5 años, 44 % con c = 0,44; con 3 años, 32 % con c = 0,32 (puntos destacados). Con 3 años de datos, apostar la Kelly estimada completa da un crecimiento esperado negativo.

Con 20 años de datos, la Kelly estimada completa conserva un 69 % del crecimiento máximo y la mejor fracción es 0,76
(76 %). Con 5 años, la Kelly estimada completa tiene un crecimiento esperado negativo (−24 %) y la mejor fracción es
0,44. Con 3 años, 0,32: la regla práctica de «medio Kelly» o «un cuarto de Kelly» no es prudencia gratuita, es lo que
pide el error de la media. Y la fórmula todavía es optimista por tres motivos:

- El Sharpe de un backtest suele estar inflado por la selección entre muchas variantes (lección 2.5.4): la media de
  la que sale $\hat f$ no es una muestra al azar sino la mejor de varias.
- Las colas gruesas y los saltos (venta de volatilidad) bajan la Kelly exacta por debajo de $\mu/\sigma^2$.
- Las correlaciones de la cartera suben en las crisis (lección 4.2.4): la volatilidad de la cartera de las nueve no
  es la de 2006-2025 cuando más importa.

## Volatility targeting: el riesgo constante

El **volatility targeting** (control por volatilidad objetivo) no decide cuánto riesgo tomar, sino que lo mantiene:
fija una volatilidad objetivo $\sigma^*$ y ajusta cada día la exposición con la volatilidad prevista, calculada solo
con datos hasta el cierre de ayer:

$$w_t = \min\!\left(\frac{\sigma^*}{\hat\sigma_{t-1}},\; w_{\max}\right), \qquad
\hat\sigma^2_{t-1} = \text{EWMA de } r^2 \text{ hasta } t-1.$$

```mermaid
flowchart LR
  R[Rendimientos] --> V[Vol. EWMA ayer]
  V --> E[Objetivo / vol.]
  E --> T[Tope y banda]
  T --> O[Orden al cierre]
  O --> R
```

Aplicado a `RV_EEUU` (la renta variable de EE. UU. del universo, que imita al S&P 500 total) con un objetivo del 15 %,
vida media de 20 sesiones y un tope de 2 veces:

```python
precios = pd.read_parquet("universo4_precios.parquet")
precios = precios.set_index("fecha")
fac = pd.read_parquet("universo4_factores_diarios.parquet")
fac = fac.set_index("fecha")
rend = precios / precios.shift(1).fillna(100) - 1  # base 100
exceso = rend.sub(fac["rf"], axis=0)


def vol_target(x, objetivo, vida_media=20, tope=2.0):
    """Exposición = objetivo / vol. EWMA de AYER, con tope."""
    sig = np.sqrt((x**2).ewm(halflife=vida_media,
                             min_periods=60).mean() * 252)
    expo = (objetivo / sig.shift(1)).clip(upper=tope)
    return (expo * x).dropna(), expo


def metricas(r):
    w = (1 + r).cumprod()
    vol_año = r.groupby(r.index.year).std() * 252**0.5
    return {"exceso": r.mean() * 252, "vol": r.std() * 252**0.5,
            "sharpe": r.mean() / r.std() * 252**0.5,
            "max_caida": (w / w.cummax() - 1).min(),
            "peor_dia": r.min(),
            "vol_año_min": vol_año.min(),
            "vol_año_max": vol_año.max()}


rv = exceso["RV_EEUU"]
vt, expo = vol_target(rv, 0.15)
print(f"Exposición media {expo.mean():.2f}, máxima {expo.max():.2f};"
      f" rotación {expo.diff().abs().sum() / (len(expo) / 252):.1f}"
      " veces al año")
pd.DataFrame({"comprar y mantener": metricas(rv.loc[vt.index]),
              "vol. objetivo 15 %": metricas(vt)}).round(3)
```
```output
Exposición media 0.95, máxima 1.84; rotación 4.4 veces al año
             comprar y mantener  vol. objetivo 15 %
exceso                    0.088               0.132
vol                       0.207               0.157
sharpe                    0.427               0.837
max_caida                -0.609              -0.346
peor_dia                 -0.115              -0.090
vol_año_min               0.110               0.125
vol_año_max               0.318               0.195
```

*Fig. — Renta variable de EE. UU. del universo (RV_EEUU) con y sin volatilidad objetivo del 15 %: volatilidad realizada de 63 sesiones y exposición del control, 2006-2025.* Arriba, la volatilidad realizada de 63 sesiones a fin de mes: la del índice va del 8 al 55 % (2020); la de la versión con objetivo (destacada) se queda casi siempre entre el 10 y el 25 %, con picos al principio de cada crisis, cuando la exposición todavía no ha bajado. Abajo, la exposición a fin de mes: entre 0,28 y 1,68 veces (tope: 2), por debajo de 1 en las crisis.

El control hace lo que promete con el riesgo: la volatilidad anual realizada se mueve entre el 12,5 y el 19,5 % en
lugar de entre el 11 y el 31,8 %, y la máxima caída baja del −60,9 al −34,6 %. La figura enseña por qué no es
exacta: la volatilidad de 63 sesiones del control salta al principio de cada crisis, cuando la exposición aún es la de
la calma, y vuelve al 15 % en cuanto el EWMA se pone al día. La exposición media es 0,95 y la máxima 1,84; la rotación,
4,4 veces el capital al año. Y el Sharpe pasa de 0,43 a 0,84. Esa última cifra pide una explicación antes de creerla.

## Por qué mejora el Sharpe, y cuándo no

Reducir la exposición cuando la volatilidad sube mejora el Sharpe solo si la rentabilidad esperada **no sube en
proporción** a la volatilidad. Si la media fuera proporcional a la volatilidad (Sharpe constante), el control no
cambiaría nada; si fuera proporcional a la varianza, lo empeoraría. Es lo que dicen Moreira y Muir (2017): las
carteras gestionadas por volatilidad suben el Sharpe «porque los cambios de volatilidad no se compensan con cambios
proporcionales de la rentabilidad esperada». En los datos se puede mirar directamente, agrupando los días por
terciles de la volatilidad prevista:

```python
pyg = pd.read_csv("riesgo4_pyg.csv", index_col="fecha",
                  parse_dates=True)["rendimiento"]


def por_tercil(x):
    sig = np.sqrt((x**2).ewm(halflife=20).mean()).shift(1)
    t = pd.qcut(sig, 3, labels=["baja", "media", "alta"])
    t.name = "vol_prevista"
    grupos = x.groupby(t, observed=True)
    return pd.DataFrame({"media_anual": grupos.mean() * 252,
                         "vol_anual": grupos.std() * 252**0.5,
                         "sharpe": grupos.mean() / grupos.std()
                         * 252**0.5})


vv = est["venta_volatilidad"]
pd.concat({"libro GARCH": por_tercil(pyg),
           "RV_EEUU": por_tercil(rv),
           "tendencia": por_tercil(est["tendencia_futuros"])}
          ).round(2)
```
```output
                          media_anual  vol_anual  sharpe
            vol_prevista
libro GARCH baja                 0.10       0.08    1.24
            media                0.05       0.11    0.49
            alta                 0.17       0.25    0.67
RV_EEUU     baja                 0.14       0.13    1.05
            media                0.26       0.16    1.60
            alta                -0.13       0.29   -0.44
tendencia   baja                 0.06       0.08    0.76
            media                0.00       0.10    0.01
            alta                 0.11       0.13    0.83
```

- **Libro GARCH** (`riesgo4_pyg.csv`, lección 4.2.3): la media verdadera es constante y la volatilidad varía. El
  Sharpe medido cae de 1,24 en el tercil de calma a 0,67 en el de volatilidad alta (las medias, 0,10 y 0,17, son
  ruido alrededor de un 7,6 % anual). Es el caso de libro en que el control ayuda.
- **`RV_EEUU`**: en el tercil de volatilidad alta la media es **−13 %** anual. No es una ley del mercado, es el
  generador: las crisis del guion tienen deriva negativa y la calma una prima de alrededor del 20 % anual, calibrada
  para que la media de 20 años sea razonable. El control gana sobre todo porque evita los tramos que el generador hizo
  perdedores.
- **`tendencia_futuros`**: el tercil de volatilidad alta tiene el mejor Sharpe (0,83), porque la estrategia gana en
  las crisis por construcción. Ahí el control recorta justo cuando gana.

Con el mismo control en varias series (objetivo igual a la volatilidad de cada una, tope de 3 veces):

```python
series = {"libro GARCH": pyg, "RV_EEUU": rv,
          "RF_T710": exceso["RF_T710"], "MP_ORO": exceso["MP_ORO"],
          "tendencia": est["tendencia_futuros"],
          "venta_vol": vv,
          "cartera 9": cartera}
filas, fechas = {}, {}
for nombre, x in series.items():
    y, _ = vol_target(x, x.std() * 252**0.5, tope=3.0)
    a, d = metricas(x.loc[y.index]), metricas(y)
    filas[nombre] = {"sharpe_antes": a["sharpe"],
                     "sharpe_vt": d["sharpe"],
                     "peor_dia_antes": a["peor_dia"],
                     "peor_dia_vt": d["peor_dia"]}
    fechas[nombre] = str(y.idxmin().date())
tabla_vt = pd.DataFrame(filas).T.round(3)
tabla_vt["fecha_peor_vt"] = pd.Series(fechas)
tabla_vt
```
```output
             sharpe_antes  sharpe_vt  peor_dia_antes  peor_dia_vt fecha_peor_vt
libro GARCH         0.626      0.842          -0.087       -0.066    2010-06-18
RV_EEUU             0.427      0.837          -0.115       -0.123    2018-10-03
RF_T710             0.117      0.134          -0.025       -0.026    2015-10-20
MP_ORO              0.711      0.701          -0.079       -0.045    2008-12-22
tendencia           0.472      0.536          -0.049       -0.039    2018-09-28
venta_vol           0.303      0.537          -0.193       -0.279    2018-02-05
cartera 9           0.855      0.988          -0.023       -0.025    2018-02-05
```

En el libro GARCH el Sharpe sube de 0,63 a 0,84 y el peor día mejora. En los bonos (`RF_T710`) y el oro, el control
casi no cambia el Sharpe (0,12 a 0,13; 0,71 a 0,70). Es el patrón que describen Harvey et al. (2018) con más de 60
activos y datos diarios desde 1926: la mejora del Sharpe se limita a los activos de riesgo (acciones y crédito) y es
despreciable en renta fija, divisas y materias primas; el efecto que sí es general es que **reduce la probabilidad de
rendimientos extremos**. Y Cederburg et al. (2020), con 103 estrategias de acciones, encuentran que las versiones
gestionadas por volatilidad no superan de forma sistemática a las originales y que, con versiones implementables en
tiempo real, suelen tener menos Sharpe. En los datos del curso, que tienen la relación plantada, el control parece
mejor de lo que hay que esperar en un mercado real.

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

La mejora media no es el dato que importa al dimensionar. La columna `peor_dia_vt` de la tabla dice que el control
**empeora** el peor día en `RV_EEUU` (−11,5 % a −12,3 %), en la venta de volatilidad (−19,3 % a −27,9 %) y en la
cartera de las nueve. Un control por volatilidad sube la exposición en la calma, y los saltos llegan en la calma.

</aside>

## El peor episodio y lo que cuesta

Los dos peores días del control, con la volatilidad prevista y la exposición de la víspera:

```python
for nombre, x, ini, fin in [("venta_vol", vv, "2018-02-01",
                             "2018-02-07"),
                            ("RV_EEUU", rv, "2018-09-28",
                             "2018-10-05")]:
    _, e = vol_target(x, x.std() * 252**0.5, tope=3.0)
    sig = np.sqrt((x**2).ewm(halflife=20, min_periods=60).mean())
    t = pd.DataFrame({"rend": x, "sigmas": x / sig.shift(1),
                      "exposicion": e, "resultado": e * x})
    print(nombre)
    print(t.loc[ini:fin].round(3).to_string(), end="\n\n")
```
```output
venta_vol
             rend  sigmas  exposicion  resultado
fecha
2018-02-01 -0.004  -0.504       1.410     -0.005
2018-02-02 -0.004  -0.542       1.428     -0.006
2018-02-05 -0.193 -27.025       1.445     -0.279
2018-02-06 -0.002  -0.059       0.284     -0.001
2018-02-07  0.007   0.197       0.289      0.002

RV_EEUU
             rend  sigmas  exposicion  resultado
fecha
2018-09-28  0.006   0.498       1.107      0.006
2018-10-01 -0.024  -2.115       1.122     -0.027
2018-10-02  0.005   0.415       1.061      0.005
2018-10-03 -0.115  -9.505       1.076     -0.123
2018-10-04 -0.038  -1.572       0.535     -0.020
2018-10-05 -0.037  -1.476       0.522     -0.019
```

El 5 de febrero de 2018 la venta de volatilidad venía de meses tranquilos: la exposición era de 1,45 veces. Pierde un
19,3 %, **−27 desviaciones típicas** de lo que preveía el EWMA, y el control lo convierte en un −27,9 %. Al día
siguiente la exposición baja a 0,28, con la pérdida ya hecha. El 3 de octubre de 2018 `RV_EEUU` cae un 11,5 % (−9,5
desviaciones previstas) con una exposición de 1,08: −12,3 %. En los dos casos el control reacciona después, que es
lo único que puede hacer con datos de cierre. Su protección funciona en las crisis que llegan despacio (2008, 2022) y
no en los saltos: para esos están los límites por escenario de la lección 4.2.4, el tope de exposición y el kill
switch de la 4.2.5.

El control tampoco es gratis. Cada cambio de exposición se opera, y lo que pasa de 1 hay que financiarlo:

```python
liq = pd.read_csv("riesgo4_liquidez.csv", index_col="activo")
media_horq = liq.at["RV_EEUU", "horquilla_pb"] / 2 / 1e4
diferencial = 0.01        # supuesto: rf + 1 % por lo prestado


def con_costes(x, objetivo, banda=0.0):
    _, e = vol_target(x, objetivo)
    e = e.dropna()
    real = e.copy()
    for i in range(1, len(e)):                 # banda de no tocar
        prev = real.iloc[i - 1]
        if abs(e.iloc[i] / prev - 1) <= banda:
            real.iloc[i] = prev
    r = (real * x.loc[real.index]
         - real.diff().abs().fillna(0) * media_horq
         - (real - 1).clip(lower=0) * diferencial / 252)
    rot = real.diff().abs().sum() / (len(real) / 252)
    return {"sharpe": r.mean() / r.std() * 252**0.5,
            "rotacion_anual": rot,
            "coste_pb_año": (r.mean() - (real * x).mean())
            * -252 * 1e4}


pd.DataFrame({f"banda {b:.0%}": con_costes(rv, 0.15, b)
              for b in (0.0, 0.10, 0.25)}).T.round(3)
```
```output
           sharpe  rotacion_anual  coste_pb_año
banda 0%    0.829           4.440        11.989
banda 10%   0.824           1.901         9.981
banda 25%   0.746           1.200        10.160
```

Con la media horquilla del ETF de `RV_EEUU` (0,435 pb, `riesgo4_liquidez.csv`) y un diferencial de financiación
supuesto del 1 % sobre lo prestado, el coste es de unos 12 pb al año y el Sharpe pasa de 0,837 a 0,829. Una banda de
no negociar del 10 % reduce la rotación de 4,4 a 1,9 veces al año casi sin coste en Sharpe (0,824); una del 25 %
sigue peor el objetivo y el Sharpe baja a 0,746. En un activo líquido el coste es pequeño; en uno con una horquilla de
20 pb, la misma rotación costaría unos 44 pb al año solo en horquilla (lección 2.4.7).

## El método del research del sitio

El research «Volatility Targeting en Python» (enlace en «Recursos») propone otra regla sobre una cartera de acciones
y bonos largos: para cada activo, $P = \hat\sigma_{100}/\sigma_{\text{hist}}$, el cociente entre la volatilidad de
100 sesiones y la de toda la serie, y un peso $\max(1 - P, 0)$: exposición plena cuando la volatilidad es mínima y
cero cuando supera la media histórica. Es un control por volatilidad más agresivo que $\sigma^*/\hat\sigma$, que
sale del mercado en lugar de reducir. Replicado con `RV_EEUU` y `RF_T20` (rendimientos totales, como en el research):

```python
def metodo_1_menos_p(s, sin_anticipacion):
    """Peso = max(1 − vol de 100 sesiones / vol de referencia, 0)."""
    if sin_anticipacion:
        v = s.rolling(100).std().shift(1)
        ref = s.expanding(252).std().shift(1)
    else:                                   # como en el research
        v = s.rolling(100).std().shift(-2)
        ref = s.std()
    return (1 - v / ref).clip(lower=0) * s


def sharpe(r):
    r = r.dropna()
    return round(r.mean() / r.std() * 252**0.5, 3)


acc, bono = rend["RV_EEUU"], rend["RF_T20"]
print("60/40 fija:       ", sharpe(0.6 * acc + 0.4 * bono))
print("1 − P, shift(-2): ", sharpe(metodo_1_menos_p(acc, False)
                                   + metodo_1_menos_p(bono, False)))
print("1 − P, shift(1):  ", sharpe(metodo_1_menos_p(acc, True)
                                   + metodo_1_menos_p(bono, True)))
```
```output
60/40 fija:        0.619
1 − P, shift(-2):  1.18
1 − P, shift(1):   0.938
```

En el código del research la volatilidad móvil se desplaza con `.shift(-2)`. En pandas un desplazamiento **negativo**
trae valores del futuro: la fila $t$ recibe la volatilidad de la ventana que termina en $t+2$, que incluye los
rendimientos de $t$, $t+1$ y $t+2$ que la regla pretende ponderar. La referencia, la volatilidad de toda la serie,
también usa datos posteriores. Con esas dos anticipaciones el Sharpe es 1,18; calculando la volatilidad hasta ayer
(`shift(1)`) y la referencia solo con el pasado, 0,94. Las dos versiones superan a la 60/40 fija (0,62) en estos datos,
por la relación entre volatilidad y rentabilidad plantada que se ha visto arriba, pero la diferencia entre ellas,
0,24 de Sharpe, es anticipación y no se podría cobrar. Es el mismo error que la lección 2.5.1 busca en cualquier
backtest: la regla debe calcularse con lo que se sabía al decidir.

## Una regla de tamaño completa

Kelly y el control por volatilidad se combinan: Kelly da la volatilidad que se puede justificar (una fracción del
Sharpe que se espera de verdad, no del backtest) y el control la mantiene. Los límites de las lecciones vecinas la
acotan por arriba:

```mermaid
flowchart TB
  M[Sharpe esperado] --> F[Fracción c]
  F --> S[Vol. objetivo]
  S --> V[Control por vol.]
  V --> X[Tope y estrés]
  X --> K[Kill switch]
  K --> P[Posición]
```

| Paso | Qué decide | Coste o peor caso en esta lección |
|---|---|---|
| Sharpe esperado | El del backtest, rebajado por selección (2.5.4) y por régimen | Una media estimada con 5 años puede valer cero |
| Fracción $c$ | $\mathrm{SR}^2T/(1+\mathrm{SR}^2T)$ como máximo; menos con colas | Kelly completo: caída del −97,9 % en la cartera de las nueve |
| Volatilidad objetivo | $c \cdot \mathrm{SR}$ | Con Sharpe 0,8 y $c = 1/4$, un 20 %: ya es alta para una cuenta personal |
| Control por volatilidad | Exposición = objetivo / volatilidad de ayer | Saltos tras la calma: −27,9 % en un día en la venta de volatilidad |
| Tope y estrés | Exposición máxima y pérdida máxima por escenario (4.2.4) | El tope limita la exposición con la que llega el salto |
| Kill switch | Cortar si la estrategia deja de funcionar (4.2.5) | Una Kelly estimada con datos viejos apalanca una estrategia muerta |

En la práctica, la volatilidad objetivo de una cuenta personal suele fijarse muy por debajo de Kelly: la que se
aguanta sin cambiar de plan en la peor caída razonable, que es un número psicológico y financiero antes que
estadístico. Kelly sirve sobre todo de **techo**: por encima de él no hay nada que ganar.

## Ejercicios

1. **Kelly sobre una estrategia que se degrada.** Estima la Kelly de `degradada` con los datos hasta el 2019-06-30 y
   aplica medio Kelly, con esa cifra fija, a partir del 2019-07-01. Calcula el CAGR y la máxima caída de los dos tramos.
   ¿Qué dice esto del orden de los pasos de la tabla anterior?

**Solución.**

```python
deg = pd.read_parquet("estrategias4_diarias.parquet")
deg = deg.set_index("fecha")["degradada"]
antes, despues = deg[:"2019-06-30"], deg["2019-07-01":]
k_deg = antes.mean() / antes.var()
print(f"Kelly estimada hasta 2019-06: {k_deg:.1f}")
pd.DataFrame({"antes": resultado(0.5 * k_deg * antes),
              "después": resultado(0.5 * k_deg * despues)}
             ).T.astype(float).round(3)
```
```output
Kelly estimada hasta 2019-06: 16.8
          cagr  max_caida  peor_dia  ruina
antes    0.873     -0.830    -0.339    0.0
después -0.440     -0.997    -0.520    0.0
```

Con trece años y medio de una estrategia de Sharpe 1,30, la Kelly estimada es de 16,8 veces y medio Kelly (8,4 veces)
da un CAGR del 87,3 % antes del corte, ya con una caída del −83 %. Después, la misma exposición sobre una estrategia
sin ventaja pierde un 44 % al año, con una caída del −99,7 % y un día de −52 %: la volatilidad se queda y la media
desaparece. Kelly multiplica la ventaja que se le da; si la ventaja ya no existe, multiplica el ruido. Por eso
el kill switch (lección 4.2.5) va antes que cualquier optimización del tamaño y la estimación de la media debe
revisarse con datos recientes.

2. **La vida media del EWMA.** Aplica el control por volatilidad a `venta_volatilidad` con vidas medias de 5, 20 y 60
   sesiones (objetivo igual a su volatilidad, tope de 3). Compara el Sharpe, la máxima caída y el peor día. ¿Hay una
   vida media que evite el 5 de febrero de 2018?

**Solución.**

```python
obj = vv.std() * 252**0.5
pd.DataFrame({vm: metricas(vol_target(vv, obj, vm, 3.0)[0])
              for vm in (5, 20, 60)}).T[
    ["sharpe", "max_caida", "peor_dia"]].round(3)
```
```output
    sharpe  max_caida  peor_dia
5    0.550     -0.509    -0.470
20   0.537     -0.404    -0.279
60   0.445     -0.382    -0.249
```

Ninguna vida media evita el salto: el peor día es siempre el 5 de febrero de 2018. Con 5 sesiones es mucho peor
(−47,0 %): la vida media corta olvida antes la última crisis, así que tras unas semanas de calma la exposición es la
más alta. Con 60 sesiones el peor día es de −24,9 % y la caída máxima la menor (−38,2 %), a cambio de un Sharpe más
bajo (0,445 frente a 0,537), porque reacciona tarde y se queda con exposición baja más tiempo tras cada crisis. El salto de un día solo se controla con el tamaño que se tiene antes de
que ocurra: tope de exposición y límites por escenario.

3. **Un backtest corto y brillante.** Un sistema tiene un Sharpe de 1,5 en un backtest de 2 años y su autor quiere
   operar medio Kelly. ¿Qué fracción de la Kelly estimada recomienda la fórmula del error de estimación? ¿Qué más
   rebajarías y por qué?

**Solución.**

Con $\mathrm{SR} = 1{,}5$ y $T = 2$, $\mathrm{SR}^2T = 4{,}5$ y $c^{\text{opt}} = 4{,}5/5{,}5 \approx 0{,}82$: la
fórmula, tomada al pie de la letra, permitiría más que medio Kelly. Pero supone que el Sharpe de 1,5 es la verdad
medida sin sesgo. Un backtest de 2 años elegido entre varias variantes tiene un Sharpe inflado (lección 2.5.4). Si el
Sharpe verdadero fuera 0,5, la Kelly estimada con 1,5 sería el triple de la verdadera, y medio Kelly estimado serían
1,5 veces la Kelly verdadera: por encima del máximo de crecimiento, con un 75 % del crecimiento posible y un 79 % de
probabilidad de caer alguna vez a la mitad (tabla de las fracciones). Además, dos años no contienen
ninguna crisis, así que la volatilidad está subestimada y las correlaciones son las de la calma. Lo razonable es fijar
la volatilidad objetivo con un Sharpe esperado prudente (no el del backtest), empezar en paper trading (lección 4.5.3)
y subir el tamaño solo cuando la estrategia confirme en real.

## Autoevaluación

1. Una estrategia tiene un exceso esperado del 6 % anual y una volatilidad del 12 %. ¿Qué apalancamiento da Kelly y qué volatilidad tendría la cuenta?

   - A. 4,2 veces el capital y un 50 % de volatilidad, que es el Sharpe (0,5)
   - B. 0,5 veces el capital y un 6 % de volatilidad
   - C. 1 vez el capital: Kelly nunca apalanca
   - D. 12 veces el capital

   *Respuesta A: 4,2 veces el capital y un 50 % de volatilidad, que es el Sharpe (0,5).* f* = μ/σ² = 0,06/0,0144 ≈ 4,2. La volatilidad de la cuenta es f*·σ = μ/σ = Sharpe = 50 %. Con colas gruesas y una media estimada, nadie opera eso: de ahí las fracciones.

2. Con medio Kelly, ¿qué parte del crecimiento máximo se conserva y cuál es la probabilidad de caer alguna vez a la mitad del capital inicial (caso continuo, parámetros conocidos)?

   - A. El 50 % del crecimiento y un 50 % de probabilidad
   - B. El 75 % del crecimiento y un 12,5 % de probabilidad, frente al 50 % de Kelly completo
   - C. El 100 % del crecimiento y ninguna probabilidad
   - D. El 25 % del crecimiento y un 1 % de probabilidad

   *Respuesta B: El 75 % del crecimiento y un 12,5 % de probabilidad, frente al 50 % de Kelly completo.* El crecimiento relativo es 2c − c² = 0,75 y la probabilidad de tocar x es x elevado a 2/c − 1: 0,5³ = 0,125. La simulación de la moneda da 0,116 con mil apuestas.

3. Una estrategia de Sharpe 0,4 se ha medido con 5 años de datos. Si se apuesta la Kelly estimada completa, ¿qué crecimiento se espera respecto al de la Kelly verdadera?

   - A. El 100 %: la estimación es insesgada
   - B. El 75 %
   - C. El 50 %
   - D. Negativo (−24 %): el error de la media hace que la Kelly estimada supere a menudo el doble de la verdadera

   *Respuesta D: Negativo (−24 %): el error de la media hace que la Kelly estimada supere a menudo el doble de la verdadera.* Con 5 años, f estimada / f verdadera tiene una desviación típica de 1/(0,4·√5) ≈ 1,1. El crecimiento esperado es 2c − c²(1 + 1/(SR²T)) = 2 − 2,25 < 0. La fracción que lo maximiza es 0,44.

4. En los datos, el volatility targeting sube el Sharpe de `RV_EEUU` de 0,43 a 0,84. ¿Por qué no hay que esperar lo mismo en un mercado real?

   - A. Porque los datos tienen errores
   - B. Porque el control usa información futura
   - C. Porque en el generador los tramos de volatilidad alta tienen deriva negativa y la calma una prima alta (≈ 20 % anual): el control gana sobre todo por esa relación plantada; en la literatura la mejora es pequeña o no sobrevive fuera de muestra
   - D. Porque la renta variable real no tiene volatilidad variable

   *Respuesta C: Porque en el generador los tramos de volatilidad alta tienen deriva negativa y la calma una prima alta (≈ 20 % anual): el control gana sobre todo por esa relación plantada; en la literatura la mejora es pequeña o no sobrevive fuera de muestra.* El control mejora el Sharpe cuando la rentabilidad esperada no sube en proporción a la volatilidad. En `RV_EEUU` el tercil de volatilidad alta rinde un −13 % anual por construcción. Harvey et al. (2018) encuentran mejora en activos de riesgo y casi ninguna en bonos, divisas y materias primas; Cederburg et al. (2020), que fuera de muestra no supera de forma sistemática a la cartera sin gestionar.

5. El 5 de febrero de 2018 la venta de volatilidad pierde un 19,3 % sin control y un 27,9 % con volatility targeting. ¿Qué pasó?

   - A. Un error de datos
   - B. El control vendió en el peor momento
   - C. La volatilidad prevista era baja tras meses de calma, así que la exposición era de 1,45 veces; un salto de −27 desviaciones previstas no da tiempo a reducirla
   - D. El tope de exposición no funcionó

   *Respuesta C: La volatilidad prevista era baja tras meses de calma, así que la exposición era de 1,45 veces; un salto de −27 desviaciones previstas no da tiempo a reducirla.* El control reacciona a la volatilidad pasada. Un salto sin aviso llega con la exposición en su máximo y el control lo amplifica. Al día siguiente la exposición baja a 0,28, cuando la pérdida ya está hecha.

## Ideas clave

- Kelly maximiza el crecimiento a largo plazo con `f* = μ/σ²`; a Kelly, la volatilidad de la cuenta es el Sharpe. Para la cartera de las nueve estrategias eso son 18,8 veces el capital y un 84 % de volatilidad.
- Apostar por encima de Kelly es un mal negocio: a 2 veces Kelly el crecimiento es cero con todo el riesgo. Por debajo, se pierde poco crecimiento y mucha caída: medio Kelly conserva el 75 % del crecimiento con la mitad de volatilidad.
- La media se estima mal: con una muestra de T años, la fracción que maximiza el crecimiento esperado es SR²T/(1 + SR²T) de la Kelly estimada (0,44 con 5 años y Sharpe 0,4), y menos si el Sharpe del backtest está inflado.
- El volatility targeting mantiene el riesgo estable y reduce la máxima caída, pero solo sube el Sharpe si la rentabilidad no crece con la volatilidad; en los datos esa relación está plantada y en la literatura es frágil.
- Su peor episodio es el salto tras la calma: exposición alta y pérdida mayor que sin control (−27,9 % frente a −19,3 % en la venta de volatilidad).
- Una regla de tamaño se calcula con lo que se sabía cada día: un `shift(-2)` en la volatilidad sube el Sharpe del método 1 − P de 0,94 a 1,18 sin que la regla sea mejor.

## Recursos

### Research

- [Volatility Targeting en Python](https://pythonparatrading.com/volatility-targeting/) · Research-0004 · 8 min

### Libros

- [Kelly, J. L. (1956): A New Interpretation of Information Rate. Bell System Technical Journal 35(4), 917-926](https://doi.org/10.1002/j.1538-7305.1956.tb03809.x) · doi.org
- [Thorp, E. O. (2006): The Kelly Criterion in Blackjack, Sports Betting, and the Stock Market. Handbook of Asset and Liability Management, cap. 9](https://doi.org/10.1016/S1872-0978(06)01009-X) · doi.org
- [Moreira, A. y Muir, T. (2017): Volatility-Managed Portfolios. The Journal of Finance 72(4), 1611-1644](https://doi.org/10.1111/jofi.12513) · doi.org
- [Harvey, C. R. et al. (2018): The Impact of Volatility Targeting. The Journal of Portfolio Management 45(1), 14-33](https://doi.org/10.3905/jpm.2018.45.1.014) · doi.org
- [Cederburg, S. et al. (2020): On the performance of volatility-managed portfolios. Journal of Financial Economics 138(1), 95-117](https://doi.org/10.1016/j.jfineco.2020.04.015) · doi.org

### Datos

- [Datos del nivel 4: rendimientos diarios de diez estrategias (Parquet)](https://pythonparatrading.com/curso/datos/nivel-4/estrategias4_diarias.parquet) · Descarga · estrategias4_diarias.parquet

Lección anterior: [4.2.1 · Riesgo por operación, stops y riesgo de ruina](https://pythonparatrading.com/curso-python-trading/nivel-4/riesgo-por-operacion-stops-y-riesgo-de-ruina/)

Lección siguiente: [4.2.3 · VaR, Expected Shortfall y backtesting del VaR](https://pythonparatrading.com/curso-python-trading/nivel-4/var-expected-shortfall-y-backtesting-del-var/)
