Lección 4.2.2 · 70 min

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.

Fig. — Apostar una fracción c de Kelly: crecimiento esperado del capital, en % del máximo, y probabilidad de caer alguna vez a la mitad del capital inicial
Lecciones del nivel 4
  1. 4.1 · Teoría y optimización de carteras

    1. 4.1.1 Markowitz: frontera eficiente y restricciones reales
    2. 4.1.2 Estimación de covarianzas: shrinkage, modelos factoriales y denoising
    3. 4.1.3 Black-Litterman: del equilibrio del mercado a las visiones
    4. 4.1.4 Risk parity, mínima varianza, HRP y HERC
    5. 4.1.5 Optimización con CVaR, drawdown, rotación y costes
    6. 4.1.6 Modelos factoriales: CAPM, Fama-French, PCA y atribución
    7. 4.1.7 Rebalanceo y carteras de estrategias
    8. 4.1.8 Herramientas de carteras: Riskfolio-Lib, PyPortfolioOpt, skfolio y bt
  2. 4.2 · Gestión del riesgo y tamaño de posición

    1. 4.2.1 Riesgo por operación, stops y riesgo de ruina
    2. 4.2.2 Criterio de Kelly y volatility targeting: cuánto arriesgar
    3. 4.2.3 VaR, Expected Shortfall y backtesting del VaR
    4. 4.2.4 Stress testing y riesgos de correlación, liquidez, gap y contraparte
    5. 4.2.5 Control del drawdown y kill switch
    6. 4.2.6 Riesgo de derivados: griegas de cartera, margen y liquidaciones
  3. 4.3 · Microestructura y ejecución

    1. 4.3.1 Implementation shortfall, VWAP, TWAP y Almgren-Chriss
    2. 4.3.2 Order flow imbalance, señales de microestructura y latencia
  4. 4.4 · Brokers y APIs

    1. 4.4.1 Elegir bróker desde España o la UE: regulación, activos, costes y API
    2. 4.4.2 Interactive Brokers: TWS e IB Gateway, ib_async, contratos, datos y órdenes
    3. 4.4.3 Alpaca, Tradier, MetaTrader 5 con Python y OANDA v20
    4. 4.4.4 APIs de exchanges cripto: ccxt, Binance, Bybit, Kraken y Coinbase
    5. 4.4.5 Credenciales seguras: variables de entorno, gestores de secretos y permisos mínimos
  5. 4.5 · Sistema de trading en vivo

    1. 4.5.1 Arquitectura de un sistema en vivo: de los datos a la reconciliación
    2. 4.5.2 Gestión de órdenes: estados, fills parciales, cancelaciones y reconexiones
    3. 4.5.3 Paper trading, shadow trading y seguimiento del slippage
    4. 4.5.4 Programación de tareas y alertas: cron, APScheduler, Prefect, Telegram, Slack y email
    5. 4.5.5 Tolerancia a fallos: idempotencia, estado persistente y reconciliación al arrancar
    6. 4.5.6 NautilusTrader o LEAN en real: del backtest a producción con el mismo código

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 ff 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 bb por unidad con probabilidad pp y pierde la unidad con q=1−pq = 1 - p:

g(f)=p ln⁡(1+fb)+q ln⁡(1−f),f∗=p−qb.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,10f^* = 0{,}10: apostar el 10 % del capital en cada tirada.

IN [01]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)
OUT [01]Una moneda con ventaja
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,10f = 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í:

IN [02]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)
OUT [02]Mil apuestas, 4.000 jugadores
      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 ff veces y rebalanceada a menudo, el crecimiento logarítmico del exceso es g(f)=fμ−12f2σ2g(f) = f\mu - \tfrac{1}{2}f^2\sigma^2, una parábola. Su máximo:

f∗=μσ2,g∗=12 SR2,f∗σ=μσ=SR.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 cc de Kelly, el crecimiento es g∗(2c−c2)g^*(2c - c^2) y la volatilidad c⋅SRc\cdot\mathrm{SR}. El logaritmo del capital es entonces un movimiento browniano con deriva ν=SR2(c−c2/2)\nu = \mathrm{SR}^2(c - c^2/2) y varianza s2=c2SR2s^2 = c^2\mathrm{SR}^2, y la probabilidad de que caiga alguna vez hasta una fracción xx del capital inicial es x2ν/s2=x2/c−1x^{2\nu/s^2} = x^{2/c - 1} (la de tocar una barrera inferior, con parámetros conocidos y horizonte infinito):

IN [03]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)
OUT [03]Fracciones de Kelly: crecimiento, volatilidad y caídas
          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 μ/σ2\mu/\sigma^2, la celda calcula la Kelly «exacta» de los datos (la ff que maximiza la media de ln⁡(1+frt)\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:

IN [04]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)
OUT [04]Kelly de cada estrategia
                     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∗σ=SRf^*\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:

IN [05]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)
OUT [05]La cartera de las nueve con fracciones de Kelly
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

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:

IN [06]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)
OUT [06]Kelly con lo que se sabía cada día
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 TT años de datos, la media muestral tiene un error típico de σ/T\sigma/\sqrt{T}, así que la Kelly estimada es f^=f∗ u\hat f = f^*\,u con u∼N ⁣(1,1SR2T)u \sim N\!\left(1, \tfrac{1}{\mathrm{SR}^2 T}\right). Apostar una fracción cc de la Kelly estimada da un crecimiento esperado, relativo al de la Kelly verdadera, de

undefined

Respuesta plegada en cada pregunta

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?

    • A4,2 veces el capital y un 50 % de volatilidad, que es el Sharpe (0,5)
    • B0,5 veces el capital y un 6 % de volatilidad
    • C1 vez el capital: Kelly nunca apalanca
    • D12 veces el capital
    Ver respuesta

    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)?

    • AEl 50 % del crecimiento y un 50 % de probabilidad
    • BEl 75 % del crecimiento y un 12,5 % de probabilidad, frente al 50 % de Kelly completo
    • CEl 100 % del crecimiento y ninguna probabilidad
    • DEl 25 % del crecimiento y un 1 % de probabilidad
    Ver respuesta

    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?

    • AEl 100 %: la estimación es insesgada
    • BEl 75 %
    • CEl 50 %
    • DNegativo (−24 %): el error de la media hace que la Kelly estimada supere a menudo el doble de la verdadera
    Ver respuesta

    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?

    • APorque los datos tienen errores
    • BPorque el control usa información futura
    • CPorque 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
    • DPorque la renta variable real no tiene volatilidad variable
    Ver respuesta

    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ó?

    • AUn error de datos
    • BEl control vendió en el peor momento
    • CLa 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
    • DEl tope de exposición no funcionó
    Ver respuesta

    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