---
title: "4.1.6 Modelos factoriales: CAPM, Fama-French y PCA"
description: "CAPM, Fama-French y momentum sobre 20 fondos con alfas y cargas conocidas: el falso positivo, los fondos no lineales, el cambio de estilo y PCA."
url: "https://pythonparatrading.com/curso-python-trading/nivel-4/modelos-factoriales-capm-fama-french-y-pca/"
lang: "es"
image: "https://pythonparatrading.com/og/curso-python-trading/nivel-4/modelos-factoriales-capm-fama-french-y-pca.png"
---

# 4.1.6 · Modelos factoriales: CAPM, Fama-French, PCA y atribución

> Un modelo factorial separa lo que una cartera gana por exponerse a primas conocidas de lo que gana por sí misma. Esta lección regresa 20 fondos sintéticos con alfas y cargas publicadas sobre el CAPM y sobre seis factores con el formato de la biblioteca de Kenneth French, y comprueba qué se recupera, qué falla (el falso positivo, el market timing, la venta de puts, el cambio de estilo) y qué ven los componentes principales de un universo cuyos factores verdaderos se conocen.

- Curso: [Nivel 4: Carteras, riesgo, ejecución y trading en real](https://pythonparatrading.com/curso-python-trading/nivel-4/)
- Módulo: 4.1 · Teoría y optimización de carteras
- Duración: 75 min
- Requisitos: [2.1.1 · Contrastes de hipótesis, p-valores, bootstrap y regresión con errores robustos](https://pythonparatrading.com/curso-python-trading/nivel-2/contrastes-bootstrap-y-errores-robustos/), [2.1.8 · El problema de las pruebas múltiples: Bonferroni, FDR y el «factor zoo»](https://pythonparatrading.com/curso-python-trading/nivel-2/pruebas-multiples-bonferroni-fdr-y-factor-zoo/), [2.3.5 · Factores (value, calidad, baja volatilidad, tamaño) y estrategias de eventos](https://pythonparatrading.com/curso-python-trading/nivel-2/factores-y-estrategias-de-eventos/), [2.6.2 · Win rate, payoff, expectativa, alpha, beta, information ratio, turnover y capacidad](https://pythonparatrading.com/curso-python-trading/nivel-2/metricas-de-operaciones-alpha-beta-y-capacidad/)

## Al terminar esta lección

- Estimar regresiones de series temporales del CAPM y de seis factores (Fama-French de cinco más momentum) con errores de Newey-West, y leer alfa, cargas y R².
- Leer y limpiar los ficheros de la biblioteca de datos de Kenneth French, la fuente primaria de los factores.
- Atribuir el rendimiento medio y el riesgo de un fondo o de una cartera a sus factores, y distinguir un alfa de una exposición no medida.
- Reconocer los fallos típicos: falsos positivos entre muchos fondos, estrategias no lineales (market timing, venta de opciones) y cambios de estilo.
- Comparar los componentes principales de un universo con sus factores verdaderos y explicar qué recupera PCA y qué no.

## Del CAPM a seis factores

El **CAPM** (Sharpe, 1964) dice que, en equilibrio, el exceso de rendimiento esperado de cualquier activo es su beta
por la prima del mercado. Aplicado a una cartera en serie temporal, la regresión

$$
r_t - r_{f,t} = \alpha + \beta\,(r_{m,t} - r_{f,t}) + \varepsilon_t
$$

separa lo que la cartera gana por exponerse al mercado ($\beta$) de lo que gana por sí misma ($\alpha$). La lección
2.6.2 la usó para medir una estrategia frente a un índice. El problema es que el mercado no es la única prima por la
que se cobra. Fama y French (1993) añadieron dos factores construidos como carteras largas y cortas de acciones: el
**tamaño** (SMB, pequeñas menos grandes) y el **valor** (HML, cotización baja frente a su valor contable menos alta).
Carhart (1997) añadió el **momentum** (los ganadores de los últimos doce meses, sin el último, menos los perdedores) y
Fama y French (2015), la **rentabilidad** (RMW, empresas rentables menos poco rentables) y la **inversión** (CMA,
empresas que invierten poco menos las que invierten mucho). Con los seis:

$$
r_t - r_{f,t} = \alpha + \beta_m\,MKT_t + s\,SMB_t + h\,HML_t + r\,RMW_t + c\,CMA_t + m\,MOM_t + \varepsilon_t.
$$

```mermaid
flowchart TB
  C[CAPM: mercado] --> F3[FF3: + SMB, HML]
  F3 --> C4[Carhart: + MOM]
  F3 --> F5[FF5: + RMW, CMA]
  C4 --> F6[Seis factores]
  F5 --> F6
```

Un alfa en un modelo es un rendimiento que **ese** modelo no explica. Cada factor que se añade convierte en exposición
algo que antes era alfa. Si las primas de los factores se pueden comprar barato (fondos indexados de estilos,
futuros), un gestor que solo cobra primas de factores no aporta nada que no se pueda replicar. Cómo se construyen los
factores con datos de acciones (ordenamientos por quintiles, Fama-MacBeth, IC) es la lección 2.3.5; aquí se usan ya
construidos, para evaluar carteras.

Los datos son sintéticos y tienen la **respuesta conocida**. `ff4_factores_mensuales.csv` trae seis factores
mensuales de 2006 a 2025 con el formato de la biblioteca de Kenneth French (en tanto por uno), coherentes con el
universo de la lección 4.1.4. `ff4_fondos_mensuales.csv` trae 20 fondos ficticios generados con alfas y cargas
publicadas en `ff4_fondos_verdad.csv`, entre ellos un fondo con alfa real, uno con alfa pequeño, varios sin alfa, dos
con alfa negativo por comisiones, dos no lineales y uno que cambia de estilo. Ningún resultado de esta lección dice
nada de fondos reales.

```python
import numpy as np
import pandas as pd
import statsmodels.api as sm

fac = pd.read_csv("ff4_factores_mensuales.csv", index_col="mes")
fondos = pd.read_csv("ff4_fondos_mensuales.csv").pivot(
    index="mes", columns="fondo", values="rendimiento")
verdad = pd.read_csv("ff4_fondos_verdad.csv", index_col="fondo")
exc = fondos.sub(fac["rf"], axis=0)       # exceso del tipo libre
F6 = ["mkt_rf", "smb", "hml", "rmw", "cma", "mom"]

print(fac.shape, exc.shape, fac.index[0], "a", fac.index[-1])
resumen = pd.DataFrame({
    "media_%": 1200 * fac[F6].mean(),
    "vol_%": 100 * np.sqrt(12) * fac[F6].std(),
    "peor_mes_%": 100 * fac[F6].min(),
})
resumen["sharpe"] = resumen["media_%"] / resumen["vol_%"]
resumen.round(2)
```
```output
(240, 7) (240, 20) 2006-01 a 2025-12
        media_%  vol_%  peor_mes_%  sharpe
mkt_rf     9.27  22.22      -28.94    0.42
smb        0.18   8.01       -8.75    0.02
hml       -2.45   8.35       -7.77   -0.29
rmw        3.52   7.67       -6.15    0.46
cma        1.69   6.94       -7.41    0.24
mom        4.05  17.64      -33.13    0.23
```

El mercado sintético tiene una prima media del 9,27 % anual con un 22,2 % de volatilidad y un peor mes del −28,9 %.
Valor (HML) tiene prima negativa en la muestra, rentabilidad (RMW) la más alta en Sharpe (0,46) y momentum un peor mes
del −33,1 %, el crash de 2009 que imitan los datos.

## La fuente primaria: la biblioteca de Kenneth French

Los factores reales se publican gratis en la biblioteca de datos de Kenneth French (Dartmouth), que es la fuente
primaria: los artículos de Fama y French usan esas series y casi todo el sector las toma como referencia. Cada
fichero es un ZIP con un CSV de formato propio. Consultada el 22 de octubre de 2026,
`F-F_Research_Data_5_Factors_2x3_CSV.zip` tiene tres líneas de texto («This file was created using the 202608 CRSP
database», de dónde sale el tipo libre: Ibbotson hasta mayo de 2024 y el índice ICE BofA de letras a un mes desde
junio), una línea en blanco, la cabecera `,Mkt-RF,SMB,HML,RMW,CMA,RF`, los meses en formato `AAAAMM` con los valores
**en porcentaje** desde julio de 1963 hasta agosto de 2026, otra línea en blanco y una segunda tabla, `Annual Factors:
January-December`, con los años. El momentum va en otro fichero, `F-F_Momentum_Factor_CSV.zip`, con una cabecera de
texto más larga que avisa de que los datos que faltan se marcan con −99,99 o −999. Las líneas terminan en CRLF.

Un lector robusto no cuenta líneas de cabecera, porque cambian de un fichero a otro: busca la primera línea que empieza
por coma y lee hasta la primera que no empieza por un año. La celda lo prueba con un texto que copia esa disposición
con los valores sintéticos del curso:

```python
import io

# Un fichero con la misma disposición que F-F_Research_Data_5_Factors
# _2x3.csv: cabecera de texto, meses AAAAMM, valores en %, y después
# los factores anuales. Los valores son los sintéticos del curso.
cab = ",Mkt-RF,SMB,HML,RMW,CMA,RF"
filas = [f"{m.replace('-', '')},"
         + ",".join(f"{100 * fac.loc[m, c]:8.2f}"
                    for c in ["mkt_rf", "smb", "hml", "rmw", "cma",
                              "rf"])
         for m in fac.index[:3]]
texto = "\r\n".join(
    ["Fichero de ejemplo (formato de la biblioteca de K. French).",
     "", cab, *filas, "", " Annual Factors: January-December ",
     cab, "  2006,   10.00,    1.00,    2.00,    3.00,    4.00,"
     "    5.00"])

def leer_french(texto):
    """Primera tabla (mensual) de un CSV de la biblioteca de French."""
    lineas = texto.splitlines()
    ini = next(i for i, l in enumerate(lineas) if l.startswith(","))
    fin = next(i for i in range(ini + 1, len(lineas))
               if not lineas[i].strip()[:1].isdigit())
    df = pd.read_csv(io.StringIO("\n".join(lineas[ini:fin])),
                     index_col=0)
    df.index = pd.PeriodIndex(df.index.astype(str), freq="M")
    df.columns = (df.columns.str.strip().str.lower()
                  .str.replace("-", "_"))
    df = df.replace([-99.99, -999], np.nan)   # faltantes
    return df / 100                            # de % a tanto por uno

leer_french(texto)
```
```output
         mkt_rf     smb     hml     rmw     cma      rf
2006-01  0.0080 -0.0235  0.0296  0.0151  0.0107  0.0034
2006-02 -0.0064 -0.0207  0.0091  0.0099  0.0265  0.0033
2006-03  0.0236 -0.0360 -0.0225  0.0560  0.0189  0.0041
```

Con red, el mismo lector sirve para los ficheros reales. El código descarga el ZIP con `urllib` (de la biblioteca
estándar), lee el CSV de dentro y une los cinco factores con el momentum por mes; no se ejecuta en el curso:

```python skip
import io
import urllib.request
import zipfile

BASE = ("https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/"
        "ftp/")
def descargar_french(nombre):
    """Descarga un ZIP de la biblioteca y devuelve el CSV como texto."""
    with urllib.request.urlopen(BASE + nombre, timeout=30) as r:
        z = zipfile.ZipFile(io.BytesIO(r.read()))
    with z.open(z.namelist()[0]) as f:
        return f.read().decode("latin-1")

ff5 = leer_french(descargar_french(
    "F-F_Research_Data_5_Factors_2x3_CSV.zip"))
mom = leer_french(descargar_french("F-F_Momentum_Factor_CSV.zip"))
ff6 = ff5.join(mom, how="inner")
```

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

Los factores de French son de acciones de EE. UU. (CRSP) y llevan su propio tipo libre a un mes. Para evaluar un fondo
europeo hacen falta los factores de su región (la biblioteca publica factores de Europa, Japón, Asia-Pacífico y
mercados desarrollados y emergentes) y en la moneda de sus rendimientos. Mezclar un fondo en euros con factores en
dólares mete el tipo de cambio en el alfa.

</aside>

## Veinte fondos con la respuesta conocida

La regresión es la misma para todos los fondos: mínimos cuadrados con constante, en datos mensuales, y errores de
Newey-West con tres retardos (lección 2.1.1), que corrigen la heterocedasticidad y algo de autocorrelación de los
residuos. El alfa mensual se multiplica por 12 para anualizarlo.

```python
def regresion(y, X, hac=True):
    """MCO con constante; errores de Newey-West (3 meses) si hac."""
    m = sm.OLS(y, sm.add_constant(X))
    if hac:
        return m.fit(cov_type="HAC", cov_kwds={"maxlags": 3})
    return m.fit()

filas = {}
for f in exc:
    capm = regresion(exc[f], fac[["mkt_rf"]])
    ff = regresion(exc[f], fac[F6])
    filas[f] = {
        "alfa_verdad_%": 100 * verdad.loc[f, "alfa_anual"],
        "alfa_capm_%": 1200 * capm.params.iloc[0],
        "beta_capm": capm.params.iloc[1],
        "alfa_ff6_%": 1200 * ff.params.iloc[0],
        "t_ff6": ff.tvalues.iloc[0],
        "r2_ff6": ff.rsquared,
    }
tab = pd.DataFrame(filas).T
tab.round(2)
```
```output
     alfa_verdad_%  alfa_capm_%  beta_capm  alfa_ff6_%  t_ff6  r2_ff6
F01           -0.1         0.04       1.00        0.05   0.55    1.00
F02           -1.0        -0.24       1.02       -0.24  -0.56    0.99
F03            0.0        -1.60       1.01       -0.72  -0.74    0.97
F04            0.0        -1.18       1.07       -1.05  -1.02    0.97
F05            0.0         3.31       0.85        0.09   0.12    0.97
F06            0.0         1.72       0.95       -1.67  -1.52    0.97
F07            0.0        -0.65       1.28        0.64   0.46    0.96
F08            3.0         3.52       0.98        3.29   2.86    0.96
F09            1.5         3.04       1.00        2.90   2.57    0.95
F10            0.0         1.45       0.73       -0.09  -0.13    0.98
F11            2.0         3.21       0.03        2.24   2.05    0.38
F12            0.0         2.88       0.67        3.13   4.15    0.96
F13            6.0        -1.19       0.54       -1.21  -1.82    0.96
F14            0.0        -3.70       1.01       -2.79  -1.98    0.94
F15            1.0         2.24       0.57        0.25   0.32    0.94
F16           -2.5        -1.99       1.00       -2.18  -3.15    0.99
F17            0.0         0.42       0.78       -0.39  -0.55    0.97
F18            0.0        -1.17       1.08        2.06   2.55    0.98
F19           -1.5        -0.09       2.00       -0.27  -0.53    1.00
F20            0.0         0.99       0.99        1.12   0.76    0.94
```

La figura de la cabecera pone el alfa verdadero (cuadrado hueco) junto al medido con seis factores (cuadrado lleno) y
su intervalo del 95 %. En la mayoría de fondos el intervalo contiene la verdad. Cuatro lecturas de la tabla:

- **El CAPM se equivoca con los fondos de estilo.** F05 (calidad) mide un 3,31 % de alfa del CAPM y un 0,09 % con seis
  factores; F06 (momentum), un 1,72 % y un −1,67 %; F03 (valor profundo), un −1,60 % y un −0,72 %. El alfa del CAPM de
  un fondo de estilo es, sobre todo, la prima de su estilo en la muestra.
- **El R² separa fondos activos de indexados.** F01 (indexado amplio) y F19 (apalancado 2x) tienen R² de 1,00; F11, un
  largo-corto neutral al mercado, 0,38: casi todo su riesgo es propio.
- **El alfa medido tiene un error grande.** Con 20 años, el error típico del alfa anual es la volatilidad propia
  dividida por √20: para un fondo con un 5 % de volatilidad propia, 1,1 puntos. F09, con un 1,5 % verdadero, mide un
  2,90 %; F19, con un −1,5 % verdadero, mide un −0,27 %.
- **Tres fondos salen mal por razones distintas.** F12 y F13 son no lineales y F14 cambia de estilo; se ven más abajo.

Las cargas se recuperan mucho mejor que los alfas, porque los factores se mueven mucho más que su media:

```python
cargas = pd.DataFrame(
    {f: regresion(exc[f], fac[F6]).params[1:] for f in exc},
    index=F6).T
err = cargas - verdad[[f"b_{c}" for c in F6]].values
lineales = [f for f in exc if f not in ("F12", "F13", "F14")]
print("error absoluto medio de las cargas (17 fondos lineales):")
err.loc[lineales].abs().mean().round(3)
```
```output
error absoluto medio de las cargas (17 fondos lineales):
mkt_rf    0.007
smb       0.023
hml       0.040
rmw       0.028
cma       0.042
mom       0.008
dtype: float64
```

En los 17 fondos lineales, el error absoluto medio de la carga de mercado es de 0,007 y el de las demás, entre 0,008
y 0,042. Una regresión factorial es un buen instrumento para medir **exposiciones** y uno malo para medir **alfas**.

## Atribución: de dónde sale el rendimiento

Con las cargas estimadas, el exceso medio de un fondo se descompone exactamente en alfa más carga por media de cada
factor (la regresión con constante pasa por las medias):

$$
\overline{r - r_f} = \hat\alpha + \sum_k \hat b_k\, \overline{f_k}.
$$

F10 es el caso de libro: un 1,45 % de alfa del CAPM.

```python
def atribucion(f, factores):
    """Rendimiento medio anual: alfa + carga × media de cada factor."""
    m = regresion(exc[f], fac[factores], hac=False)
    partes = 1200 * m.params[1:] * fac[factores].mean()
    partes["alfa"] = 1200 * m.params.iloc[0]
    partes["total"] = 1200 * exc[f].mean()
    return partes

pd.DataFrame({"capm": atribucion("F10", ["mkt_rf"]),
              "ff6": atribucion("F10", F6)}).round(2)
```
```output
        capm   ff6
alfa    1.45 -0.09
cma      NaN  0.44
hml      NaN -1.24
mkt_rf  6.79  7.51
mom      NaN  0.34
rmw      NaN  1.21
smb      NaN  0.07
total   8.25  8.25
```

El exceso medio del 8,25 % anual es el mismo en las dos columnas; cambia el reparto. Con el CAPM, 6,79 puntos son
mercado y 1,45 alfa. Con seis factores, el mercado sube a 7,51 (la beta de mercado de F10 con los demás factores es
mayor que su beta del CAPM), rentabilidad aporta 1,21, inversión 0,44, momentum 0,34, valor resta 1,24 y el alfa queda
en −0,09. El fondo tenía exposiciones a primas que el CAPM no mide; no tenía alfa.

## Muchos fondos, algunos con suerte

Probar el alfa de 20 fondos es hacer 20 contrastes. Con un nivel del 5 %, aunque ninguno tuviera alfa, se esperaría
uno significativo por azar. La lección 2.1.8 explica las correcciones; aquí se aplican con la verdad a la vista:

```python
from statsmodels.stats.multitest import multipletests

p = pd.Series({f: regresion(exc[f], fac[F6]).pvalues.iloc[0]
               for f in exc})
holm = multipletests(p, alpha=0.05, method="holm")
bh = multipletests(p, alpha=0.05, method="fdr_bh")
sig = pd.DataFrame({"alfa_verdad_%": tab["alfa_verdad_%"],
                    "t": tab["t_ff6"], "p": p,
                    "holm": holm[0], "fdr_bh": bh[0]})
sig[sig["p"] < 0.05].round(4)
```
```output
     alfa_verdad_%       t       p   holm  fdr_bh
F08            3.0  2.8593  0.0042  False    True
F09            1.5  2.5705  0.0102  False    True
F11            2.0  2.0466  0.0407  False   False
F12            0.0  4.1459  0.0000   True    True
F14            0.0 -1.9828  0.0474  False   False
F16           -2.5 -3.1471  0.0016   True    True
F18            0.0  2.5541  0.0106  False    True
```

Siete fondos tienen p < 0,05. Con la verdad conocida:

| Fondo | Alfa verdadero | p | ¿Qué es? | Holm | BH |
|---|---|---|---|---|---|
| F12 | 0 | 0,0000 | Market timing: alfa espurio de un modelo mal especificado | sí | sí |
| F16 | −2,5 % | 0,0016 | Comisión alta: alfa negativo real | sí | sí |
| F08 | 3 % | 0,0042 | Alfa real | no | sí |
| F09 | 1,5 % | 0,0102 | Alfa real pequeño, medido con suerte | no | sí |
| F18 | 0 | 0,0106 | **Falso positivo** | no | sí |
| F11 | 2 % | 0,0407 | Alfa real | no | no |
| F14 | 0 | 0,0474 | Cambio de estilo: alfa espurio | no | no |

Holm controla la probabilidad de cometer **algún** falso positivo entre los 20 y se queda con F12 y F16: elimina el
falso positivo F18, pero también los alfas reales de F08, F09 y F11. Benjamini-Hochberg controla la **proporción** de
falsos descubrimientos y acepta cinco: tres con alfa real o negativo real, el falso positivo F18 y el espurio F12.
Ninguna corrección arregla F12: su t de 4,15 es real, pero mide un modelo mal planteado, no una habilidad.

F18 es un fondo «contrario» con una carga de −0,4 en momentum y cero alfa. En esta muestra su residuo tuvo una media
positiva del orden de dos errores típicos. Con 20 fondos, que a uno le pase es lo esperable.

```mermaid
flowchart TB
  A["Alfa con t > 2"] --> M{¿Muchos fondos?}
  M -- sí --> C[Holm o BH]
  M -- no --> N{¿No lineal?}
  C --> N
  N -- sí --> T[Añadir TM o HM]
  N -- no --> E{¿Carga estable?}
  T --> E
  E -- no --> V[Ventanas móviles]
  E -- sí --> R[Alfa creíble]
```

## Market timing y venta de opciones

Dos fondos tienen rendimientos que no son lineales en el mercado:

- **F12 hace market timing.** Sube su exposición antes de las subidas y la baja antes de las caídas. El resultado es una
  relación convexa con el mercado; Treynor y Mazuy (1966) la modelaron con un término cuadrático:
  $r - r_f = \alpha + \beta\,MKT + \gamma\,MKT^2 + \dots$. Verdad: $\gamma = 0,5$, $\alpha = 0$.
- **F13 vende puts.** Cobra una prima fija y, cuando el mercado cae, pierde más que su beta normal. Henriksson y
  Merton (1981) lo modelaron con un término $\min(MKT, 0)$: una beta distinta en las caídas. Verdad: $\alpha = 6\,\%$
  anual (la prima), beta normal 0,4 y beta extra de 0,25 en las caídas.

```python
X = fac[F6].copy()
X["mkt2"] = fac["mkt_rf"] ** 2                  # Treynor-Mazuy
X["mkt_neg"] = np.minimum(fac["mkt_rf"], 0)     # Henriksson-Merton

tm = regresion(exc["F12"], X[F6 + ["mkt2"]])
hm = regresion(exc["F13"], X[F6 + ["mkt_neg"]])
pd.DataFrame({
    "F12_lineal": [tab.loc["F12", "alfa_ff6_%"], np.nan],
    "F12_TM": [1200 * tm.params.iloc[0], tm.params.iloc[-1]],
    "F13_lineal": [tab.loc["F13", "alfa_ff6_%"], np.nan],
    "F13_HM": [1200 * hm.params.iloc[0], hm.params.iloc[-1]],
}, index=["alfa_%", "coef_no_lineal"]).round(2)
```
```output
                F12_lineal  F12_TM  F13_lineal  F13_HM
alfa_%                3.13    0.68       -1.21    5.83
coef_no_lineal         NaN    0.44         NaN    0.24
```

El modelo lineal se equivoca con los dos y en sentidos opuestos. A F12 le atribuye un 3,13 % de alfa: la media de
$MKT^2$ es positiva y, sin el término cuadrático, acaba en la constante. Con Treynor-Mazuy el alfa baja al 0,68 % (no
significativo) y $\gamma$ sale 0,44, cerca de 0,5. A F13 le atribuye un −1,21 %, y con Henriksson-Merton el alfa sale
5,83 % y la beta extra 0,24: la verdad.

¿Qué es entonces el 6 % de F13? Lo que cobra por asegurar a otros contra las caídas. Lo que le cuesta:

```python
b_mkt = hm.params.iloc[1]
extra = hm.params.iloc[-1]
print(f"beta normal {b_mkt:.2f}, beta extra en caídas {extra:.2f}")
coste_put = 1200 * extra * X["mkt_neg"].mean()
alfa_hm = 1200 * hm.params.iloc[0]
print(f"alfa (prima cobrada):         {alfa_hm:6.2f} %")
print(f"media de extra·min(mkt, 0):   {coste_put:6.2f} %")
peores = fac["mkt_rf"].nsmallest(3).index
(100 * pd.DataFrame({"mkt_rf": fac.loc[peores, "mkt_rf"],
                     "F13": exc.loc[peores, "F13"]})).round(2)
```
```output
beta normal 0.40, beta extra en caídas 0.24
alfa (prima cobrada):           5.83 %
media de extra·min(mkt, 0):    -5.68 %
         mkt_rf    F13
mes
2018-10  -28.94 -18.54
2011-09  -21.28 -12.79
2025-03  -20.74 -13.54
```

*Fig. — Rendimiento mensual medio del fondo F13, que vende puts, por tramos del mercado, con el ajuste de Henriksson-Merton (2006-2025).* Medias del exceso mensual de F13 por tramos de 3 puntos del exceso del mercado (240 meses). Una línea quebrada destacada en el cero: pendiente 0,40 cuando el mercado sube y 0,64 cuando cae. Las medias siguen la línea quebrada; el tramo más bajo, un único mes con el mercado a −29 %, da una pérdida de F13 del 18,5 %.

La beta extra de 0,24 en las caídas tiene un coste medio del 5,68 % anual, casi todo el alfa. En los tres peores meses
del mercado sintético (−28,9 %, −21,3 % y −20,7 %), F13 pierde un 18,5 %, un 12,8 % y un 13,5 %. La figura muestra la
forma: medias por tramos del mercado sobre una línea quebrada con pendiente 0,40 en las subidas y 0,64 en las caídas.
Un «alfa» que se cobra a cambio de un riesgo de cola no es habilidad; es una prima de riesgo con otro nombre (lección
3.6.1). La regresión lineal, además, lo esconde.

## Cambio de estilo

F14 era un fondo de valor (carga de 0,8 en HML) hasta diciembre de 2015 y desde enero de 2016 es de crecimiento
(−0,3). Una sola regresión de toda la muestra promedia los dos:

```python
movil = {}
for i in range(36, len(exc) + 1):
    v = slice(i - 36, i)
    m = regresion(exc["F14"].iloc[v], fac[F6].iloc[v], hac=False)
    movil[exc.index[i - 1]] = m.params["hml"]
movil = pd.Series(movil)
mitades = {t: regresion(exc["F14"].loc[a:b], fac[F6].loc[a:b],
                        hac=False).params["hml"]
           for t, (a, b) in {"2006-2015": ("2006-01", "2015-12"),
                             "2016-2025": ("2016-01", "2025-12")
                             }.items()}
print("toda la muestra:", round(cargas.loc["F14", "hml"], 2),
      "· por mitades:", {k: round(float(v), 2)
                         for k, v in mitades.items()})
movil.iloc[::24].round(2)
```
```output
toda la muestra: 0.22 · por mitades: {'2006-2015': 0.85, '2016-2025': -0.35}
2008-12    0.94
2010-12    0.84
2012-12    0.86
2014-12    0.79
2016-12    0.51
2018-12   -0.39
2020-12   -0.35
2022-12   -0.36
2024-12   -0.35
dtype: float64
```

*Fig. — Carga en valor (HML) del fondo F14, que cambia de estilo en enero de 2016: regresión móvil de 36 meses frente a la verdad.* Línea destacada con la carga en HML estimada con los 36 meses anteriores, de finales de 2008 a 2025, y una línea discontinua con la verdad: 0,8 hasta diciembre de 2015 y −0,3 desde enero de 2016. La estimación ronda 0,8-0,95 hasta 2015, baja de forma gradual durante 2016, 2017 y 2018, cruza el cero en septiembre de 2018, casi tres años después del cambio, y se queda cerca de −0,35 desde entonces.

Con toda la muestra, la carga en valor sale 0,22: un fondo «ligeramente de valor» que nunca existió. Por mitades sale
0,85 y −0,35, cerca de la verdad. La regresión móvil de 36 meses ve el cambio, pero tarde: cruza el cero en
septiembre de 2018, casi tres años después. Además, el promedio mal especificado deja un alfa de −2,79 % con t −1,98,
que no está en el fondo: es la consecuencia de imponer una carga fija a un fondo que no la tiene. Ventanas móviles,
regresiones por tramos o modelos de cargas variables (el filtro de Kalman de la lección 2.1.6) son las herramientas
para esto.

## Atribución del riesgo de una cartera

La atribución también sirve para el riesgo. Con un modelo factorial $\Sigma = B\,\Sigma_f\,B' + D$, la varianza de una
cartera $w$ es $x'\Sigma_f x + w'Dw$ con $x = B'w$, la exposición de la cartera a cada factor. Por Euler, como en la
lección 4.1.4, cada factor aporta $x_k(\Sigma_f x)_k / \sigma_p^2$ y el resto es idiosincrático.

El universo de la lección 4.1.4 se generó con un modelo de diez factores publicado: cargas verdaderas en
`universo4_verdad.csv`, volatilidades y correlaciones de los factores por régimen en `universo4_factores_verdad.csv` y
los rendimientos diarios realizados de los factores en `universo4_factores_diarios.parquet`. Se puede calcular la
atribución verdadera del régimen de calma y la estimada con regresiones diarias en las sesiones de calma, y
compararlas:

```python
precios = pd.read_parquet("universo4_precios.parquet")
precios = precios.set_index("fecha")
diarios = pd.read_parquet("universo4_factores_diarios.parquet")
diarios = diarios.set_index("fecha")
r = precios.pct_change()
r.iloc[0] = precios.iloc[0] / 100 - 1
cols = [c for c in precios if c not in ("MONET", "RF_T13")]
ex_d = r[cols].sub(diarios["rf"], axis=0)
nombres = [c[2:] for c in diarios if c.startswith("f_")]
f_d = diarios[[f"f_{k}" for k in nombres]].set_axis(nombres, axis=1)

# verdad: B, covarianza de los factores y D del régimen de calma
uv = pd.read_csv("universo4_verdad.csv", index_col="activo").loc[cols]
B = uv[[f"b_{k}" for k in nombres]].values
fv = pd.read_csv("universo4_factores_verdad.csv")
fv = fv[fv["regimen"] == "calma"].set_index("factor").loc[nombres]
C = fv[[f"corr_{k}" for k in nombres]].values
Sf = np.outer(fv["vol_anual"], fv["vol_anual"]) * C
D = np.diag(uv["vol_idio"] ** 2)
cvr = pd.read_csv("universo4_cov_verdad.csv")
cvr = cvr[cvr["regimen"] == "calma"].set_index("activo")
dif = B @ Sf @ B.T + D - cvr.loc[cols, cols].values
print(f"máx. |BΣfB' + D − Σ_calma|: {np.abs(dif).max():.1e}")

# estimación: regresiones diarias en las sesiones de calma
calma = diarios["regimen"] == "calma"
Xf = sm.add_constant(f_d[calma])
coef = np.linalg.lstsq(Xf.values, ex_d[calma].values, rcond=None)[0]
B_e = coef[1:].T
res = ex_d[calma].values - Xf.values @ coef
Sf_e = 252 * np.cov(f_d[calma].values.T)
D_e = np.diag(252 * res.var(axis=0, ddof=Xf.shape[1]))

def riesgo_factores(w, B, Sf, D):
    x = B.T @ w                          # exposición a cada factor
    var = x @ Sf @ x + w @ D @ w
    rc = x * (Sf @ x) / var              # contribución de cada factor
    return pd.Series(np.r_[rc, w @ D @ w / var],
                     index=nombres + ["idiosincrático"])

w = pd.Series(0.0, index=cols)
w[["RV_EEUU", "RF_T710"]] = [0.6, 0.4]
w_n = np.full(len(cols), 1 / len(cols))
pd.DataFrame({
    "60/40_verdad": riesgo_factores(w.values, B, Sf, D),
    "60/40_estim": riesgo_factores(w.values, B_e, Sf_e, D_e),
    "1/N_verdad": riesgo_factores(w_n, B, Sf, D),
    "1/N_estim": riesgo_factores(w_n, B_e, Sf_e, D_e),
}).round(3)
```
```output
máx. |BΣfB' + D − Σ_calma|: 5.0e-09
                60/40_verdad  60/40_estim  1/N_verdad  1/N_estim
mercado                0.976        0.974       0.786      0.777
tamano                -0.008       -0.006       0.007      0.006
valor                  0.002        0.003       0.004      0.002
tipos                 -0.000        0.002      -0.011     -0.010
credito                0.000       -0.000       0.021      0.021
materias               0.000        0.000       0.107      0.114
dolar                 -0.000       -0.001       0.052      0.055
emergentes             0.000       -0.001       0.019      0.021
europa                 0.000        0.000       0.001      0.000
japon                  0.000       -0.000       0.003      0.002
idiosincrático         0.030        0.029       0.011      0.011
```

Primero, la comprobación: $B\,\Sigma_f\,B' + D$ con los ficheros publicados reproduce la covarianza verdadera de calma
con un error de $5 \cdot 10^{-9}$, es decir, el redondeo de los ficheros. Después, la atribución: en la 60/40, el
factor de mercado explica el 97,6 % del riesgo (verdad) y el 97,4 % (estimado); los tipos, nada: la cartera tiene
exposición a ellos, pero su covarianza con la cartera es casi nula, porque la varianza propia del factor se compensa
con su correlación negativa con el mercado. En la 1/N de los 36 activos, el
mercado explica el 78,6 %, las materias primas el 10,7 % y el dólar el 5,2 %; las estimaciones están a menos de un
punto de la verdad en todos los factores. Con un modelo bien especificado y 20 años de datos diarios, la atribución
del riesgo es fiable. La del rendimiento, como se vio con los alfas, no tanto.

## PCA: factores sin nombre

Los factores de Fama-French son **observados**: carteras construidas con una regla económica. Los componentes
principales son factores **estadísticos**: las direcciones de máxima varianza de los propios rendimientos,
ortogonales entre sí, sin nombre ni signo fijado. Se calculan con la descomposición en autovalores de la matriz de
correlación (lección 0.7.3); su uso para estimar covarianzas con pocos datos está en la lección 4.1.2. Aquí la
pregunta es otra: ¿los componentes de un universo son sus factores?

```python
Z = (ex_d - ex_d.mean()) / ex_d.std()
autoval, autovec = np.linalg.eigh(np.corrcoef(Z.values.T))
autoval, autovec = autoval[::-1], autovec[:, ::-1]
pcs = Z.values @ autovec[:, :10]
print("autovalores:", autoval[:6].round(2))
print("varianza explicada por 1, 3 y 10:",
      (autoval.cumsum()[[0, 2, 9]] / autoval.sum()).round(3))

def r2(y, X):
    X = np.column_stack([np.ones(len(X)), X])
    e = y - X @ np.linalg.lstsq(X, y, rcond=None)[0]
    return 1 - e.var() / y.var()

pd.DataFrame({k: [r2(f_d[f].values, pcs[:, :k]) for f in nombres]
              for k in (1, 3, 5, 10)}, index=nombres).round(2)
```
```output
autovalores: [20.15  6.11  2.68  1.06  0.95  0.74]
varianza explicada por 1, 3 y 10: [0.56  0.804 0.931]
              1     3     5     10
mercado     0.97  0.98  0.99  0.99
tamano      0.05  0.05  0.06  0.09
valor       0.00  0.06  0.08  0.78
tipos       0.05  0.96  0.98  0.98
credito     0.28  0.33  0.93  0.95
materias    0.21  0.85  0.89  0.93
dolar       0.16  0.35  0.65  0.91
emergentes  0.19  0.23  0.24  0.41
europa      0.00  0.00  0.01  0.03
japon       0.00  0.00  0.00  0.95
```

El primer componente explica el 56 % de la varianza de los 36 activos; los tres primeros, el 80 %, y los diez
primeros, el 93 %. Que haya diez factores verdaderos no quiere decir que los diez primeros componentes sean esos
diez factores. La tabla da el R² de la regresión de cada factor verdadero sobre los $k$ primeros componentes:

*Fig. — Cuánto de cada factor verdadero del universo recuperan los componentes principales de los 36 activos (2006-2025).* Una fila por factor con el R² de su regresión sobre los 3 primeros componentes (cuadrado hueco) y sobre los 10 primeros (lleno). Mercado 0,98 y 0,99; tipos 0,96 y 0,98; materias primas 0,85 y 0,93; crédito 0,33 y 0,95; dólar 0,35 y 0,91; Japón 0,00 y 0,95; valor 0,06 y 0,78; emergentes 0,23 y 0,41; tamaño 0,05 y 0,09; Europa 0,00 y 0,03 (destacado): con diez componentes, el factor europeo sigue sin aparecer.

- **Un componente ya es el mercado** (R² 0,97). Con tres, aparecen los tipos (0,96) y las materias primas (0,85).
- **Con cinco**, el crédito (0,93); **con diez**, el dólar (0,91), Japón (0,95) y el valor (0,78).
- **Tamaño, emergentes y Europa no aparecen** ni con diez componentes (0,09, 0,41 y 0,03). El factor europeo, con un
  6 % de volatilidad, solo carga en dos activos (la bolsa europea con y sin cobertura); el de Japón, con un 9 %, también
  en dos, y sí aparece. PCA ordena por varianza explicada: un factor estrecho y poco volátil queda por debajo de
  combinaciones de ruido idiosincrático de otros activos.

```python
cargas_pc = pd.DataFrame(autovec[:, :3], index=cols,
                         columns=["pc1", "pc2", "pc3"])
for c in cargas_pc:
    s = cargas_pc[c].sort_values()
    print(c, "extremos:", ", ".join(
        f"{k} {v:+.2f}" for k, v in pd.concat([s.head(2),
                                               s.tail(2)]).items()))
```
```output
pc1 extremos: RF_T20 -0.05, RF_T710 -0.05, SC_IND +0.21, RV_EEUU +0.22
pc2 extremos: RF_T710 -0.38, RF_T37 -0.38, ES_VAL +0.05, SC_FIN +0.06
pc3 extremos: MP_AMP -0.48, MP_ENE -0.47, RF_CIG +0.10, RF_CHY +0.14
```

Las cargas de los tres primeros componentes se pueden interpretar porque el universo es sencillo: el primero carga
positivo en todas las bolsas (mercado), el segundo carga casi solo en los bonos del Tesoro con el mismo signo (tipos;
el signo negativo es arbitrario: un componente y su opuesto son el mismo) y el tercero, en las materias primas. En un
universo real la interpretación es más difícil y cambia de una ventana a otra; a partir del cuarto componente casi
nunca hay una lectura económica limpia.

Para qué sirve cada tipo de factor:

| | Factores observados (Fama-French) | Componentes principales |
|---|---|---|
| Qué son | Carteras con una regla económica | Direcciones de máxima varianza |
| Interpretación | Directa (valor, tamaño…) | Solo los primeros, y no siempre |
| Se pueden comprar | Sí, aproximadamente | No como tales |
| Para qué | Evaluar gestores, atribuir rendimiento | Reducir dimensión, estimar covarianzas (4.1.2), detectar cambios de régimen |
| Riesgo | Olvidar un factor (el alfa lo absorbe) | Sobreinterpretar los componentes |

## Errores típicos

- **Quedarse con el CAPM.** Un alfa del CAPM en un fondo de estilo es la prima del estilo.
- **Factores de otra región o moneda.** Factores de EE. UU. para un fondo europeo meten en el alfa el tipo de cambio y
  la diferencia entre mercados.
- **Leer el t de un fondo entre muchos.** Entre 20 fondos, uno sin alfa sale con t > 2 (F18).
- **Modelos lineales para estrategias con opciones o con timing.** La regresión lineal fabrica alfa (F12) o lo esconde
  (F13). Para estrategias de venta de volatilidad, el alfa es la prima de un seguro.
- **Cargas fijas para fondos que cambian.** F14 sale con un estilo que nunca tuvo y un alfa negativo espurio.
- **Interpretar todos los componentes principales.** El primero suele ser el mercado; a partir de ahí, cuidado.
- **Rendimientos logarítmicos.** La regresión factorial de una cartera usa rendimientos simples en exceso, como los
  factores de French.

## Ejercicios

1. Repite la regresión de seis factores de F08 solo con los diez primeros años y solo con los diez últimos. ¿Cuántas
   veces sale significativo su alfa (verdadero: 3 %)? ¿Qué dice eso de evaluar a un gestor con diez años de datos?

**Solución.**

```python
for a, b in [("2006-01", "2015-12"), ("2016-01", "2025-12")]:
    m = regresion(exc["F08"].loc[a:b], fac[F6].loc[a:b])
    print(f"{a[:4]}-{b[:4]}: alfa {1200 * m.params.iloc[0]:5.2f} %"
          f"  t {m.tvalues.iloc[0]:5.2f}")
```
```output
2006-2015: alfa  3.69 %  t  2.42
2016-2025: alfa  2.47 %  t  1.43
```

Con diez años, el error típico del alfa crece en un factor $\sqrt{2}$ respecto a veinte, y un alfa real del 3 % con
un 4,5 % de volatilidad propia tiene un t esperado de solo $3 / (4,5/\sqrt{10}) \approx 2,1$. Aproximadamente la mitad
de las veces no saldrá significativo. En estos datos pasa exactamente eso: en 2006-2015 el alfa sale un 3,69 % con
t = 2,42 y en 2016-2025 un 2,47 % con t = 1,43, que no es significativo. Diez años de historia no bastan para separar a un buen gestor de uno con suerte,
y casi ningún gestor tiene veinte con la misma estrategia.

2. Estima F13 con el CAPM y con el modelo de Henriksson-Merton solo con mercado (sin los otros cinco factores) y
   compara el alfa. ¿Cambia la conclusión respecto al modelo de seis factores?

**Solución.**

```python
capm13 = regresion(exc["F13"], fac[["mkt_rf"]])
hm13 = regresion(exc["F13"], X[["mkt_rf", "mkt_neg"]])
print(f"CAPM: alfa {1200 * capm13.params.iloc[0]:.2f} %, "
      f"beta {capm13.params.iloc[1]:.2f}")
print(f"HM:   alfa {1200 * hm13.params.iloc[0]:.2f} %, "
      f"beta {hm13.params.iloc[1]:.2f}, "
      f"extra {hm13.params.iloc[2]:.2f}")
```
```output
CAPM: alfa -1.19 %, beta 0.54
HM:   alfa 5.79 %, beta 0.40, extra 0.24
```

No cambia: F13 no tiene exposición a los otros factores, así que el mercado basta. Lo que decide es el término no
lineal. Con el CAPM lineal, el alfa es del −1,19 % y la beta, 0,54, queda entre la normal y la de las caídas; con
Henriksson-Merton, el alfa vuelve al 5,79 %, la beta normal a 0,40 y la extra a 0,24, cerca de la verdad. Elegir los factores importa;
elegir la forma del modelo, también.

3. Sin código: un gestor de una estrategia de venta de puts sobre un índice presenta un alfa de seis factores del
   −0,5 % y argumenta que «su estrategia no tiene alfa, pero tampoco cuesta nada, porque su beta es solo 0,5». Usa F13
   para explicar qué está ocultando la regresión lineal y qué pedirías para evaluarlo.

**Solución.**

La regresión lineal mezcla dos cosas que en F13 son de signo contrario: una prima que se cobra todos los meses (el
alfa de Henriksson-Merton, 5,83 % anual) y una pérdida extra en las caídas (beta adicional de 0,24, que cuesta de
media un 5,68 % al año y concentra las pérdidas en los peores meses: −18,5 % cuando el mercado cae un 28,9 %). La
beta de 0,5 es un promedio de 0,40 en las subidas y 0,64 en las caídas: la exposición en el peor momento es mayor que
la que se declara. Pediría la regresión con el término $\min(MKT, 0)$, los peores meses de la estrategia junto a los
del mercado, su caída máxima y un análisis de estrés (lección 4.2.4) con caídas de mercado que no estén en su
historial. La pregunta no es si tiene alfa, sino cuánto pierde cuando el mercado cae y si alguien le está pagando lo
suficiente por asumirlo.

## Autoevaluación

1. F10 tiene un alfa del CAPM del 1,45 % anual y un alfa de seis factores del −0,09 %. ¿De dónde salía el alfa del CAPM?

   - A. De la habilidad del gestor, que el modelo de seis factores no sabe medir
   - B. De un error de los datos
   - C. De exposiciones a primas que el CAPM no incluye: rentabilidad (RMW, +1,21 puntos), inversión (CMA, +0,44) y momentum (+0,34), con HML restando 1,24
   - D. Del tipo libre de riesgo

   *Respuesta C: De exposiciones a primas que el CAPM no incluye: rentabilidad (RMW, +1,21 puntos), inversión (CMA, +0,44) y momentum (+0,34), con HML restando 1,24.* La atribución con seis factores reparte el exceso medio del 8,25 % en mercado (7,51), los otros cinco factores y un alfa de −0,09. El fondo cobra primas que se pueden comprar con un índice de factores: no es alfa.

2. Entre los 20 fondos, siete tienen p < 0,05 en el alfa de seis factores. Con la corrección de Holm, solo quedan F12 y F16. ¿Qué pasa con F08, que tiene un alfa verdadero del 3 %?

   - A. Que Holm está mal aplicado
   - B. Que con 20 años y su volatilidad propia, un 3 % de alfa da un t de 2,86 y p = 0,0042: no supera el umbral de Holm (0,05/20 = 0,0025 para el primero). Controlar los falsos positivos cuesta potencia
   - C. Que F08 no tiene alfa
   - D. Que hay que usar errores ordinarios en lugar de Newey-West

   *Respuesta B: Que con 20 años y su volatilidad propia, un 3 % de alfa da un t de 2,86 y p = 0,0042: no supera el umbral de Holm (0,05/20 = 0,0025 para el primero). Controlar los falsos positivos cuesta potencia.* Holm controla la probabilidad de algún falso positivo entre los 20; con eso pierde fondos con alfa real. Benjamini-Hochberg (FDR) sí acepta F08 y F09, pero también el falso positivo F18. No hay corrección sin coste.

3. F12 tiene un alfa lineal del 3,13 % con t = 4,15, el más significativo de todos, y un alfa verdadero de cero. ¿Por qué?

   - A. Porque hace market timing: su rendimiento lleva un término 0,5·mkt_rf², siempre positivo, que la regresión lineal mete en el alfa. Con el término cuadrático de Treynor-Mazuy el alfa baja al 0,68 % y el coeficiente sale 0,44
   - B. Por azar
   - C. Porque su beta es baja
   - D. Porque los errores de Newey-West inflan el t

   *Respuesta A: Porque hace market timing: su rendimiento lleva un término 0,5·mkt_rf², siempre positivo, que la regresión lineal mete en el alfa. Con el término cuadrático de Treynor-Mazuy el alfa baja al 0,68 % y el coeficiente sale 0,44.* La media de mkt_rf² es positiva; en una regresión lineal se convierte en constante. El modelo correcto es no lineal, y la significación del alfa lineal no dice nada de la habilidad.

4. F13 vende puts: alfa verdadero del 6 % y beta extra de 0,25 cuando el mercado cae. ¿Qué alfa da la regresión lineal y por qué?

   - A. Un 6 %, porque la regresión es insesgada
   - B. Cero
   - C. Un 12 %
   - D. Un −1,21 %: el término 0,25·min(mkt_rf, 0) tiene media negativa y la regresión lineal lo absorbe entre el alfa y la beta. Con el término de Henriksson-Merton el alfa sale 5,83 %

   *Respuesta D: Un −1,21 %: el término 0,25·min(mkt_rf, 0) tiene media negativa y la regresión lineal lo absorbe entre el alfa y la beta. Con el término de Henriksson-Merton el alfa sale 5,83 %.* El 6 % es la prima que cobra por vender seguro; la media de 0,24·min(mkt_rf, 0) le cuesta un 5,68 % al año. Lo que gana en los meses tranquilos lo devuelve en los de caída (−18,5 % en el peor mes). Separar los dos términos exige el modelo no lineal.

5. PCA sobre los 36 activos del universo recupera el factor de mercado con un solo componente (R² 0,97) y no recupera el factor europeo ni con diez (R² 0,03). ¿Por qué?

   - A. Porque el factor europeo no existe
   - B. Porque PCA necesita datos mensuales
   - C. Porque PCA ordena por varianza: el mercado mueve casi todos los activos y domina, mientras que el factor europeo, de un 6 % de volatilidad, solo carga en dos activos y su efecto se confunde con otras combinaciones
   - D. Porque los componentes principales son siempre los factores de Fama-French

   *Respuesta C: Porque PCA ordena por varianza: el mercado mueve casi todos los activos y domina, mientras que el factor europeo, de un 6 % de volatilidad, solo carga en dos activos y su efecto se confunde con otras combinaciones.* Los componentes son las direcciones de máxima varianza, ortogonales entre sí, no los factores económicos. Recuperan bien los factores grandes y anchos (mercado, tipos, materias primas) y mal los estrechos (Europa, tamaño, emergentes).

## Ideas clave

- Una regresión de series temporales de los excesos de una cartera sobre los factores da su alfa (la constante), sus cargas y su R². Con 240 meses, las cargas de los 17 fondos lineales se recuperan con un error medio de 0,01 a 0,04.
- Un alfa del CAPM puede ser una exposición a otros factores: el de F10 (1,45 %) es rentabilidad, inversión y momentum, y desaparece con seis factores.
- Entre 20 fondos sin corregir, un fondo sin alfa sale significativo (F18, t = 2,55). Holm lo elimina pero también elimina alfas reales; Benjamini-Hochberg conserva los reales y el falso.
- Las estrategias no lineales engañan a la regresión lineal: el market timing parece alfa (F12) y la venta de puts parece no tenerlo (F13). Hay que añadir mkt_rf² o min(mkt_rf, 0).
- Una carga estable en toda la muestra puede ser la media de dos estilos (F14: 0,22 frente a 0,85 y −0,35 por mitades); una ventana móvil de 36 meses tarda casi tres años en verlo.
- PCA recupera los factores grandes y anchos (mercado, tipos, materias primas) y no los estrechos; sus componentes no son factores económicos, sino direcciones de varianza.

## Recursos

### Research

- [Alpha Factors y Alpha Trading en Python](https://pythonparatrading.com/alpha-factors-y-alpha-trading-en-python/) · Research-0007 · 5 min
- [Price Discovery & Arbitrage Price Theory](https://pythonparatrading.com/arbitrage-pricing-theory-and-price-discovery/) · Research-0006 · 6 min

### Documentación

- [Kenneth R. French: Data Library (factores de Fama-French y momentum)](https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html) · mba.tuck.dartmouth.edu
- [Kenneth R. French: descripción de los factores de Fama-French de cinco factores (2x3)](https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/Data_Library/f-f_5_factors_2x3.html) · mba.tuck.dartmouth.edu
- [statsmodels: multipletests](https://www.statsmodels.org/stable/generated/statsmodels.stats.multitest.multipletests.html) · statsmodels.org

### Libros

- [Sharpe, W. F. (1964): Capital Asset Prices: A Theory of Market Equilibrium under Conditions of Risk. The Journal of Finance 19(3), 425-442](https://doi.org/10.2307/2977928) · doi.org
- [Fama, E. F. y French, K. R. (1993): Common risk factors in the returns on stocks and bonds. Journal of Financial Economics 33(1), 3-56](https://doi.org/10.1016/0304-405X(93)90023-5) · doi.org
- [Fama, E. F. y French, K. R. (2015): A five-factor asset pricing model. Journal of Financial Economics 116(1), 1-22](https://doi.org/10.1016/j.jfineco.2014.10.010) · doi.org
- [Carhart, M. M. (1997): On Persistence in Mutual Fund Performance. The Journal of Finance 52(1), 57-82](https://doi.org/10.1111/j.1540-6261.1997.tb03808.x) · doi.org
- [Henriksson, R. D. y Merton, R. C. (1981): On Market Timing and Investment Performance. II. Statistical Procedures for Evaluating Forecasting Skills. The Journal of Business 54(4)](https://doi.org/10.1086/296144) · doi.org

### Datos

- [Datos del nivel 4: factores mensuales sintéticos con el formato de Kenneth French (CSV)](https://pythonparatrading.com/curso/datos/nivel-4/ff4_factores_mensuales.csv) · Descarga · ff4_factores_mensuales.csv
- [Datos del nivel 4: rendimientos mensuales de 20 fondos sintéticos (CSV)](https://pythonparatrading.com/curso/datos/nivel-4/ff4_fondos_mensuales.csv) · Descarga · ff4_fondos_mensuales.csv

Lección anterior: [4.1.5 · Optimización con CVaR, drawdown, rotación y costes](https://pythonparatrading.com/curso-python-trading/nivel-4/optimizacion-cvar-drawdown-turnover-y-costes/)

Lección siguiente: [4.1.7 · Rebalanceo y carteras de estrategias](https://pythonparatrading.com/curso-python-trading/nivel-4/rebalanceo-y-carteras-de-estrategias/)
