---
title: "2.3.1 Seguimiento de tendencia y momentum"
description: "Momentum de series temporales con escalado de volatilidad, cruces, rupturas Donchian y Turtle, momentum transversal 12-1 y rotación sectorial."
url: "https://pythonparatrading.com/curso-python-trading/nivel-2/seguimiento-de-tendencia-y-momentum/"
lang: "es"
image: "https://pythonparatrading.com/og/curso-python-trading/nivel-2/seguimiento-de-tendencia-y-momentum.png"
---

# 2.3.1 · Seguimiento de tendencia y momentum

> Dos familias con el mismo nombre: comprar lo que sube frente a su propia historia (tendencia) o frente a los demás (momentum transversal). Esta lección construye las dos con costes y ejecución a la sesión siguiente, sobre 24 futuros y 120 acciones sintéticas con la prima plantada, y las compara con controles que no tienen ninguna.

- Curso: [Nivel 2: Estrategias sistemáticas y backtesting riguroso](https://pythonparatrading.com/curso-python-trading/nivel-2/)
- Módulo: 2.3 · Familias de estrategias
- Duración: 75 min
- Requisitos: [1.4.6 · Series continuas de futuros: reglas de roll, ajuste por diferencia y ajuste por ratio](https://pythonparatrading.com/curso-python-trading/nivel-1/series-continuas-de-futuros/), [1.4.4 · Universos sin sesgo de supervivencia: deslistados, fusiones y cambios de símbolo](https://pythonparatrading.com/curso-python-trading/nivel-1/sesgo-de-supervivencia-y-point-in-time/), [1.6.1 · Rentabilidades, volatilidad, correlaciones móviles y drawdown](https://pythonparatrading.com/curso-python-trading/nivel-1/volatilidad-correlaciones-y-drawdown/)

## Al terminar esta lección

- Programar momentum de series temporales con escalado de volatilidad, un cruce de medias y una ruptura Donchian tipo Turtle, con costes por lado, coste del roll y ejecución en la sesión siguiente.
- Comprobar con controles por permutación qué parte del resultado es tendencia y qué parte es la deriva media de cada mercado.
- Comprobar si la tendencia tiene «sonrisa» frente a la renta variable y en qué crisis gana o pierde.
- Evaluar el momentum transversal 12-1 con IC de rangos, carteras por deciles, rentabilidades de deslistado y un placebo, y explicar por qué el IC lineal y el diferencial de deciles exageran.
- Reconocer los crashes del momentum tras los suelos de mercado y el límite estadístico de una rotación entre diez sectores.

## Dos ideas con el mismo nombre

«Momentum» se usa para dos estrategias distintas que comparten una intuición: lo que ha subido tiende a seguir
subiendo durante un tiempo. La diferencia está en contra qué se compara.

- **Momentum de series temporales** (*time series momentum*, TSMOM, o simplemente **tendencia**): cada activo se
  compara con su propio pasado. Si el futuro del crudo ha subido en los últimos doce meses, se compra; si ha bajado,
  se vende. Cada mercado se decide por separado y la cartera puede estar larga o corta en todo a la vez. Es lo que
  hacen los CTA y los fondos de gestión de futuros.
- **Momentum transversal** (*cross-sectional momentum*): los activos se comparan entre sí. Cada mes se ordenan las
  acciones por su rentabilidad pasada, se compran las mejores y se venden las peores. La cartera es neutral por
  construcción: gana si los ganadores baten a los perdedores, aunque todo el mercado caiga.

```mermaid
flowchart TB
  P[Precios pasados] --> TS[Contra su pasado]
  P --> XS[Contra los demás]
  TS --> S1[Signo por activo]
  XS --> S2[Rango en el corte]
  S1 --> R1[Largo o corto neto]
  S2 --> R2[Largo-corto neutro]
```

Las dos tienen evidencia académica amplia en datos reales. Jegadeesh y Titman documentaron en 1993 que comprar
ganadores y vender perdedores de los 3 a 12 meses anteriores daba rentabilidades positivas significativas en acciones
de EE. UU., y que parte se deshacía en los dos años siguientes[^1]. Moskowitz, Ooi y Pedersen encontraron en 2012
momentum de series temporales en cada uno de los 58 futuros líquidos que estudiaron (índices, divisas, materias
primas y bonos): persistencia de 1 a 12 meses que se revierte en parte a horizontes más largos, y una cartera
diversificada que rinde mejor en los mercados extremos[^2]. Esta lección no repite esas cifras: construye las
estrategias con el método de esos trabajos y las prueba en datos donde se conoce la respuesta.

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

Los datos son **sintéticos y el efecto está plantado**. En los futuros, el generador añade al rendimiento esperado
anual `0,15·σ·signo(rentabilidad de las 252 sesiones anteriores)`: un Sharpe de tendencia de ≈ 0,15 por mercado. En
las acciones, una prima mensual de `0,0025·z` sobre la puntuación por rangos del momentum 12-1, y crashes en los tres
meses tras los suelos de 2009 y 2020. Que una regla gane aquí demuestra que el código la recupera, no que funcione en
un mercado real.

</aside>

## Futuros: rentabilidades, rolls y costes

Los 24 mercados de `futuros2_continuos.parquet` cubren índices, bonos, energía, metales, agrícolas y divisas de 2000 a
2025. La columna `cierre_ajustado` es la serie continua con ajuste proporcional hacia atrás en cada roll: su variación
porcentual es la rentabilidad de mantener el futuro (lección 1.4.6). La columna `contrato` dice qué vencimiento se
tiene cada día, y con ella se detectan los rolls, que cuestan dinero.

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

fut = pd.read_parquet("futuros2_continuos.parquet")
spec = pd.read_csv("futuros2_especificaciones.csv")
spec = spec.set_index("mercado")
ancho = lambda col: fut.pivot(index="fecha", columns="mercado",
                              values=col)
px, cierre, contrato = (ancho("cierre_ajustado"), ancho("cierre"),
                        ancho("contrato"))
r = px.pct_change()
roll = (contrato != contrato.shift()).astype(float)
roll.iloc[0] = 0.0
print(px.shape[1], "mercados,", len(px), "sesiones,",
      px.index[0].date(), "a", px.index[-1].date())
rolls_ano = (roll.sum() / 26).round().astype(int)
print("rolls al año:", rolls_ano.value_counts().sort_index().to_dict())
```
```output
24 mercados, 6539 sesiones, 2000-01-03 a 2025-12-31
rolls al año: {4: 14, 5: 5, 6: 1, 7: 1, 12: 3}
```

Cuatro rolls al año en los financieros (vencimientos trimestrales), doce en la energía (mensuales) y entre cuatro y
siete en metales y agrícolas. Cada roll son dos operaciones: cerrar el contrato que vence y abrir el siguiente.

El coste de una operación sale de las especificaciones: un deslizamiento típico en ticks por lado más la comisión por
contrato. Para expresarlo como fracción del nominal hay que dividir por el valor del contrato, `cierre × multiplicador`:

$$
c_{\text{lado}} = \frac{n_{\text{ticks}} \cdot \text{tick}}{F} + \frac{\text{comision}}{F \cdot \text{multiplicador}}
$$

```python
c_lado = (spec["coste_tipico_ticks"] * spec["tick"] / cierre
          + spec["comision_usd"] / (cierre * spec["multiplicador"]))
pb = (1e4 * c_lado.median()).sort_values()
print(pb.round(1).iloc[[0, 1, 2, 12, 21, 22, 23]].to_string())
print(f"mediana de los 24 mercados: {pb.median():.1f} pb")
```
```output
mercado
IDB     0.7
DIA     0.8
BOA     0.9
BOE     3.1
AGA    10.9
AGB    11.3
MEB    13.2
mediana de los 24 mercados: 2.7 pb
```

La salida enseña los tres más baratos, el mercado del centro y los tres más caros. La mediana de los 24 es de 2,7
puntos básicos por lado, pero los extremos se separan casi veinte veces por una razón que conviene recordar con
datos reales: el tick es fijo en precio. En el índice IDB, un tick de 0,25 puntos sobre un precio mediano de unos
5.000 pesa medio punto básico; en la plata (MEB), un tick de 0,005 USD sobre unos 7,9 USD pesa más de 6, y las
especificaciones suponen dos ticks de deslizamiento por lado: 13,2 pb. El coste relevante no es «un tick», sino un
tick dividido por el precio, y cambia con el tiempo: el trigo (AGB) se mueve en estos datos entre 1,86 y 11,58 USD, así
que el mismo tick le cuesta seis veces más en porcentaje en su suelo que en su pico.

## Momentum de series temporales con escalado de volatilidad

La regla de Moskowitz, Ooi y Pedersen tiene dos piezas. La señal es el signo de la rentabilidad de los últimos doce
meses. El tamaño hace que cada mercado tenga el mismo riesgo ex ante: la posición es un objetivo de volatilidad
(40 % anual en el artículo) dividido por la volatilidad estimada con una media exponencial de los rendimientos
diarios al cuadrado, con centro de masa de 60 sesiones y con datos hasta la víspera[^2]:

$$
w_{i,t} = \operatorname{signo}\left(\frac{P_{i,t}}{P_{i,t-252}} - 1\right) \cdot \frac{40\,\%}{\hat\sigma_{i,t}}
$$

Sin ese escalado, el gas natural (50 % de volatilidad anual en estos datos) pesaría veinticinco veces más que el
bono a 2 años (2 %). Con él, la media de los 24 mercados es una cartera en la que cada uno aporta un riesgo parecido.

La ejecución es la de todo el nivel: la señal se calcula con el cierre de la sesión `t` y se opera al cierre de `t+1`;
la posición gana o pierde desde ahí. Los costes se cobran sobre cada cambio de posición y sobre la posición entera en
cada roll (dos lados).

```mermaid
flowchart LR
  C[Cierre t] --> S[Señal y tamaño]
  S --> E[Orden cierre t+1]
  E --> G[Gana desde t+1]
```

```python
def backtest(senal, r, objetivo=0.40):
    """Señal en {-1, 0, 1} decidida al cierre de t; se opera en t+1."""
    vol = r.ewm(com=60, min_periods=60).std() * np.sqrt(252)
    w = (senal * objetivo / vol).clip(-4, 4)
    pos = w.shift(1).fillna(0.0)          # tenida desde el cierre t+1
    bruto = (pos.shift(1) * r).fillna(0.0)
    giro = (pos - pos.shift()).abs()
    coste = (giro * c_lado + pos.abs() * roll * 2 * c_lado).fillna(0.0)
    return bruto.mean(axis=1), coste.mean(axis=1), pos

def sharpe(x):
    return x.mean() / x.std() * np.sqrt(252)

def resumen(bruto, coste):
    neto = bruto - coste
    return pd.Series({
        "sharpe_bruto": sharpe(bruto), "sharpe_neto": sharpe(neto),
        "vol_anual": neto.std() * np.sqrt(252),
        "coste_anual": coste.mean() * 252,
        "max_dd": ((1 + neto).cumprod()
                   / (1 + neto).cumprod().cummax() - 1).min()})

tsmom = np.sign(px / px.shift(252) - 1)
b_ts, c_ts, pos_ts = backtest(tsmom, r)
resumen(b_ts, c_ts).round(3)
```
```output
sharpe_bruto    0.946
sharpe_neto     0.772
vol_anual       0.105
coste_anual     0.018
max_dd         -0.212
dtype: float64
```

La cartera de 24 mercados tiene un Sharpe bruto de 0,95 y neto de 0,77, con una volatilidad del 10,5 % anual (cerca
del 12 % que da el artículo con el mismo objetivo del 40 % por mercado) y una caída máxima del 21 %. Los costes, 1,8
puntos al año, se llevan casi una quinta parte del Sharpe: el escalado de volatilidad cambia la posición todos los
días un poco, y cada roll paga dos lados sobre toda la posición. El README de los datos da, con otra ponderación
(10 % sobre la volatilidad de 63 sesiones) y sin costes, un Sharpe de 0,98 para la misma señal: el motor recupera lo
que el generador puso. El `clip(-4, 4)` limita el apalancamiento de un mercado a
cuatro veces su nominal cuando su volatilidad estimada se hunde. La figura de la cabecera enseña cómo crece 1 USD con esta regla y
con las otras dos de la lección, frente al control de la sección siguiente.

```python
vol = r.ewm(com=60, min_periods=60).std() * np.sqrt(252)
pos_m = (tsmom * 0.40 / vol).clip(-4, 4).shift(1).fillna(0.0)
bruto_m = (pos_m.shift(1) * r).fillna(0.0)
coste_m = ((pos_m - pos_m.shift()).abs() * c_lado
           + pos_m.abs() * roll * 2 * c_lado).fillna(0.0)
por_mercado = pd.DataFrame({
    "bruto": bruto_m.apply(sharpe),
    "neto": (bruto_m - coste_m).apply(sharpe)})
print(por_mercado.describe().loc[["mean", "50%", "min", "max"]]
      .round(2).T.to_string())
print("mercados con Sharpe neto > 0:",
      (por_mercado["neto"] > 0).sum(), "de 24")
rho = (bruto_m.corr().to_numpy()[np.triu_indices(24, 1)]).mean()
print(f"correlación media entre mercados: {rho:.2f}")
```
```output
       mean   50%   min   max
bruto  0.29  0.26 -0.13  0.79
neto   0.24  0.24 -0.25  0.71
mercados con Sharpe neto > 0: 21 de 24
correlación media entre mercados: 0.05
```

Mercado a mercado, el Sharpe bruto medio es 0,29 y la mediana 0,26: por encima del 0,15 plantado, porque la regla
también captura las tendencias del guion (las crisis largas en los índices, la caída de los bonos en 2022) y la
deriva de los índices. El rango va de −0,13 a 0,79, y 21 de los 24 mercados ganan en neto: con 26 años de datos, el
error típico de un Sharpe anual es ≈ 1/√26 ≈ 0,20, así que la dispersión entre mercados es casi toda ruido. Lo que
convierte una ventaja pequeña y ruidosa en una cartera con Sharpe de 0,95 es la diversificación: con una correlación
media de 0,05 entre los resultados de los mercados,

$$
SR_{\text{cartera}} \approx SR_{\text{mercado}} \sqrt{\frac{N}{1 + (N-1)\rho}} = 0{,}29 \sqrt{\frac{24}{1 + 23 \cdot 0{,}05}} \approx 0{,}97
$$

Es la razón de ser de los CTA: ninguna tendencia individual es fiable, pero muchas poco correladas sí suman.

## Un control que hay que saber leer

¿Cuánto de ese Sharpe es tendencia de verdad? El control natural es repetir la estrategia sobre rendimientos
**permutados**: los mismos rendimientos diarios de cada mercado en un orden aleatorio, sin ninguna memoria. Si la
regla solo explotara la tendencia, daría cero. Hay dos maneras de permutar, y en general no dicen lo mismo:

```python
rng = np.random.default_rng(2028)

def permuta(r, quitar_media):
    out = r.copy()
    for m in r:
        v = r[m].to_numpy().copy()
        ok = ~np.isnan(v)
        x = v[ok] - (v[ok].mean() if quitar_media else 0.0)
        v[ok] = rng.permutation(x)
        out[m] = v
    return out

for quitar_media in (False, True):
    res = []
    for _ in range(10):
        rp = permuta(r, quitar_media)
        pp = (1 + rp.fillna(0)).cumprod()
        b, c, _ = backtest(np.sign(pp / pp.shift(252) - 1), rp)
        res.append([sharpe(b), sharpe(b - c)])
    m, s = np.mean(res, axis=0), np.std(res, axis=0)
    print(f"media restada={quitar_media!s:5}  bruto {m[0]:+.2f} "
          f"± {s[0]:.2f}   neto {m[1]:+.2f} ± {s[1]:.2f}")
```
```output
media restada=False  bruto +0.06 ± 0.17   neto -0.21 ± 0.18
media restada=True   bruto -0.12 ± 0.22   neto -0.39 ± 0.22
```

Las dos permutaciones dan un Sharpe bruto compatible con cero: +0,06 ± 0,17 sin restar la media y −0,12 ± 0,22
restándola, en diez permutaciones cada una. En neto, −0,21 y −0,39: lo que cuesta operar sin ventaja. Frente a esos
controles, el 0,95 de la regla real está a más de cuatro desviaciones típicas: es tendencia, no ruido.

La diferencia entre las dos versiones es la que hay que saber leer. Permutar conserva la **media** de cada mercado.
En un mercado que sube en promedio, la rentabilidad de doce meses es positiva la mayor parte del tiempo y la regla
está casi siempre larga: cobra la deriva, no una tendencia. Por eso el control sin restar la media sale por encima
del otro (aquí, unos 0,2 de Sharpe, que con diez permutaciones tampoco se separa del ruido). En estos datos esa parte es pequeña porque casi no hay deriva que cobrar: los
bonos no tienen prima de plazo, las materias primas y las divisas revierten a un ancla a través del carry y solo los
cinco índices llevan la prima de la renta variable. En mercados reales, con décadas de bonos al alza y de prima de
la renta variable, la deriva puede ser una parte grande de lo que gana una regla de tendencia larga en promedio.
Las dos fuentes son legítimas, pero son dos apuestas distintas y conviene saber cuánto pesa cada una.

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

Moskowitz, Ooi y Pedersen hacen una descomposición parecida: separan lo que la estrategia gana por la covarianza entre
la señal y el rendimiento futuro (el momentum propiamente dicho) de lo que gana por las medias de los rendimientos. Es
la pregunta correcta ante cualquier regla larga-corta en activos con deriva: ¿bate a estar largo o corto
permanentemente según el signo de la media?

</aside>

## Cruces de medias y rupturas Donchian: la misma idea, otro horizonte

Las reglas clásicas de los CTA son variaciones de la misma idea con otros filtros:

- **Cruce de medias**: largo si la media de 50 sesiones está por encima de la de 200; corto si está por debajo
  (lección 1.7.1 para las medias).
- **Ruptura Donchian**: largo cuando el precio supera el máximo de las `n` sesiones anteriores; corto cuando perfora
  el mínimo. Las reglas originales de los Turtle, publicadas por uno de los traders del grupo, usaban dos sistemas
  basados en el canal de Richard Donchian: el Sistema 1, con ruptura de 20 sesiones y salida al perforar el extremo
  contrario de 10, y el Sistema 2, con 55 y 20[^3]. El tamaño dependía de `N`, la media exponencial de 20 sesiones
  del rango verdadero: cada unidad se dimensionaba para que un movimiento de `N` costara el 1 % de la cuenta. Es otra
  forma de escalar por volatilidad.

La ruptura es una máquina de estados: plano, largo o corto, con transiciones que dependen del canal.

```mermaid
stateDiagram-v2
  [*] --> PLANO
  PLANO --> LARGO: rompe máx. 55
  PLANO --> CORTO: rompe mín. 55
  LARGO --> PLANO: pierde mín. 20
  CORTO --> PLANO: supera máx. 20
  LARGO --> CORTO: rompe mín. 55
  CORTO --> LARGO: rompe máx. 55
```

Con datos de cierre no hay máximos y mínimos de sesión, así que el canal se calcula con cierres y el tamaño se hace
con la misma volatilidad EWMA que la regla de 12 meses: así las tres reglas solo se diferencian en la señal.

```python
cruce = np.sign(px.rolling(50).mean() - px.rolling(200).mean())

def donchian(p, entrada=55, salida=20):
    alto = p.rolling(entrada).max().shift(1).to_numpy()
    bajo = p.rolling(entrada).min().shift(1).to_numpy()
    s_alto = p.rolling(salida).max().shift(1).to_numpy()
    s_bajo = p.rolling(salida).min().shift(1).to_numpy()
    a = p.to_numpy()
    out = np.zeros(a.shape)
    for j in range(a.shape[1]):
        est = 0
        for i in range(a.shape[0]):
            if np.isnan(alto[i, j]):
                continue
            x = a[i, j]
            if x > alto[i, j]:
                est = 1
            elif x < bajo[i, j]:
                est = -1
            elif est == 1 and x < s_bajo[i, j]:
                est = 0
            elif est == -1 and x > s_alto[i, j]:
                est = 0
            out[i, j] = est
    return pd.DataFrame(out, index=p.index, columns=p.columns)

ruptura = donchian(px)
b_cr, c_cr, _ = backtest(cruce, r)
b_dn, c_dn, _ = backtest(ruptura, r)
tabla = pd.DataFrame({"tsmom_12m": resumen(b_ts, c_ts),
                      "cruce_50_200": resumen(b_cr, c_cr),
                      "donchian_55_20": resumen(b_dn, c_dn)})
print(tabla.round(3).to_string())
print("tiempo en mercado de la ruptura:",
      f"{(ruptura != 0).to_numpy().mean():.0%}")
```
```output
              tsmom_12m  cruce_50_200  donchian_55_20
sharpe_bruto      0.946         0.819           0.647
sharpe_neto       0.772         0.701           0.491
vol_anual         0.105         0.106           0.091
coste_anual       0.018         0.012           0.014
max_dd           -0.212        -0.214          -0.311
tiempo en mercado de la ruptura: 63%
```

Las tres reglas ganan con la misma prima plantada, y el orden sigue al horizonte. La regla de 12 meses, que mira
exactamente lo que el generador premia (el signo de las 252 sesiones anteriores), tiene el mejor Sharpe neto (0,77);
el cruce 50/200, que mira tendencias de varios meses, se queda cerca (0,70, con la misma caída máxima del 21 %); la
ruptura Donchian es la peor (0,49 neto, caída del 31 %). La ruptura solo está en el mercado el 63 % del tiempo,
porque la salida de 20 sesiones la deja plana tras cualquier retroceso, y reacciona a movimientos de dos o tres
meses que aquí son sobre todo ruido. Con un único conjunto de datos y tres reglas, la diferencia entre 0,70 y 0,77
está dentro del error de un Sharpe de 26 años (≈ 0,2); la de 0,49 a 0,77 empieza a no estarlo, y tiene una razón: el
efecto plantado es de un año.

```python
netos = pd.DataFrame({"tsmom": b_ts - c_ts, "cruce": b_cr - c_cr,
                      "donchian": b_dn - c_dn})
netos.loc["2001":].corr().round(2)
```
```output
          tsmom  cruce  donchian
tsmom      1.00   0.71      0.33
cruce      0.71   1.00      0.30
donchian   0.33   0.30      1.00
```

La regla de 12 meses y el cruce 50/200 tienen una correlación de 0,71: las dos miran tendencias de meses. La ruptura
de 55 sesiones es más rápida y solo correla 0,33 y 0,30 con las otras dos. En la práctica, los CTA combinan
varios horizontes por eso mismo: diversifican entre velocidades de tendencia además de entre mercados.

## ¿Hay sonrisa de la tendencia?

Una propiedad que hace valiosa la tendencia en una cartera es cómo se comporta cuando la renta variable se mueve mucho.
Moskowitz, Ooi y Pedersen dibujan las rentabilidades trimestrales de su cartera diversificada frente a las del S&P 500
y encuentran una forma de sonrisa: le va mejor en los trimestres extremos, al alza y a la baja[^2]. No es una ley de la
regla, sino una consecuencia de cómo fueron las crisis de su muestra: largas, y precedidas de caídas que ya habían
puesto la regla corta. Aquí se puede comprobar si sale en unos datos donde el efecto plantado no depende del estado de
la renta variable.

```python
trim = lambda x: (1 + x).resample("QE").prod() - 1
q = pd.DataFrame({"indice": trim(r["IDA"].fillna(0)),
                  "tendencia": trim(b_ts - c_ts)}).loc["2001":]
a2, a1, a0 = np.polyfit(q["indice"], q["tendencia"], 2)
print(f"ajuste: {a0:+.3f} {a1:+.3f}·x {a2:+.3f}·x²")
extremos = q["indice"].abs() > q["indice"].abs().quantile(0.8)
print(q.groupby(extremos)["tendencia"].mean().rename(
    {False: "80 % central", True: "20 % extremo"}).round(4))
print(q.nsmallest(4, "indice").round(3))
```
```output
ajuste: +0.021 +0.078·x -0.094·x²
indice
80 % central    0.0236
20 % extremo    0.0131
Name: tendencia, dtype: float64
            indice  tendencia
fecha
2020-03-31  -0.510     -0.078
2001-09-30  -0.275      0.178
2008-12-31  -0.268      0.062
2011-09-30  -0.209     -0.086
```

*Fig. — Sin sonrisa: rentabilidad trimestral de la cartera de tendencia en 24 futuros frente a la del índice IDA, 2001-2025.* Dispersión de 100 trimestres: en el eje horizontal, la rentabilidad del futuro del índice IDA, de −51,0 % a +32,5 %; en el vertical, la de la regla de tendencia de 12 meses, de −14 % a +18 %. La parábola ajustada (destacada) es casi plana y algo cóncava: no hay sonrisa. Rotulados, el primer trimestre de 2020 (índice −51,0 %, tendencia −7,8 %), el tercero de 2001 (−27,5 % y +17,8 %) y el cuarto de 2008 (−26,8 % y +6,2 %).

No sale. El término en x² del ajuste es −0,094, ligeramente negativo (una parábola casi plana y algo cóncava, no una
sonrisa), y la pendiente, +0,078: la cartera de tendencia sube un poco con la renta variable, porque está larga en los
índices la mayor parte del tiempo. En el 80 % central de los trimestres del índice la tendencia gana de media un
2,4 %; en el 20 % de trimestres más extremos, un 1,3 %. De los cuatro peores trimestres del índice, dos fueron buenos
para la tendencia (el tercero de 2001, −27,5 % el índice y +17,8 % la tendencia, y el cuarto de 2008, −26,8 % y +6,2 %)
y dos malos (el primero de 2020, −51,0 % y −7,8 %, y el tercero de 2011, −20,9 % y −8,6 %).

La diferencia entre unas crisis y otras se ve mejor con los tramos de estrés del guion de los datos (los del README),
desde que la señal existe (enero de 2001), mirando la posición en el índice IDA al empezar cada tramo:

```python
tramos = [("2001-01-03", "2002-10-09"), ("2008-09-02", "2009-03-09"),
          ("2011-07-25", "2011-10-03"), ("2015-08-17", "2016-02-11"),
          ("2018-10-01", "2018-12-25"), ("2020-02-20", "2020-03-23"),
          ("2022-01-04", "2022-10-12"), ("2025-02-20", "2025-04-08")]
neto = b_ts - c_ts
filas = []
for a, b in tramos:
    filas.append({"desde": a, "sesiones": len(r.loc[a:b]),
                  "IDA": (1 + r["IDA"].loc[a:b]).prod() - 1,
                  "tendencia": (1 + neto.loc[a:b]).prod() - 1,
                  "pos_IDA_ini": pos_ts["IDA"].loc[a:].iloc[0]})
print(pd.DataFrame(filas).set_index("desde").round(3).to_string())
```
```output
            sesiones    IDA  tendencia  pos_IDA_ini
desde
2001-01-03       442 -0.499      0.001        1.559
2008-09-02       130 -0.406      0.140       -2.693
2011-07-25        50 -0.213     -0.098        2.731
2015-08-17       124 -0.071     -0.138        3.689
2018-10-01        59 -0.115     -0.088        4.000
2020-02-20        23 -0.400     -0.082        2.939
2022-01-04       195 -0.038      0.072        2.307
2025-02-20        34 -0.144     -0.049        2.743
```

En seis de los ocho tramos la regla empezaba larga en el índice (`pos_IDA_ini` positiva), porque llegaban tras un
periodo alcista. Las caídas rápidas de 23 a 59 sesiones (2011, 2018, 2020 y 2025) la pillan larga y no le dan tiempo a
girar: pierde entre un 4,9 % y un 9,8 % en cada una. En 2015-2016 pierde un 13,8 % en un tramo de vaivenes en el que
el índice solo cae un 7,1 %. El tramo de 2001-2002, el más largo (442 sesiones y −49,9 % del índice), lo termina
plana (+0,1 %): gira a corto y gana el tercer trimestre de 2001, pero devuelve casi todo en los rebotes. Los dos tramos
que gana son los que el guion hace largos o precedidos de caídas: 2008-2009 (+14,0 %), en el que ya estaba corta en el
índice al empezar, y 2022 (+7,2 % con el índice en −3,8 %), donde la ganancia viene de los bonos, que caen durante
meses.

Esa es la lectura útil de la sonrisa. Una regla de doce meses protege en las crisis que llegan despacio o que duran,
y pierde en las caídas bruscas tras un mercado alcista; la prima plantada aquí (`0,15·σ·signo`) no depende del
estado de la renta variable, así que la forma del gráfico depende solo de cómo son las crisis de la muestra. En los
datos de Moskowitz, Ooi y Pedersen predominaron las del primer tipo. No es un seguro contra el próximo crash.

## Momentum transversal 12-1 en acciones

El universo `universo2` tiene 120 acciones ficticias de 2006 a 2025, con salidas a bolsa, cuatro quiebras y seis
compras o fusiones. La señal clásica es la rentabilidad **12-1**: del cierre de hace doce meses al de hace uno,
saltándose el último mes (que en datos reales tiene un efecto de reversión de corto plazo propio; lección 2.3.2).

Tres decisiones evitan los sesgos de siempre:

1. **Universo point-in-time**: cada mes solo entran las acciones que cotizaban ese mes (lección 1.4.4).
2. **Ejecución en la sesión siguiente**: la señal se calcula con el cierre del último día del mes y la cartera se
   forma al cierre de la primera sesión del mes siguiente. La rentabilidad va de esa sesión a la primera del mes
   siguiente.
3. **Rentabilidad de deslistado**: si una acción deja de cotizar durante el mes, su rentabilidad incluye la del
   deslistado (−100 % en una quiebra). Sin ella, las quiebras desaparecen justo antes de su peor día.

```python
aj = pd.read_parquet("universo2_ajustados.parquet")
P = aj.pivot(index="fecha", columns="ticker",
             values="cierre_ajustado")
ev = pd.read_csv("universo2_eventos.csv", parse_dates=["fecha"])
desl = ev.dropna(subset=["rentabilidad_deslistado"])
ses = P.index
mes = ses.to_period("M")
fin = ses[np.r_[mes[1:] != mes[:-1], True]][:-1]   # último día
ent = ses[ses.searchsorted(fin, side="right")]      # sesión siguiente

Pf = P.loc[fin]
mom = Pf.shift(1) / Pf.shift(12) - 1                # 12-1
Pe = P.loc[ent].set_axis(fin)
fwd = Pe.shift(-1) / Pe - 1                         # de ent a ent

for _, d in desl.iterrows():            # mes en que deja de cotizar
    k = ent.searchsorted(d["fecha"]) - 1
    p0 = Pe.iloc[k][d["ticker"]]
    p_ult = P[d["ticker"]].dropna().iloc[-1]
    fwd.iloc[k, fwd.columns.get_loc(d["ticker"])] = (
        p_ult / p0 * (1 + d["rentabilidad_deslistado"]) - 1)

mom, fwd = mom.loc["2007":], fwd.loc["2007":]
validas = mom.notna() & fwd.notna()
n_mes = validas.sum(axis=1).iloc[:-1]   # el último mes no tiene futuro
print(len(n_mes), "meses de cartera; acciones por mes:",
      n_mes.min(), "a", n_mes.max())
print(fwd.loc[:, ["QXQT", "QXKV"]].min().round(3).to_dict())
```
```output
226 meses de cartera; acciones por mes: 106 a 110
{'QXQT': -1.0, 'QXKV': -1.0}
```

Del orden de un centenar de acciones por mes (de 106 a 110: las salidas a bolsa entran cuando tienen doce meses de
historia y los deslistados salen). Las dos primeras quiebras tienen en su último mes una rentabilidad de −100 %: el
dato que faltaría si solo se usaran los precios.

El fichero `universo2_caracteristicas.parquet` trae esas rentabilidades ya calculadas: cada acción que deja de cotizar
tiene una última fila sin precio, con una `rentabilidad_mes` que encadena lo que va de mes con la de deslistado. Aquí
se construyen a mano desde los eventos para ver el mecanismo y porque la cartera va de la primera sesión de un mes a la
del siguiente, no de fin de mes a fin de mes. Cuando más abajo se lee ese fichero para el placebo ESG y la horquilla,
esas filas no cambian nada: caen en el mes en que la acción ya no tiene rentabilidad siguiente que predecir.

La medida estándar de una señal transversal es el **coeficiente de información** (IC): la correlación, cada mes, entre
la señal y la rentabilidad siguiente en todo el corte transversal. La media de los IC mensuales y su estadístico
$t = \overline{IC} / (s_{IC} / \sqrt{T})$ dicen si hay relación. Hay dos versiones:

```python
from scipy import stats

def ic_mensual(senal):
    filas = []
    for d in senal.index[:-1]:
        v = senal.loc[d].notna() & fwd.loc[d].notna()
        if v.sum() < 50:
            continue
        x, y = senal.loc[d][v], fwd.loc[d][v]
        filas.append((d, stats.spearmanr(x, y).statistic,
                      np.corrcoef(x, y)[0, 1]))
    return pd.DataFrame(filas, columns=["fecha", "rangos", "lineal"]
                        ).set_index("fecha")

ic = ic_mensual(mom)
t = ic.mean() / ic.std() * np.sqrt(len(ic))
pd.DataFrame({"ic_medio": ic.mean(), "t": t}).round(3)
```
```output
        ic_medio      t
rangos     0.027  2.808
lineal     0.041  4.295
```

El IC de rangos (Spearman) es 0,027 con t = 2,8: lo que predice el generador (≈ 0,03). El IC lineal (Pearson) es 0,041
con t = 4,3: parece una señal un 50 % más fuerte y mucho más segura. No lo es. La correlación lineal pondera cada
observación por su distancia a la media, y cuatro quiebras, guiadas durante 320 sesiones hasta un último precio de entre
0,30 y 1,50 USD y que terminan en −100 %, son las observaciones más extremas del panel en las dos variables a la vez: momentum
muy negativo y rentabilidad siguiente muy negativa. Unas pocas filas mueven la correlación. El IC de rangos solo usa el
orden y no las ve más que como «la peor» de su mes.

## Deciles, quiebras y un placebo

La imagen habitual del momentum es la de diez carteras: cada mes se ordenan las acciones por su señal, se reparten en
deciles y se mide la rentabilidad media de cada uno. La cartera «ganadores menos perdedores» (WML, *winners minus
losers*) compra el decil 10 y vende el 1.

```python
def deciles(senal, rent):
    out = {}
    for d in senal.index[:-1]:
        v = senal.loc[d].notna() & rent.loc[d].notna()
        if v.sum() < 50:
            continue
        g = pd.qcut(senal.loc[d][v].rank(method="first"), 10,
                    labels=range(1, 11))
        out[d] = rent.loc[d][v].groupby(g, observed=True).mean()
    return pd.DataFrame(out).T

D = deciles(mom, fwd)
quiebras = ["QXQT", "QXKV", "QXZT", "QXYX"]
D_sq = deciles(mom, fwd.drop(columns=quiebras))
car = pd.read_parquet("universo2_caracteristicas.parquet")
esg = car.pivot(index="fecha", columns="ticker",
                values="puntuacion_esg").reindex(mom.index)
D_esg = deciles(esg.where(mom.notna()), fwd)
anual = pd.DataFrame({"momentum": 12 * D.mean(),
                      "sin_quiebras": 12 * D_sq.mean(),
                      "placebo_esg": 12 * D_esg.mean()})
anual.loc["10-1"] = anual.loc[10] - anual.loc[1]
print(anual.round(3).T.to_string())
wml = D[10] - D[1]
w_esg = D_esg[10] - D_esg[1]
for nombre, x in (("WML momentum", wml), ("10-1 placebo", w_esg)):
    print(f"{nombre}: t = {x.mean() / x.std() * np.sqrt(len(x)):.2f}")
ic_esg = ic_mensual(esg.where(mom.notna()))["rangos"]
print(f"IC de rangos del placebo: {ic_esg.mean():.3f}, t = "
      f"{ic_esg.mean() / ic_esg.std() * np.sqrt(len(ic_esg)):.2f}")
```
```output
                  1      2      3      4      5      6      7      8      9     10   10-1
momentum     -0.046  0.049  0.097  0.101  0.096  0.089  0.110  0.094  0.075  0.114  0.160
sin_quiebras  0.013  0.045  0.103  0.101  0.098  0.096  0.106  0.094  0.076  0.112  0.098
placebo_esg   0.056  0.085  0.101  0.063  0.060  0.045  0.083  0.077  0.085  0.119  0.063
WML momentum: t = 4.25
10-1 placebo: t = 2.18
IC de rangos del placebo: 0.010, t = 1.46
```

*Fig. — Rentabilidad anual media por deciles del momentum 12-1 y de un placebo (puntuación ESG) en 120 acciones sintéticas, 2007-2025.* Dos paneles de barras por deciles. Momentum 12-1: el decil 1 de perdedores (destacado) rinde −4,6 % anual con las cuatro quiebras y +1,3 % sin ellas; los deciles 2 a 10 rinden entre 4,9 % y 11,4 % sin una escalera clara. Placebo ESG, sin ningún efecto: de 4,5 % a 11,9 %, con un decil 10 de 11,9 % y un decil 1 de 5,6 %: 6,3 puntos de diferencial por azar.

Tres lecturas de la tabla y de la figura:

- **Las quiebras hacen la mitad del diferencial.** Con ellas, ganadores menos perdedores da un 16,0 % anual (t = 4,25);
  sin las cuatro acciones que quebraron, un 9,8 %. El decil 1 pasa de −4,6 % a +1,3 % al año. Lo plantado (`0,0025·z`
  al mes con z de ±1,75 en los deciles extremos) da ≈ 10 % anual: el diferencial sin quiebras es el que se acerca a la
  verdad.
- **El centro no está ordenado.** Los deciles 2 a 9 no suben en escalera (el 9 rinde menos que el 3): con una docena
  de acciones por decil y volatilidades idiosincráticas del 20-30 %, la media de 19 años de cada decil tiene un error
  de varios puntos.
- **El placebo también tiene diferencial.** La puntuación ESG, que no tiene ningún efecto, da 6,3 puntos al año entre
  su decil alto y el bajo, con un t de 2,18 que pasaría un contraste al 5 %. Su IC de rangos, con todo el corte
  transversal, es 0,010 con t = 1,46: no significativo. El diferencial de dos carteras extremas es una imagen, no una
  prueba (lección 2.1.8 para el problema de probar muchas variantes).

## Costes y crashes

Una cartera de deciles se rehace cada mes. El coste de cada cambio es, como mínimo, media horquilla: la columna
`horquilla_pb` de las características da la horquilla media cotizada de cada acción y mes.

```python
hs = car.pivot(index="fecha", columns="ticker",
               values="horquilla_pb").reindex(mom.index) / 2 / 1e4

def pesos(senal):
    W = {}
    for d in senal.index[:-1]:
        v = senal.loc[d].dropna()
        g = pd.qcut(v.rank(method="first"), 10, labels=False)
        w = pd.Series(0.0, index=senal.columns)
        w[g.index[g == 9]] = 1 / (g == 9).sum()
        w[g.index[g == 0]] = -1 / (g == 0).sum()
        W[d] = w
    return pd.DataFrame(W).T

W = pesos(mom)
bruto = (W * fwd.reindex(W.index)).sum(axis=1)
giro = (W - W.shift().fillna(0.0)).abs()
coste = (giro * hs.reindex(W.index)).sum(axis=1)
print(f"rotación mensual: {giro.sum(axis=1).mean():.0%} del capital")
print(f"bruto {12 * bruto.mean():.2%}  coste {12 * coste.mean():.2%}"
      f"  neto {12 * (bruto - coste).mean():.2%} al año")
```
```output
rotación mensual: 113% del capital
bruto 16.14%  coste 0.49%  neto 15.65% al año
```

La cartera cambia más de la mitad de sus posiciones cada mes (una rotación del 113 % sobre un capital bruto del 200 %,
100 % largo y 100 % corto), pero las acciones del universo son grandes y la media horquilla, de unos pocos puntos
básicos, cuesta un 0,5 % al año. El momentum mensual en acciones grandes no lo matan los costes de horquilla; sí lo
encarecen el impacto en carteras grandes y el préstamo en el lado corto, que en las acciones que van a quebrar es caro
o imposible (lecciones 2.4.7 y 2.3.5).

El riesgo del momentum transversal no está en los costes, sino en los **crashes**. Daniel y Moskowitz muestran que el
momentum sufre rachas de pérdidas infrecuentes y persistentes, en parte previsibles: llegan en estados de «pánico»,
tras caídas del mercado y con volatilidad alta, y suelen coincidir con rebotes[^4]. El mecanismo es sencillo: tras una
caída fuerte, los perdedores son las acciones con más beta y más castigadas; cuando el mercado rebota, son las que
más suben, y la cartera está corta en ellas. El generador de estos datos lo planta en los tres meses siguientes a los
suelos de 2009 y 2020.

```python
meses_mes = wml.copy()
meses_mes.index = (wml.index.to_period("M") + 1).strftime("%Y-%m")
crash = meses_mes.loc[["2009-04", "2009-05", "2009-06",
                       "2020-04", "2020-05", "2020-06"]]
print(crash.round(3).to_string())
print("peores meses de toda la muestra:")
print(meses_mes.nsmallest(5).round(3).to_string())
```
```output
2009-04   -0.073
2009-05    0.035
2009-06   -0.161
2020-04   -0.046
2020-05   -0.032
2020-06   -0.032
peores meses de toda la muestra:
2009-06   -0.161
2022-02   -0.123
2014-09   -0.090
2008-06   -0.087
2023-03   -0.083
```

El trimestre tras el suelo de 2009 suma un −20 % (−7,3 %, +3,5 % y −16,1 %), y el de 2020, un −11 %. Lo plantado
(coeficiente −0,012 al mes en esos seis meses, con z de ±1,75) da ≈ −4,2 % al mes, −12,6 % por trimestre; el ruido
hace que 2009 salga peor y 2020 algo mejor. Junio de 2009 es el peor mes de toda la muestra. Los otros cuatro
peores (febrero de 2022, septiembre de 2014, junio de 2008 y marzo de 2023) no están plantados: son ruido de una
cartera de 24 acciones. Para un
sistema real, la consecuencia es de tamaño: una estrategia con un 10 % anual de media que puede perder un 20 % en un
trimestre necesita un objetivo de volatilidad y un capital que lo resistan. Daniel y Moskowitz proponen escalar el
momentum por su volatilidad prevista, la misma idea que en los futuros[^4].

## Rotación sectorial: diez activos son pocos

La rotación sectorial es el momentum transversal entre sectores: cada mes, comprar los sectores con mejor rentabilidad
12-1 y vender los peores. Moskowitz y Grinblatt encontraron en 1999 que el momentum de industrias explicaba buena
parte del momentum de acciones individuales en EE. UU.[^5]. En este universo no hay una prima sectorial plantada: los
sectores heredan la prima de sus acciones y tienen algunos tramos de deriva (finanzas en 2008, energía en 2014-2016 y
2020, tecnología en 2022).

```python
sector = pd.read_csv("universo2_sectores.csv").set_index("ticker")
R = P.pct_change(fill_method=None)
R_sec = R.T.groupby(sector["sector"]).mean().T     # equiponderado
S = (1 + R_sec.fillna(0.0)).cumprod()
Sf = S.loc[fin]
s_mom = (Sf.shift(1) / Sf.shift(12) - 1).loc["2007":]
Se = S.loc[ent].set_axis(fin)
s_fwd = (Se.shift(-1) / Se - 1).loc[s_mom.index]
rk = s_mom.rank(axis=1)
ls = (s_fwd[rk >= 8].mean(axis=1)
      - s_fwd[rk <= 3].mean(axis=1)).dropna()
ic_s = pd.Series([stats.spearmanr(s_mom.loc[d], s_fwd.loc[d]).statistic
                  for d in ls.index])
print(f"largo-corto: {12 * ls.mean():.2%} al año, t = "
      f"{ls.mean() / ls.std() * np.sqrt(len(ls)):.2f}")
print(f"IC de rangos: {ic_s.mean():.3f}, t = "
      f"{ic_s.mean() / ic_s.std() * np.sqrt(len(ic_s)):.2f}")
```
```output
largo-corto: 3.98% al año, t = 1.34
IC de rangos: 0.024, t = 1.02
```

La rotación gana un 4,0 % al año con t = 1,34, y su IC de rangos es 0,024 con t = 1,02. Las dos cifras son
compatibles con una prima pequeña y también con cero. El problema es de cantidad de información: un IC entre diez
sectores tiene un error típico mensual enorme (con N = 10, una correlación de rangos por azar tiene una desviación
típica de ≈ 1/√9 ≈ 0,33), y 226 meses no bastan para separar 0,02 de cero. Para una estrategia con tan pocos activos,
la evidencia tiene que venir de otro sitio: de décadas de datos, de varios mercados o de una razón económica fuerte.

## Lo que esto cambia en tus backtests

- **Pregunta por el control adecuado.** Una regla larga-corta sobre activos con deriva gana algo solo por estar del
  lado de la media. El control con la media restada separa esa parte de la tendencia.
- **El coste es por tick, no por contrato.** Un mercado cuyo precio ha caído mucho puede ser caro de operar aunque su
  tick no haya cambiado.
- **Rangos antes que niveles.** En corte transversal, el IC de rangos y su estadístico son más robustos que el IC
  lineal o el diferencial de dos deciles, que mueven unas pocas observaciones extremas.
- **Deslistados dentro.** Sin la rentabilidad de deslistado el decil perdedor parece mejor de lo que fue; con ella,
  hay que comprobar cuánto del resultado depende de un puñado de quiebras.
- **El riesgo del momentum es de cola.** Una media positiva convive con meses de −10 % o peores justo cuando el mercado
  rebota.

## Ejercicios

1. Repite la regla de series temporales con horizontes de 1, 3 y 12 meses (21, 63 y 252 sesiones). ¿Cuál se acerca
   más al efecto plantado, que depende de las 252 sesiones anteriores, y qué pasa con los costes al acortar el
   horizonte?

**Solución.**

```python
filas = {}
for n in (21, 63, 252):
    b, c, _ = backtest(np.sign(px / px.shift(n) - 1), r)
    filas[f"{n} sesiones"] = resumen(b, c)
pd.DataFrame(filas).loc[["sharpe_bruto", "sharpe_neto",
                         "coste_anual"]].round(3)
```
```output
              21 sesiones  63 sesiones  252 sesiones
sharpe_bruto        0.414        0.607         0.946
sharpe_neto        -0.029        0.312         0.772
coste_anual         0.049        0.032         0.018
```

Los tres horizontes ganan en bruto porque una tendencia de un año también se ve, con más ruido, en tramos de uno y
tres meses, pero el de 252 sesiones es el que recoge la prima plantada (0,95 bruto, frente a 0,61 y 0,41). Al acortar
el horizonte la señal cambia mucho más a menudo: el coste anual pasa del 1,8 % al 4,9 % y la regla de un mes pierde
todo en neto (−0,03). Un horizonte corto necesita
una ventaja mucho mayor para pagar su rotación.

2. Las reglas Turtle tenían también un «Sistema 1» más rápido: entrada a 20 sesiones y salida a 10. Pruébalo con la
   función `donchian` y compáralo con el de 55/20 en Sharpe neto, coste y correlación.

**Solución.**

```python
b_d1, c_d1, _ = backtest(donchian(px, 20, 10), r)
print(pd.DataFrame({"20_10": resumen(b_d1, c_d1),
                    "55_20": resumen(b_dn, c_dn)}).round(3).to_string())
print("correlación de los netos:",
      round(np.corrcoef(b_d1 - c_d1, b_dn - c_dn)[0, 1], 2))
```
```output
              20_10  55_20
sharpe_bruto  0.484  0.647
sharpe_neto   0.212  0.491
vol_anual     0.096  0.091
coste_anual   0.026  0.014
max_dd       -0.483 -0.311
correlación de los netos: 0.76
```

El Sistema 1 es más rápido y opera más: cuesta casi el doble (2,6 % frente a 1,4 % anual), su Sharpe neto baja a 0,21 y
su caída máxima sube al 48 %. Las dos versiones se parecen mucho (correlación de 0,76), así que combinarlas diversifica
poco. En estos datos la prima de tendencia está en el horizonte de un año, y una ruptura de 20 sesiones reacciona a
movimientos que son sobre todo ruido.

3. Un compañero te enseña un backtest de momentum transversal en acciones reales con un diferencial de deciles del
   15 % anual, sin rentabilidades de deslistado y con el universo de los miembros actuales del índice. Enumera qué le
   pedirías antes de creérselo.

**Solución.**

Primero, el universo point-in-time: con los miembros actuales sobreviven las empresas que subieron, y el sesgo de
supervivencia (lección 1.4.4) cambia los dos extremos. Después, las rentabilidades de deslistado: sin ellas el decil
perdedor pierde sus peores meses y el diferencial cambia, en cualquier dirección según cómo se trate la última
cotización. Tercero, el IC de rangos con su estadístico, no solo dos deciles: en esta lección, un placebo da 6 puntos
de diferencial con un t de 2,2, aunque su IC de rangos no es significativo (t = 1,5). Cuarto, el resultado sin las cinco o diez observaciones más extremas. Quinto, la
ejecución: señal al cierre de mes y cartera formada al cierre siguiente, con media horquilla y, en el lado corto, el
coste de préstamo (lección 2.4.7). Y por último, los meses de crash tras los suelos de mercado: cuánto pierde y si el
tamaño de la posición sobreviviría a ellos.

[^1]: N. Jegadeesh y S. Titman, «Returns to Buying Winners and Selling Losers: Implications for Stock Market
    Efficiency», *Journal of Finance* 48(1), 1993, 65-91. DOI 10.1111/j.1540-6261.1993.tb04702.x.
[^2]: T. J. Moskowitz, Y. H. Ooi y L. H. Pedersen, «Time series momentum», *Journal of Financial Economics* 104(2),
    2012, 228-250. DOI 10.1016/j.jfineco.2011.11.003. Escalado al 40 % y estimador EWMA con centro de masa de 60
    días: secciones 2.4 y 4.1; la sonrisa, figura 4.
[^3]: «The Original Turtle Trading Rules», publicadas en tradingblox.com/originalturtles: N y unidades en las
    páginas 13-14, sistemas de entrada en la 18 y salidas en la 26. Los Turtle operaban la ruptura en cuanto se
    producía durante la sesión; aquí se opera al cierre siguiente, que es más conservador.
[^4]: K. Daniel y T. J. Moskowitz, «Momentum crashes», *Journal of Financial Economics* 122(2), 2016, 221-247. DOI
    10.1016/j.jfineco.2015.12.002.
[^5]: T. J. Moskowitz y M. Grinblatt, «Do Industries Explain Momentum?», *Journal of Finance* 54(4), 1999,
    1249-1290. DOI 10.1111/0022-1082.00146.

## Autoevaluación

1. Para controlar una regla `signo(rentabilidad de 12 meses)`, ¿por qué conviene restar la media de cada mercado antes de permutar sus rendimientos?

   - A. Porque sin restarla la permutación está mal hecha
   - B. Porque la permutación conserva la deriva media de cada mercado: si un mercado sube en promedio, su rentabilidad de 12 meses suele ser positiva y la regla está casi siempre larga, cobrando esa deriva sin que haya tendencia
   - C. Porque los costes son negativos
   - D. Porque el escalado de volatilidad crea rentabilidad

   *Respuesta B: Porque la permutación conserva la deriva media de cada mercado: si un mercado sube en promedio, su rentabilidad de 12 meses suele ser positiva y la regla está casi siempre larga, cobrando esa deriva sin que haya tendencia.* Permutar destruye el orden temporal pero no la media. En estos datos la deriva es pequeña (bonos sin prima de plazo, materias primas y divisas que revierten al ancla), y las dos versiones dan un Sharpe bruto compatible con cero: +0,06 ± 0,17 sin restarla y −0,12 ± 0,22 restándola. En mercados con mucha deriva, lo que gana la regla por estar del lado de la media puede ser una parte grande, y eso no es «momentum».

2. ¿Qué hace el escalado de volatilidad de Moskowitz, Ooi y Pedersen?

   - A. Opera solo cuando la volatilidad es baja
   - B. Fija la posición en cada mercado como objetivo/σ estimada con datos hasta la víspera, para que cada mercado aporte un riesgo parecido
   - C. Escala la señal según la fuerza de la tendencia
   - D. Reduce las comisiones

   *Respuesta B: Fija la posición en cada mercado como objetivo/σ estimada con datos hasta la víspera, para que cada mercado aporte un riesgo parecido.* Sin escalar, el gas natural (50 % de volatilidad) dominaría a un bono a 2 años (2 %). Con una posición de 40 %/σ cada mercado tiene un riesgo ex ante igual, y la cartera media de muchos mercados poco correlados queda en torno al 10,5 % anual.

3. En el universo de acciones, el IC lineal del momentum 12-1 es 0,041 y el de rangos 0,027. ¿Cuál describe mejor la prima plantada y por qué?

   - A. El lineal, porque usa más información
   - B. El de rangos: el lineal lo inflan cuatro quiebras con rentabilidad de −100 % que estaban en el decil perdedor; unas pocas observaciones extremas mueven una correlación de Pearson
   - C. Ninguno: el IC no mide nada
   - D. El lineal, porque los rangos pierden el signo

   *Respuesta B: El de rangos: el lineal lo inflan cuatro quiebras con rentabilidad de −100 % que estaban en el decil perdedor; unas pocas observaciones extremas mueven una correlación de Pearson.* La prima del generador da un IC de rangos esperado de ≈ 0,03, que es lo que mide el de rangos. Las cuatro quiebras guiadas caen en el decil de perdedores y sus −100 % pesan muchísimo en una correlación lineal y en el diferencial de deciles (16,0 % anual con ellas, 9,8 % sin ellas).

4. Una cartera por deciles de la puntuación ESG (un placebo sin ningún efecto) da un diferencial de 6,3 puntos al año entre el decil alto y el bajo. ¿Qué conclusión es correcta?

   - A. Que el ESG tiene una prima del 6 % anual
   - B. Que un diferencial entre dos carteras de 12 acciones es muy ruidoso: hay que mirar el IC de todo el corte transversal y su t (0,010 con t = 1,46 aquí); el diferencial de deciles llega a t = 2,18 por azar
   - C. Que hay un error en los datos
   - D. Que el placebo funciona como el momentum

   *Respuesta B: Que un diferencial entre dos carteras de 12 acciones es muy ruidoso: hay que mirar el IC de todo el corte transversal y su t (0,010 con t = 1,46 aquí); el diferencial de deciles llega a t = 2,18 por azar.* El decil extremo tiene una docena de acciones con volatilidades idiosincráticas del 20-30 %: su media de 19 años tiene un error de varios puntos. El diferencial de deciles es una buena imagen, pero la prueba es el IC y su estadístico.

5. ¿Cuándo pierde más el momentum transversal, según la evidencia y según el generador de estos datos?

   - A. En las caídas fuertes del mercado
   - B. En los rebotes tras un suelo de mercado: los perdedores, con más beta, suben más que los ganadores
   - C. En los mercados laterales
   - D. Nunca pierde en un mes

   *Respuesta B: En los rebotes tras un suelo de mercado: los perdedores, con más beta, suben más que los ganadores.* Daniel y Moskowitz documentan crashes en estados de pánico, tras caídas y con volatilidad alta, que coinciden con rebotes del mercado. Aquí está plantado en los tres meses tras los suelos de 2009 y 2020: la cartera de ganadores menos perdedores pierde un 20 % en el trimestre de 2009.

## Ideas clave

- Tendencia (series temporales) compara un activo con su propio pasado y puede estar corta en todo; momentum transversal compara activos entre sí y es neutral por construcción.
- La regla 12 meses con escalado de volatilidad recupera la prima plantada en los 24 futuros (Sharpe bruto 0,95, neto 0,77), a más de cuatro desviaciones típicas de un control por permutación; el control con la media restada separa además lo que sería cobrar la deriva de cada mercado.
- Cruce de medias, Donchian y momentum de 12 meses son la misma idea con distintos horizontes: correlaciones de 0,3 a 0,7 entre ellas.
- La «sonrisa» frente a la renta variable depende de las crisis de la muestra: aquí no aparece; la regla de 12 meses gana en las caídas largas o precedidas de caídas (2008-2009) y pierde en las bruscas tras un mercado alcista (2020).
- En acciones, IC de rangos (0,027, t = 2,8) en vez de IC lineal o diferencial de deciles, que inflan unas pocas quiebras y el ruido de carteras pequeñas; un placebo da 6 puntos de diferencial (t = 2,2) por azar.
- El momentum transversal sufre crashes en los rebotes tras los suelos, y una rotación entre diez sectores no tiene datos suficientes para separar una prima de cero.

## Recursos

### Research

- [Volatility Targeting en Python](https://pythonparatrading.com/volatility-targeting/) · Research-0004 · 8 min
- [Tu primer sistema en Python: cruce de medias móviles sobre SPY](https://pythonparatrading.com/primer-sistema-cruce-de-medias/) · Research-0018 · 7 min

### Documentación

- [Moskowitz, Ooi y Pedersen (2012): «Time series momentum», Journal of Financial Economics 104(2), 228-250](https://doi.org/10.1016/j.jfineco.2011.11.003) · doi.org
- [Jegadeesh y Titman (1993): «Returns to Buying Winners and Selling Losers», Journal of Finance 48(1), 65-91](https://doi.org/10.1111/j.1540-6261.1993.tb04702.x) · doi.org
- [Daniel y Moskowitz: «Momentum Crashes» (NBER w20439; Journal of Financial Economics 122(2), 2016)](https://www.nber.org/papers/w20439) · nber.org
- [Moskowitz y Grinblatt (1999): «Do Industries Explain Momentum?», Journal of Finance 54(4), 1249-1290](https://doi.org/10.1111/0022-1082.00146) · doi.org
- [The Original Turtle Trading Rules (PDF; sistemas 1 y 2, N y unidades)](https://www.tradingblox.com/originalturtles/originalturtlerules.pdf) · tradingblox.com

### Datos

- [Datos del nivel 2: 24 futuros continuos, 2000-2025 (Parquet)](https://pythonparatrading.com/curso/datos/nivel-2/futuros2_continuos.parquet) · Descarga · futuros2_continuos.parquet

Lección anterior: [2.2.4 · Diario de investigación y registro de experimentos contra el data snooping](https://pythonparatrading.com/curso-python-trading/nivel-2/diario-de-investigacion-y-registro-de-experimentos/)

Lección siguiente: [2.3.2 · Reversión a la media: RSI y Bollinger, reversión intradía y huecos](https://pythonparatrading.com/curso-python-trading/nivel-2/reversion-a-la-media-y-gaps/)
