Lección 2.3.7 · 65 min
Estrategias específicas de cripto: momentum, arbitraje de funding y basis
Las cripto se negocian todos los días a todas horas, se mueven juntas y tienen dos fuentes de carry propias: el funding de los perpetuos y el basis de los futuros con vencimiento. Esta lección mide el factor común de quince monedas sintéticas, prueba un momentum transversal semanal plantado con ejecución al día siguiente y costes, y presenta la idea del cash-and-carry, que el nivel 3 desarrolla.
- Módulo
- 2.3 · Familias de estrategias
- Duración
- 65 min
Lecciones del nivel 2
2.1 · Estadística y econometría para trading
- 2.1.1 Contrastes de hipótesis, p-valores, bootstrap y regresión con errores robustos
- 2.1.2 Estacionariedad: ADF, KPSS, diferenciación y diferenciación fraccional
- 2.1.3 Modelos ARMA y ARIMA: autocorrelación simple (ACF) y parcial (PACF)
- 2.1.4 Modelos de volatilidad: ARCH, GARCH, EGARCH y GJR con la librería arch
- 2.1.5 Cointegración: Engle-Granger, Johansen y vida media de la reversión
- 2.1.6 Filtro de Kalman para hedge ratios dinámicos
- 2.1.7 Detección de regímenes: modelos de Markov ocultos y cambios estructurales
- 2.1.8 El problema de las pruebas múltiples: Bonferroni, FDR y el «factor zoo»
2.2 · Anatomía de un sistema de trading
- 2.2.1 Hipótesis de ventaja: riesgo, comportamiento, estructura e información
- 2.2.2 Universo, señal, filtro, entrada, salida, sizing y gestión del riesgo
- 2.2.3 Frecuencias: intradía, swing y posicional, y la capacidad de una estrategia
- 2.2.4 Diario de investigación y registro de experimentos contra el data snooping
2.3 · Familias de estrategias
- 2.3.1 Seguimiento de tendencia y momentum
- 2.3.2 Reversión a la media: RSI y Bollinger, reversión intradía y huecos
- 2.3.3 Pairs trading y arbitraje estadístico: distancia, cointegración y Kalman
- 2.3.4 Carry en divisas, futuros y bonos; estacionalidad y efectos calendario
- 2.3.5 Factores (value, calidad, baja volatilidad, tamaño) y estrategias de eventos
- 2.3.6 Introducción al market making: inventario, spread y selección adversa (Avellaneda-Stoikov)
- 2.3.7 Estrategias específicas de cripto: momentum, arbitraje de funding y basis
2.4 · Backtesting: motores y paradigmas
- 2.4.1 Backtest vectorizado desde cero: matrices, desfase, costes y límites
- 2.4.2 Backtest por eventos desde cero: bucle, cartera, órdenes y fills
- 2.4.3 vectorbt: barridos masivos de parámetros y simulación de carteras
- 2.4.4 backtesting.py y backtrader: dos motores didácticos y su estado
- 2.4.5 NautilusTrader: arquitectura, datos, estrategias y el mismo código en backtest y en real
- 2.4.6 LEAN/QuantConnect y Zipline Reloaded; bt para asignación de activos
- 2.4.7 Modelado de costes: comisiones, horquilla, impacto, financiación y préstamo de títulos
- 2.4.8 Modelado de fills: órdenes limitadas, cola, fills parciales, huecos y stops
2.5 · Sesgos y validación
- 2.5.1 Sesgos de backtest: anticipación, supervivencia, selección y narrativa
- 2.5.2 In-sample y out-of-sample: walk-forward anclado y móvil
- 2.5.3 Validación cruzada combinatoria purgada para estrategias
- 2.5.4 Deflated Sharpe Ratio y Probability of Backtest Overfitting (PBO)
- 2.5.5 Monte Carlo: remuestreo de trades, bootstrap de bloques y permutaciones de señales
- 2.5.6 Sensibilidad de parámetros: mesetas frente a picos, robustez entre activos y periodos
- 2.5.7 Datos sintéticos para pruebas de estrés: GBM, GARCH y bootstrapping
- 2.5.8 Checklist de «backtest honesto» antes de pasar a paper trading
2.6 · Métricas de rendimiento
Un mercado que no cierra y se mueve en bloque
El mercado cripto tiene tres rasgos que cambian cómo se diseña una estrategia (lecciones 1.2.6 y 1.3.5). No cierra: la «sesión» diaria es una convención (aquí, el cierre a las 00:00 UTC) y los fines de semana cuentan. Tiene derivados propios: el perpetuo, un futuro sin vencimiento que se ancla al contado con pagos periódicos de funding, y futuros con vencimiento cuyo precio se separa del contado en el basis. Y casi todas las monedas suben y bajan a la vez.
Fuente Mermaid
flowchart TB C[Mercado cripto] --> F[Factor común] C --> M[Momentum transv.] C --> D[Derivados] D --> P[Perpetuo: funding] D --> T[Futuro: basis] P --> K[Cash-and-carry] T --> K
import numpy as np
import pandas as pd
cd = pd.read_parquet("cripto2_diario.parquet")
P = cd.pivot(index="fecha", columns="moneda", values="cierre")
r = P.pct_change(fill_method=None)
resumen = pd.DataFrame({
"desde": P.apply(lambda s: s.first_valid_index()).dt.date,
"hasta": P.apply(lambda s: s.last_valid_index()).dt.date,
"vol_anual_pct": 100 * np.log1p(r).std() * np.sqrt(365),
})
print(resumen.round(0).sort_values("vol_anual_pct").to_string())
print("peor día de KJT y KLU:",
(100 * r[["KJT", "KLU"]].min()).round(1).to_dict()) desde hasta vol_anual_pct
moneda
KAL 2018-01-01 2025-12-31 67.0
KMV 2019-07-01 2025-12-31 73.0
KCX 2018-01-01 2025-12-31 74.0
KGN 2018-01-01 2025-12-31 75.0
KES 2018-01-01 2025-12-31 78.0
KFL 2018-01-01 2025-12-31 81.0
KNX 2020-09-15 2025-12-31 85.0
KRM 2018-01-01 2025-12-31 98.0
KHX 2018-01-01 2025-12-31 99.0
KBR 2018-01-01 2025-12-31 103.0
KIO 2018-01-01 2025-12-31 103.0
KLU 2018-01-01 2022-11-30 108.0
KDL 2018-01-01 2025-12-31 109.0
KOB 2021-03-01 2025-12-31 111.0
KJT 2018-01-01 2022-05-27 138.0
peor día de KJT y KLU: {'KJT': -61.7, 'KLU': -45.5}Doce monedas cotizan los ocho años; KMV, KNX y KOB empiezan más tarde, y KJT y KLU dejan de cotizar en
2022 tras perder el 99 % y el 90 % en pocos días (su peor día, −61,7 % y −45,5 %). La volatilidad anual va del 67 %
de KAL, la mayor y más líquida, al 138 % de KJT: entre tres y siete veces la de un índice de acciones. Un universo
que se construyera hoy con las monedas que existen no tendría ni KJT ni KLU.
El factor común
El mercado cripto se puede resumir en un índice equiponderado de las monedas que cotizan cada día. Una regresión de cada moneda sobre ese índice da su beta y su , la fracción de su varianza diaria que explica el factor común:
mercado = r.mean(axis=1)
filas = {}
for mon in r:
d = pd.concat([r[mon], mercado], axis=1).dropna()
b, a = np.polyfit(d.iloc[:, 1], d.iloc[:, 0], 1)
filas[mon] = {"beta": b, "r2": d.corr().iloc[0, 1] ** 2}
fc = pd.DataFrame(filas).T.sort_values("r2")
corr = r.corr().to_numpy()
media_corr = corr[np.triu_indices_from(corr, 1)].mean()
completas = r.dropna()
valores = np.linalg.eigvalsh(np.corrcoef(completas.T.to_numpy()))
print(f"correlación media: {media_corr:.2f}; primer componente: "
f"{valores[-1] / valores.sum():.0%} de la varianza")
fc.round(2).Tcorrelación media: 0.58; primer componente: 70% de la varianza
KJT KBR KHX KOB KIO KMV KES KFL KRM KCX KLU KDL KGN KNX KAL
beta 0.91 0.94 0.91 1.31 1.08 0.86 0.85 0.91 1.12 0.86 1.06 1.37 0.94 1.15 0.89
r2 0.40 0.40 0.42 0.54 0.54 0.59 0.59 0.62 0.63 0.67 0.71 0.75 0.75 0.77 0.84La correlación media entre pares es de 0,58 y el primer componente principal explica el 70 % de la varianza de las
quince. El frente al índice va del 0,40 de KJT y KBR al 0,84 de KAL: en la moneda grande, más de cuatro
quintas partes de lo que pasa cada día es el mercado entero; en las que tienen más volatilidad propia, menos de la
mitad. Las betas están entre 0,85 y 1,37. Para una estrategia, la consecuencia es directa: una cartera solo larga es,
sobre todo, una apuesta por el factor común, y la señal transversal solo se aísla con una cartera long-short.
Momentum transversal semanal
La hipótesis plantada es la de un momentum de corto plazo: las monedas que más han subido en las últimas cuatro semanas siguen haciéndolo un poco mejor que las demás la semana siguiente. Liu, Tsyvinski y Wu (2022) encuentran en datos reales que un modelo de tres factores (mercado, tamaño y momentum) explica la sección cruzada de rentabilidades de las cripto; Liu y Tsyvinski (2021) documentan un momentum de series temporales fuerte.
El calendario de la señal importa. La señal se calcula con el cierre del domingo (rentabilidad de 28 días hasta ese cierre) y la posición se toma al cierre del lunes, la sesión siguiente:
Fuente Mermaid
flowchart LR D[Cierre domingo] --> S[Señal 28 días] S --> L[Orden lunes] L --> H[7 días]
from scipy import stats
lunes = [i for i, f in enumerate(P.index)
if f.dayofweek == 0 and 29 <= i < len(P) - 8]
logp = np.log(P)
ic = {"al cierre del domingo": [], "al cierre del lunes": []}
for i in lunes:
senal = logp.iloc[i - 1] - logp.iloc[i - 29]
for clave, ent in [("al cierre del domingo", i - 1),
("al cierre del lunes", i)]:
fut = logp.iloc[ent + 7] - logp.iloc[ent]
ok = senal.notna() & fut.notna()
ic[clave].append(stats.spearmanr(senal[ok], fut[ok])[0])
ic = pd.DataFrame(ic)
pd.DataFrame({"ic_medio": ic.mean(),
"t": ic.mean() / ic.std() * np.sqrt(len(ic)),
"semanas_pos_pct": 100 * (ic > 0).mean()}).round(3) ic_medio t semanas_pos_pct
al cierre del domingo 0.068 4.820 59.223
al cierre del lunes 0.069 4.842 60.922El IC de rangos semanal es de +0,068 ejecutando al cierre del domingo (el de la señal) y de +0,069 al del lunes, con t de 4,8 en los dos casos: la señal plantada (IC esperado ≈ +0,05) se recupera con claridad, y es positiva en el 59 % al 61 % de las semanas. Que la ejecución al día siguiente no la empeore es una propiedad de esta señal concreta: el rendimiento plantado se reparte por igual en toda la semana, y la ventana del lunes al lunes también lo recoge casi entero. Una señal cuyo efecto se concentrara en las primeras horas no lo resistiría.
La cartera compra las cinco monedas de mayor señal y vende las cinco de menor, con el mismo peso, entra al cierre del lunes y se rehace cada semana. El coste es un supuesto de la lección: 10 puntos básicos por lado sobre el nominal negociado, entre comisión y deslizamiento, del orden de lo que paga un cliente minorista que toma liquidez en un exchange grande con monedas líquidas. Las posiciones vendidas se suponen en perpetuos, así que además pagarían o cobrarían funding, que aquí se ignora.
COSTE = 10 / 1e4
pesos = pd.DataFrame(0.0, index=P.index, columns=P.columns)
for i in lunes:
senal = (logp.iloc[i - 1] - logp.iloc[i - 29]).dropna()
orden = senal.rank()
w = (pd.Series(0.0, index=P.columns)
.add((orden > len(orden) - 5) / 5, fill_value=0)
.sub((orden <= 5) / 5, fill_value=0))
pesos.iloc[i + 1:i + 8] = w.to_numpy() # desde el martes
pesos = pesos.where(P.notna(), 0.0)
giro = pesos.diff().abs().sum(axis=1)
ls = (pesos * r.fillna(0)).sum(axis=1) - COSTE * giro
ls = ls[ls.index >= P.index[lunes[0] + 1]]
ew = mercado.reindex(ls.index)
def metricas(x):
eq = (1 + x).cumprod()
return pd.Series({
"rent_anual_pct": 100 * x.mean() * 365,
"vol_anual_pct": 100 * x.std() * np.sqrt(365),
"sharpe": x.mean() / x.std() * np.sqrt(365),
"max_dd_pct": 100 * (eq / eq.cummax() - 1).min(),
"beta": np.polyfit(ew, x, 1)[0]})
coste_anual = 100 * COSTE * giro[ls.index].mean() * 365
print(f"coste anual de comisiones: {coste_anual:.2f} %")
pd.DataFrame({"long_short_neto": metricas(ls),
"indice_equiponderado": metricas(ew)}).round(2)coste anual de comisiones: 5.80 %
long_short_neto indice_equiponderado
rent_anual_pct 46.89 30.46
vol_anual_pct 39.94 70.79
sharpe 1.17 0.43
max_dd_pct -41.45 -84.27
beta -0.05 1.00Neta de comisiones, la cartera rinde un 46,9 % anual con una volatilidad del 39,9 %: un Sharpe de 1,17 y una beta de −0,05 frente al índice, que es casi nula. Las comisiones, con un giro semanal alto, se llevan 5,8 puntos al año. El índice equiponderado rinde un 30,5 % con un Sharpe de 0,43 y una caída máxima del 84 %: esa es la prima del factor común de estos datos, no la de la señal.
El Sharpe de 1,17 no es una promesa para las cripto reales: es lo que da una señal plantada con un IC de 0,07 en quince monedas sintéticas. Lo útil es compararlo con lo plantado. Con una diferencia media de 1,96 entre las puntuaciones normales por rangos de las dos patas, el generador promete unos 70 puntos al año antes de costes, y la cartera gana unos 53 (46,9 más 5,8 de comisiones). Con una volatilidad del 40 % en ocho años, el error típico de la rentabilidad media anual es de unos 14 puntos: la diferencia es poco más de un error típico, compatible con el azar. Y la caída máxima del 41 %, en una cartera neutral al mercado, pide mirar los peores días:
peores = ls.nsmallest(3)
print((100 * peores).round(1).to_string())
d = peores.index[0]
aporte = (pesos.loc[d] * r.fillna(0).loc[d]).nsmallest(2)
print("peor día, por moneda (% del capital):",
(100 * aporte).round(1).to_dict())
m = aporte.index[0]
print(f"{m} ese día: {100 * r.loc[d, m]:+.0f} %, "
f"peso {pesos.loc[d, m]:.2f}")
eq = (1 + ls).cumprod()
dd = eq / eq.cummax() - 1
print("caída máxima:", eq[:dd.idxmin()].idxmax().date(), "a",
dd.idxmin().date(), f"({100 * dd.min():.1f} %)")fecha
2022-05-03 -16.5
2023-08-22 -10.6
2022-06-21 -10.0
peor día, por moneda (% del capital): {'KOB': -15.6, 'KES': -1.2}
KOB ese día: +78 %, peso -0.20
caída máxima: 2021-03-08 a 2022-06-26 (-41.4 %)El peor día es el 3 de mayo de 2022: KOB, que la cartera tenía vendida con un 20 % del capital, sube un 78 % y la
pata corta pierde un 15,6 % del capital en una sesión; el resto de las posiciones casi no cuenta. Los dos peores días
siguientes, de −10,6 % y −10,0 %, son de la misma magnitud, y la caída máxima, del 41,4 %, va del 8 de marzo de 2021 al
26 de junio de 2022. El generador recorta las innovaciones idiosincráticas a ±5 desviaciones típicas, y aun así, con
la volatilidad de estas monedas, quedan días de hasta el +84 % según el README de los datos. Es el riesgo propio de la
pata corta: una posición vendida en un activo pequeño y volátil puede perder en un día lo que la señal gana en meses.
Límites de peso por moneda, stops de la pata corta y ponderar por la inversa de la volatilidad son la respuesta
habitual, y todos cambian el resultado.
La figura enseña la curva de la cartera frente a la del índice, en escala logarítmica. La cartera sube con fuerza en 2018 y 2019, se aplana en 2020 y 2021, cae en la primera mitad de 2022 y vuelve a subir desde 2023. El índice, en cambio, pierde más de la mitad en 2018 y en 2022 y gana en los tramos alcistas: dos curvas casi independientes, como dice la beta.
El funding de los perpetuos
Un perpetuo no vence. Para que su precio no se aleje del contado, cada 8 horas los largos pagan a los cortos un
porcentaje del nominal, el funding, si el perpetuo cotiza por encima del índice, y al revés si cotiza por debajo
(lección 1.2.6). Cuando el mercado está eufórico y muchos quieren estar largos con apalancamiento, el funding sube.
cripto2_funding.parquet tiene la tasa de cada periodo de KAL, KBR y KCX:
fu = pd.read_parquet("cripto2_funding.parquet")
fu["fecha"] = fu["ts"].dt.tz_convert(None).dt.normalize()
diario = fu.groupby(["fecha", "moneda"])["tasa_funding"].sum().unstack()
anual = 100 * diario * 365 # % anual, sin capitalizar
tabla = pd.DataFrame({
"media_pct": anual.mean(),
"dias_negativo_pct": 100 * (diario < 0).mean(),
"peor_30d_pct": anual.rolling(30).mean().min(),
"mejor_30d_pct": anual.rolling(30).mean().max(),
})
r7 = np.log(P[anual.columns]).diff(7)
tabla["corr_con_r7"] = [anual[c].corr(r7[c]) for c in anual]
print(tabla.round(2))
print((anual.groupby(anual.index.year).mean()).round(1).T) media_pct dias_negativo_pct peor_30d_pct mejor_30d_pct corr_con_r7
moneda
KAL 11.52 35.63 -36.30 52.86 0.84
KBR 11.40 42.09 -36.93 63.70 0.89
KCX 14.04 34.60 -37.91 63.72 0.89
fecha 2018 2019 2020 2021 2022 2023 2024 2025
moneda
KAL 1.4 15.2 13.1 11.3 2.6 20.3 18.9 9.4
KBR 5.9 9.0 9.4 14.3 14.5 12.3 9.8 16.0
KCX 5.8 20.8 15.5 13.8 9.0 16.4 12.4 18.7El funding medio, anualizado sin capitalizar, es de un 11,4 % a un 14,0 %: de media, los largos pagan a los cortos
algo más que el 0,01 % por periodo de base. Pero no es estable. Entre el 35 % y el 42 % de los días es negativo; la
peor media de 30 días es de −36 % a −38 % anual, y la mejor, de +53 % a +64 %. La correlación con la rentabilidad de
los 7 días anteriores es de 0,84 a 0,89: sube tras las subidas, que es la fórmula plantada
( por periodo, más ruido). Por años, el de KAL va del 1,4 % de 2018 al 20,3 %
de 2023.
Cash-and-carry: cobrar el funding sin apostar por el precio
El cash-and-carry compra la moneda al contado y vende la misma cantidad en el perpetuo. Las dos patas se compensan: si el precio sube, gana el contado y pierde el perpetuo en la misma cuantía. Lo que queda es el funding que cobra la pata corta cuando es positivo (y paga cuando es negativo), menos los costes de entrar y salir de las dos patas.
Fuente Mermaid
flowchart TB K[Capital] --> S[Contado largo] K --> M[Margen del corto] M --> P[Perpetuo corto] P --> F[Cobra funding] S --> N[Precio neutro] P --> N
f_kal = diario["KAL"]
cobrado = f_kal.groupby(f_kal.index.year).sum() * 100
print("funding cobrado por el corto, % del nominal por año:")
print(cobrado.round(1).to_string())
# capital: 1 en contado + margen del perpetuo corto
# (1/3 del nominal: apalancamiento 3x)
rend_capital = f_kal.sum() / (1 + 1 / 3) / (len(f_kal) / 365)
print(f"rendimiento anual sobre el capital: {100 * rend_capital:.1f} %"
" (sin costes)")
subida_30d = (P["KAL"] / P["KAL"].rolling(30).min() - 1).max()
print(f"mayor subida de KAL en 30 días: {100 * subida_30d:.0f} %")funding cobrado por el corto, % del nominal por año:
fecha
2018 1.4
2019 15.2
2020 13.1
2021 11.3
2022 2.6
2023 20.3
2024 18.9
2025 9.4
rendimiento anual sobre el capital: 8.6 % (sin costes)
mayor subida de KAL en 30 días: 116 %El corto del perpetuo de KAL cobra entre un 1,4 % (2018) y un 20,3 % (2023) del nominal cada año, y ningún año
negativo. Pero el capital necesario no es solo el nominal del contado: el perpetuo corto necesita margen. Con un
apalancamiento de 3x en esa pata (un tercio del nominal), el rendimiento sobre el capital baja al 8,6 % anual, sin
costes. Y la última línea es el riesgo: KAL llegó a subir un 116 % en 30 días. Con un margen de un tercio del
nominal, una subida así se lo come varias veces; hay que reponerlo a tiempo, vendiendo parte del contado o con
efectivo, o el exchange liquida la pata corta.
El basis de los futuros con vencimiento
El futuro trimestral vence en una fecha fija y converge al contado al vencer. Su diferencia con el contado, anualizada, es el basis: . Comprar el contado y vender el futuro fija ese basis al abrir: al vencimiento las dos patas valen lo mismo y el resultado es la diferencia inicial, pase lo que pase con el precio. En los datos, el basis se forma a partir del funding: alrededor de 0,8 veces el funding anualizado de 7 días más un 2 %.
ba = pd.read_parquet("cripto2_basis.parquet")
f7 = (diario.rolling(7).mean() * 365).stack().rename("funding_7d")
f7.index.names = ["fecha", "moneda"]
ba = ba.join(f7, on=["fecha", "moneda"]).dropna()
for mon, g in ba.groupby("moneda"):
b, a = np.polyfit(g["funding_7d"], g["basis_anual"], 1)
print(f"{mon}: basis = {a:.3f} + {b:.2f} × funding_7d,"
f" corr {g['basis_anual'].corr(g['funding_7d']):.2f}")
# un cash-and-carry por contrato: se abre a 80-90 días del vencimiento
entrada = ba[ba["dias_al_vencimiento"].between(80, 90)]
entrada = entrada.groupby(["moneda", "contrato"]).first()
fijado = 100 * entrada["basis_anual"]
print("\nbasis fijado al abrir (% anual) por moneda:")
print(fijado.groupby("moneda").describe()[
["count", "mean", "min", "max"]].round(1))KAL: basis = 0.025 + 0.80 × funding_7d, corr 0.97
KBR: basis = 0.012 + 0.80 × funding_7d, corr 0.99
KCX: basis = 0.012 + 0.81 × funding_7d, corr 0.97
basis fijado al abrir (% anual) por moneda:
count mean min max
moneda
KAL 33.0 17.1 -25.9 58.6
KBR 33.0 8.1 -49.0 74.2
KCX 33.0 15.2 -30.0 84.4La regresión recupera la relación plantada: una pendiente de 0,80 a 0,81 sobre el funding de 7 días y una
correlación de 0,97 a 0,99. La ordenada sale entre 1,2 % y 2,5 % (verdad 2 %). Para el cash-and-carry con futuro, lo
importante es la segunda tabla: abriendo a 80-90 días del vencimiento, el basis fijado medio es del 17,1 % anual en
KAL, del 8,1 % en KBR y del 15,2 % en KCX. El mínimo es negativo en las tres: en los trimestres de pánico el
futuro cotiza por debajo del contado, y el cash-and-carry habría que hacerlo al revés (vender contado y comprar
futuro), lo que exige tomar prestada la moneda. A diferencia del perpetuo, el basis se fija al abrir: si el contado y
el futuro se compran y venden a esos precios, el resultado al vencimiento es ese basis, haga lo que haga el funding
mientras tanto.
Costes, comisiones y lo que el backtest no ve
- Comisiones por lado. Las comisiones de los exchanges dependen del volumen del cliente y de si pone o toma liquidez; un long-short semanal paga cuatro lados por moneda y semana. El supuesto de 10 puntos básicos de la lección se lleva varios puntos al año.
- Fin de semana y horarios. No hay cierre oficial: el precio de «cierre» es el que elige el proveedor (lección 1.3.5). Dos fuentes con horas de corte distintas dan señales distintas.
- Colapsos.
KJTyKLUpierden el 99 % y el 90 % en pocos días y dejan de cotizar. Un universo construido con las monedas de hoy los borra (lección 1.4.4); uno point-in-time los incluye, y una cartera larga en ellas los paga. - Liquidaciones y apalancamiento. Los derivados cripto se negocian con margen y liquidación automática; una mecha de pocos minutos puede cerrar una posición que en datos diarios nunca estuvo en peligro.
- Contraparte. El dinero está en el exchange. La diversificación entre exchanges y la retirada periódica de beneficios son parte de la gestión del riesgo, no un detalle operativo.
Ejercicios
- Repite el IC de rangos semanal (ejecución al cierre del lunes) con ventanas de 7, 14, 28 y 56 días para la señal. ¿Cuál da el mejor IC? ¿Qué te dice el resultado sobre buscar la ventana óptima?
Solución
def ic_ventana(n):
v = []
for i in lunes:
if i - 1 - n < 0:
continue
senal = logp.iloc[i - 1] - logp.iloc[i - 1 - n]
fut = logp.iloc[i + 7] - logp.iloc[i]
ok = senal.notna() & fut.notna()
v.append(stats.spearmanr(senal[ok], fut[ok])[0])
v = np.array(v)
return v.mean(), v.mean() / v.std() * np.sqrt(len(v))
pd.DataFrame({n: ic_ventana(n) for n in [7, 14, 28, 56]},
index=["ic_medio", "t"]).T.round(3) ic_medio t
7 0.034 2.414
14 0.057 3.893
28 0.069 4.847
56 0.069 4.597La ventana de 28 días, la plantada, da el t más alto (4,85), pero la de 56 días empata con ella en IC medio (+0,069, t = 4,60): se solapan, y la de 56 días contiene entera la ventana plantada. La de 14 días queda en +0,057 y la de 7, en +0,034. Sin conocer la verdad, nadie sabría con estos números si la ventana buena es la de 28 o la de 56 días. En datos reales no hay una ventana «verdadera» conocida: probar varias y quedarse con la mejor es una prueba múltiple (lección 2.1.8), y el IC de la ganadora estará inflado. Aquí la diferencia entre las dos mejores es ruido.
- Un cash-and-carry condicional solo mantiene la posición cuando el funding medio de los últimos 7 días, anualizado,
supera el 5 %, y paga 10 puntos básicos por lado en cada pata al entrar y al salir. Calcula su resultado anual en
KALfrente al de mantenerla siempre.
Solución
f7_kal = diario["KAL"].rolling(7).mean() * 365
dentro = (f7_kal > 0.05).shift(1, fill_value=False) # decide ayer
cambios = dentro.astype(int).diff().abs().fillna(0)
coste = cambios * 2 * 2 * 10 / 1e4 # 2 patas × entrar o salir
anos = len(f_kal) / 365
siempre = f_kal.sum() / anos
condicional = ((f_kal * dentro).sum() - coste.sum()) / anos
print(f"siempre dentro: {100 * siempre:.1f} % anual del nominal")
print(f"condicional: {100 * condicional:.1f} % anual "
f"({int(cambios.sum())} entradas y salidas, "
f"{100 * dentro.mean():.0f} % del tiempo dentro)")siempre dentro: 11.5 % anual del nominal
condicional: 4.7 % anual (183 entradas y salidas, 60 % del tiempo dentro)Mantener siempre el cash-and-carry rinde un 11,5 % anual del nominal; la versión condicional, solo un 4,7 %. Está dentro el 60 % del tiempo, pero entra y sale 183 veces en ocho años, y cada cambio paga cuatro lados de 10 puntos básicos: unos 9 puntos al año de costes. Además, el funding es persistente pero ruidoso, y una regla con un umbral fijo entra justo después de las subidas y sale justo después de las caídas. Una regla con banda (entrar por encima de un nivel y salir por debajo de otro más bajo) reduciría los cambios.
- El backtest del cash-and-carry de
KALcobra funding neto todos los años. Enumera lo que tendría que pasar en un exchange real para que perdiera dinero, aunque el funding fuera el de los datos.
Solución
Que una subida rápida del precio consumiera el margen del perpetuo corto y el exchange lo liquidara antes de reponerlo: la cobertura desaparecería y el contado quedaría sin cubrir, o se vendería con pérdidas para pagar. Que los costes reales (comisiones, horquilla al entrar y salir, deslizamiento en las liquidaciones) fueran mayores que los supuestos. Que el perpetuo cotizara durante días con una prima o un descuento grande frente al índice, de forma que la pata corta no compensara exactamente al contado. Que el exchange congelara las retiradas o quebrara con el contado y el margen dentro. Y que el funding de los datos no fuera el que paga ese exchange: cada uno calcula el suyo con su propio índice y su propia fórmula.
Respuesta plegada en cada pregunta
Autoevaluación
La correlación media entre las quince monedas es de 0,58 y el primer componente principal explica el 70 % de la varianza. ¿Qué implica para una estrategia de momentum transversal?
- AQue no sirve para nada
- BQue basta con comprar las ganadoras
- CQue conviene apalancarla más
- DQue hay que construirla long-short: comprar unas y vender otras quita casi todo el factor común, que si no domina el resultado
Ver respuesta
Respuesta D. Que hay que construirla long-short: comprar unas y vender otras quita casi todo el factor común, que si no domina el resultado
Una cartera solo larga de las ganadoras es, sobre todo, una apuesta por el mercado cripto. La versión long-short equiponderada, con betas parecidas en las dos patas, aísla la parte transversal, que es donde está la señal plantada.
La señal de momentum se calcula con el cierre del domingo. ¿Por qué la lección ejecuta al cierre del lunes y no al del domingo?
- APorque los exchanges cierran el domingo
- BPorque la orden necesita el dato del cierre del domingo para calcularse; ejecutar a ese mismo precio supone operar en un instante que ya pasó
- CPorque el lunes hay más volumen
- DPor convención
Ver respuesta
Respuesta B. Porque la orden necesita el dato del cierre del domingo para calcularse; ejecutar a ese mismo precio supone operar en un instante que ya pasó
Es el mismo principio de todo el nivel: el dato de un cierre sirve para actuar después de ese cierre. En cripto, que no tiene subasta ni cierre oficial, el «cierre» es una hora convenida (00:00 UTC aquí) y entre el cálculo y la orden siempre pasa algo de tiempo.
Un perpetuo paga un funding de 0,01 % cada 8 horas. ¿Cuál es su equivalente anual aproximado?
- A0,01 %
- B3,65 %
- CUnos 11 %
- DUnos 33 %
Ver respuesta
Respuesta C. Unos 11 %
Tres pagos al día durante 365 días: 0,0001 × 3 × 365 ≈ 0,1095, un 11 % anual sin capitalizar. Es el orden de magnitud del funding medio de las tres monedas de la lección (del 11,4 % al 14,0 %).
¿Qué diferencia un cash-and-carry con futuro trimestral de uno con perpetuo?
- ACon el futuro trimestral el carry queda fijado al abrir (el basis converge a cero al vencimiento); con el perpetuo se cobra el funding de cada periodo, que cambia y puede volverse negativo
- BNinguna
- CEl trimestral no tiene riesgo de contraparte
- DEl perpetuo no necesita margen
Ver respuesta
Respuesta A. Con el futuro trimestral el carry queda fijado al abrir (el basis converge a cero al vencimiento); con el perpetuo se cobra el funding de cada periodo, que cambia y puede volverse negativo
Comprar el contado y vender el futuro fija la diferencia de precio, que desaparece al vencimiento. El perpetuo no vence: el funding se recalcula cada 8 horas y en las caídas puede pasar a pagar el corto. En los dos casos hay margen, liquidaciones posibles y riesgo del exchange.
En los datos,
KJTpierde el 99 % en cinco días y deja de cotizar. ¿Qué error cometería un backtest que solo usa las monedas que existen hoy?- ANinguno
- BUn error de zona horaria
- CUn error de costes
- DSesgo de supervivencia: quitaría de la historia las monedas que se hundieron, y una estrategia larga en ellas parecería mejor de lo que fue
Ver respuesta
Respuesta D. Sesgo de supervivencia: quitaría de la historia las monedas que se hundieron, y una estrategia larga en ellas parecería mejor de lo que fue
Es el sesgo de la lección 1.4.4 en su versión más extrema. En cripto, los colapsos de monedas y de exchanges no son raros, y un universo construido con la lista actual los borra.
Ideas clave
- Las cripto comparten un factor común muy fuerte: correlación media de 0,58 y un primer componente que explica el 70 % de la varianza en los datos.
- El momentum transversal semanal plantado se recupera con un IC de rangos de +0,069 (t ≈ 4,8); el long-short neto de 10 pb por lado tiene un Sharpe de 1,17, pero una caída máxima del 41 % y un peor día de −16,5 % por una sola posición corta.
- El funding de un perpetuo, anualizado, está entre un 11 % y un 14 % de media en los datos, sube tras las subidas y puede ser negativo durante semanas.
- El cash-and-carry (contado largo, derivado corto) cobra el funding o el basis sin exposición neta al precio, pero exige margen en la pata corta y queda expuesto al exchange.
- El basis del futuro trimestral sigue al funding (≈ 0,8 × funding + 2 %) y fija el carry hasta el vencimiento.
- Colapsos de monedas, liquidaciones y quiebras de exchanges son riesgos que un backtest con precios limpios no ve.