

La mayoría de las estrategias de trading quedan espectaculares en un gráfico que alguien publicó en X.
Muy pocas sobreviven a veinte años de datos reales, costes de operación y un periodo para el que nunca fueron ajustadas.
Así que hice el experimento yo mismo. Backtesting en Python, mismas fechas, mismos costes, siete de las estrategias basadas en reglas más populares contra la más aburrida de todas: comprar y mantener (buy and hold). Primero sobre el S&P 500, después sobre Microsoft, Apple, Amazon, Alphabet, Nvidia e Intel.
Si estás:
Estos resultados valen cinco minutos.
Todos los tutoriales de trading te enseñan a programar un RSI o un cruce de medias móviles.
Casi ninguno te enseña qué pasa cuando lo comparas de forma justa.
El patrón habitual es este. Alguien elige una acción, un periodo con suerte, retoca los parámetros hasta que la curva queda bonita, ignora las comisiones y publica. La estrategia "le gana al mercado". Sobre el papel.
Luego entra dinero real y la ventaja desaparece.
El problema no es el indicador. Es la prueba.
Así que la pregunta del experimento era simple:
¿Alguna de estas estrategias le ganó al buy and hold sin asumir más riesgo?
Antes de escribir una sola línea de código, fijé las reglas. Ningún cambio después de ver resultados.
¿Por qué mensual? Porque la mayoría de quienes buscan "cómo hacer backtesting de una estrategia de trading" no son day traders. Tienen un trabajo. Una regla que revisas una vez al mes es una regla que de verdad puedes seguir.
Cada una es un clásico que encontrarás en cualquier libro de trading. Esto es lo que dice cada regla, en lenguaje llano.
1. Cruce de medias móviles (3/10). Comprado cuando la media de 3 meses está por encima de la de 10 meses. Es más o menos la versión mensual del famoso golden cross 50/200 días.
2. Régimen RSI (14). Comprado cuando el RSI de 14 periodos está por encima de 50. Fuera cuando el momentum cae por debajo de 50.
3. MACD (12/26/9). Comprado cuando la línea MACD está por encima de su línea de señal.
4. Reversión con Bandas de Bollinger (20, 2). Compra cuando el precio cierra por debajo de la banda inferior. Vende cuando vuelve a la banda media. La clásica regla de "comprar en la caída".
5. Ruptura de 12 meses. Compra cuando el precio cierra en un nuevo máximo de 12 meses. Sale cuando cierra por debajo del cierre más bajo de los 6 meses anteriores.
6. Momentum de 12 meses. Comprado si SPY ha subido en los últimos 12 meses. Si no, liquidez.
7. Filtro de tendencia de 10 meses. Comprado cuando el precio está por encima de su media móvil de 10 meses. Es el equivalente mensual del filtro de la media de 200 días.
Y el benchmark: buy and hold. Comprar una vez en 2007. No volver a tocarlo nunca.
Un backtest es tan bueno como sus precios.
Si tus datos no ajustan por dividendos, el buy and hold parece peor de lo que es (SPY paga aproximadamente un 1,5% al año). Si los splits no se gestionan, tus señales saltan con caídas falsas. Ya escribí sobre por qué las fuentes gratuitas de datos históricos se rompen una y otra vez, y es lo primero que arruina un backtest.
Para esta prueba usé la API de fin de día de EODHD. Una sola petición te da décadas de velas mensuales, semanales o diarias con un campo adjusted_close ya calculado. Si nunca la has usado, mi guía de datos bursátiles de fin de día en Python explica la configuración.
Usa los mismos datos que usé yo Precios ajustados por dividendos para más de 150.000 tickers y más de 30 años de historia. 10% de descuento con el código KEVIN10. → Prueba EODHD aquí
Sin librería de backtesting. Solo pandas y numpy, para que veas cada supuesto.
Si prefieres una introducción más lenta y paso a paso, empieza por cómo hacer backtesting de una estrategia de trading con Python y EODHD. Este script va más allá: siete estrategias, siete tickers, un solo motor. Para probar tu propia lista, solo edita TICKERS.
pip install pandas numpy requests matplotlib
import requests
import numpy as np
import pandas as pd
API_KEY = "YOUR_EODHD_API_KEY"
COST = 0.001 # 0.1% per position change
def load_prices(ticker="SPY.US", start="2005-01-01", end="2026-09-30"):
url = f"https://eodhd.com/api/eod/{ticker}"
params = {"api_token": API_KEY, "period": "m", "fmt": "json",
"from": start, "to": end}
r = requests.get(url, params=params, timeout=30)
r.raise_for_status()
df = pd.DataFrame(r.json())
df.index = pd.to_datetime(df["date"]) + pd.offsets.MonthEnd(0)
return df["adjusted_close"].astype(float)
def rsi(s, n=14):
d = s.diff()
up = d.clip(lower=0).ewm(alpha=1 / n, adjust=False).mean()
dn = (-d.clip(upper=0)).ewm(alpha=1 / n, adjust=False).mean()
return 100 - 100 / (1 + up / dn)
def stateful(entry, exit_):
# Holds a position from an entry signal until an exit signal
pos, out = 0, []
for e, x in zip(entry, exit_):
if pos == 0 and e:
pos = 1
elif pos == 1 and x:
pos = 0
out.append(pos)
return pd.Series(out, index=entry.index)
def signals(c):
s = {"Buy & Hold": pd.Series(1, index=c.index)}
s["SMA Crossover (3/10)"] = (c.rolling(3).mean() > c.rolling(10).mean()).astype(int)
s["RSI(14) > 50"] = (rsi(c) > 50).astype(int)
macd = c.ewm(span=12, adjust=False).mean() - c.ewm(span=26, adjust=False).mean()
s["MACD (12/26/9)"] = (macd > macd.ewm(span=9, adjust=False).mean()).astype(int)
mid, sd = c.rolling(20).mean(), c.rolling(20).std()
s["Bollinger Reversion (20,2)"] = stateful(c < mid - 2 * sd, c > mid)
s["12-Month Breakout"] = stateful(c >= c.rolling(12).max(),
c < c.shift(1).rolling(6).min())
s["12-Month Momentum"] = (c.pct_change(12) > 0).astype(int)
s["10-Month Trend Filter"] = (c > c.rolling(10).mean()).astype(int)
return s
def backtest(c, sig, start, end):
ret = c.pct_change()
pos = sig.shift(1).fillna(0) # trade on the NEXT bar
pos, ret = pos[start:end], ret[start:end]
trades = pos.diff().abs().fillna(pos.iloc[0])
strat = pos * ret - trades * COST
equity = (1 + strat).cumprod()
years = len(strat) / 12
vol = strat.std() * np.sqrt(12)
return {
"CAGR %": (equity.iloc[-1] ** (1 / years) - 1) * 100,
"Max DD %": (equity / equity.cummax() - 1).min() * 100,
"Sharpe": strat.mean() * 12 / vol if vol > 0 else 0.0, # a rule that never trades has zero volatility
"Trades": int(trades.sum()),
"Exposure %": pos.mean() * 100,
}
TICKERS = ["SPY.US", "MSFT.US", "AAPL.US", "AMZN.US", "GOOGL.US", "NVDA.US", "INTC.US"]
periods = {"Full": ("2007-01", "2026-09"),
"In-sample": ("2007-01", "2019-12"),
"Holdout": ("2020-01", "2026-09")}
rows = []
for ticker in TICKERS:
close = load_prices(ticker)
for strat_name, sig in signals(close).items():
for period, (a, b) in periods.items():
rows.append({"Ticker": ticker, "Strategy": strat_name, "Period": period,
**backtest(close, sig, a, b)})
results = pd.DataFrame(rows)
results.to_csv("backtest_results.csv", index=False)
for (ticker, period), table in results.groupby(["Ticker", "Period"], sort=False):
print(f"\n=== {ticker} | {period} ===")
print(table.set_index("Strategy").drop(columns=["Ticker", "Period"]).round(2).to_string())
Dos líneas de ese script importan más que todos los indicadores juntos.
sig.shift(1) significa que cada decisión usa solo la información disponible en ese momento. Quítala y estarás operando con el periódico de mañana.
trades * COST significa que cada cambio cuesta dinero. Quítala y las estrategias que más operan parecerán las mejores.
Ahí es donde mienten la mayoría de los backtests.
Este es el periodo completo, de enero de 2007 a septiembre de 2026. Capital inicial de $10.000.
| Estrategia | CAGR | Drawdown máximo | Sharpe | Operaciones | Tiempo en mercado | Valor final |
|---|---|---|---|---|---|---|
| Buy & Hold | 10,90% | -50,8% | 0,75 | 1 | 100% | $77.116 |
| Momentum 12 meses | 9,72% | -19,5% | 0,83 | 15 | 84% | $62.454 |
| Cruce de medias (3/10) | 8,98% | -19,7% | 0,80 | 19 | 79% | $54.626 |
| MACD (12/26/9) | 8,25% | -19,5% | 0,79 | 15 | 70% | $47.822 |
| Filtro de tendencia 10 meses | 8,00% | -23,4% | 0,77 | 33 | 79% | $45.731 |
| RSI(14) > 50 | 7,20% | -36,4% | 0,62 | 21 | 88% | $39.445 |
| Ruptura 12 meses | 6,70% | -22,9% | 0,65 | 19 | 74% | $36.003 |
| Reversión Bollinger (20,2) | 0,45% | -35,8% | 0,10 | 4 | 8% | $10.922 |
Operaciones = número de cambios de posición (entradas más salidas). Sharpe calculado sin tasa libre de riesgo.
La respuesta corta a la pregunta inicial:
Ninguna estrategia le ganó al buy and hold en rentabilidad total.
Ni una.
Pero eso es solo la mitad de la historia. Mira la columna del drawdown.
El buy and hold perdió más de la mitad de su valor entre 2007 y 2009. Cuatro estrategias (momentum, cruce de medias, MACD y el filtro de tendencia) nunca cayeron más de un 23% aproximadamente. Y las cuatro tuvieron un ratio de Sharpe mejor que el buy and hold en el periodo completo.
Así que podrías decir que ganaron en términos ajustados por riesgo.
Luego revisé el holdout.

Los años in-sample (2007 a 2019) fueron amables con el seguimiento de tendencia. El crash de 2008 fue largo y lento, justo el tipo de caída que una regla de tendencia mensual está diseñada para esquivar.
| Estrategia | CAGR 2007–2019 | Sharpe 2007–2019 | CAGR 2020–2026 | Sharpe 2020–2026 |
|---|---|---|---|---|
| Buy & Hold | 8,70% | 0,65 | 15,23% | 0,93 |
| Momentum 12 meses | 8,18% | 0,77 | 12,74% | 0,92 |
| Cruce de medias (3/10) | 8,33% | 0,84 | 10,22% | 0,77 |
| MACD (12/26/9) | 7,72% | 0,84 | 9,25% | 0,75 |
| Filtro de tendencia 10 meses | 7,54% | 0,79 | 8,89% | 0,76 |
En el periodo que las estrategias nunca habían "visto", el buy and hold ganó en rentabilidad y en ratio de Sharpe. El momentum fue el que más se acercó, prácticamente empatado en términos ajustados por riesgo, pero aun así unos 2,5 puntos al año por detrás.
¿Por qué? Porque 2020 fue lo contrario de 2008.
El crash del COVID duró alrededor de un mes. La recuperación, unos pocos más. Una regla de tendencia mensual vende cuando el daño ya está hecho y vuelve a comprar cuando el rebote ya ha empezado. Pagas el seguro y el seguro no paga.
La curva de capital lo muestra con claridad. La estrategia de momentum iba por delante del buy and hold al cierre de cada año entre 2008 y 2018. Once años por delante.
Luego el buy and hold la adelantó en 2019 y no volvió a mirar atrás.
Once años buenos pueden acabar igualmente en segundo lugar.
SPY es un solo activo. Un solo activo no demuestra nada.
Así que ejecuté exactamente el mismo script, sin cambiar ni un parámetro, sobre seis de las acciones más populares de las dos últimas décadas: Microsoft, Apple, Amazon, Alphabet, Nvidia e Intel. Son 42 combinaciones más de estrategia y acción.

Periodo completo, de enero de 2007 a septiembre de 2026. Para cada ticker, el buy and hold frente a la regla con mayor rentabilidad:
| Ticker | CAGR Buy & Hold | DD máx. Buy & Hold | Mejor regla | CAGR mejor regla | DD máx. mejor regla |
|---|---|---|---|---|---|
| SPY | 10,9% | -51% | Momentum 12 meses | 9,7% | -20% |
| MSFT | 17,6% | -55% | Filtro de tendencia 10 meses | 12,3% | -34% |
| AAPL | 28,0% | -57% | RSI(14) > 50 | 24,1% | -43% |
| AMZN | 27,8% | -54% | Momentum 12 meses | 25,0% | -35% |
| GOOGL | 18,8% | -59% | Filtro de tendencia 10 meses | 14,6% | -27% |
| NVDA | 35,5% | -79% | Filtro de tendencia 10 meses | 37,4% | -43% |
| INTC | 12,3% | -67% | Cruce de medias (3/10) | 11,1% | -39% |
Tres cosas saltaron a la vista.
1. El buy and hold ganó casi en todas partes. De 42 combinaciones de acción y estrategia, exactamente una lo superó en rentabilidad: Nvidia con el filtro de tendencia de 10 meses. Un 37,4% anual frente a un 35,5%, recortando además el peor drawdown del -79% al -43%.
2. La ventaja ajustada por riesgo casi desapareció. En SPY, cuatro reglas tuvieron mejor ratio de Sharpe que el buy and hold. En las seis acciones, solo una de 42 lo consiguió (esa misma combinación de Nvidia). Las acciones individuales tienen más ruido que un índice. Más señales falsas, más whipsaws, más costes.
3. Intel fue la excepción en el holdout. De 2020 a 2026, la única acción en la que alguna regla superó al buy and hold en rentabilidad fue Intel. Cinco de las siete reglas lo hicieron. El cruce de medias ganó un 20,6% anual frente al 13,0% del buy and hold.
Intel es la acción que se rompió. En su peor momento de este periodo perdió dos tercios de su valor. Las reglas de tendencia te sacaron a tiempo.
Esa es la verdadera lección escondida en esta tabla.
En 2007 nadie sabía que Nvidia multiplicaría su valor casi por 500 ni que Intel tropezaría durante años. Si tienes la próxima Nvidia, las reglas de timing te cuestan dinero. Si tienes la próxima Intel, te salvan. Simplemente no sabes cuál tienes hasta que es demasiado tarde.
Pros
Contras
Ideal para: inversores que prefieren ganar algo menos antes que vivir una caída del 50%. Construí una app completa alrededor de esta idea en este proyecto de trading por momentum con Claude Code y EODHD.
Ambas se comportaron casi como el momentum. Drawdowns menores, rentabilidades algo menores, ratios de Sharpe en torno a 0,80.
Son tres formas de hacer la misma pregunta: ¿la tendencia es alcista?
Vale la pena saberlo antes de pasar un fin de semana comparando indicadores que miden lo mismo.
La famosa regla de "quédate por encima de la media de 200 días" hizo 33 operaciones, más que ninguna otra estrategia. Cada vez que SPY rondaba su media, entraba y salía.
Cada cambio costaba un 0,1% más el movimiento que se perdía.
Esta me sorprendió. En el periodo 2020–2026, el drawdown máximo de la regla RSI fue del -36,4%, más profundo que el -23,9% del buy and hold. Vendía cerca de los mínimos y volvía a comprar cerca de los máximos.
Ideal para: nada, al menos con velas mensuales de SPY.
Esperar a un nuevo máximo de 12 meses significa que siempre compras después de una gran subida. Salir en un mínimo de 6 meses significa que siempre vendes después de una gran caída. Capturó el centro de las tendencias y pagó por ambos extremos.
Comprar cuando el precio cae por debajo de la banda inferior suena a "comprar barato". En 2008 significó comprar un mercado en caída y aguantarlo otro 35% hacia abajo.
Estuvo en el mercado solo el 8% del tiempo y convirtió $10.000 en $10.922 después de casi 20 años.
La lección: la reversión a la media y el seguimiento de tendencia son apuestas opuestas. En un índice amplio y con velas mensuales, ganó la tendencia.
Un buen backtest te dice sus propios límites. Estos son los míos.
Y si vas a medir tus propios resultados, asegúrate de calcular bien la rentabilidad. CAGR, rentabilidad total y rentabilidad media cuentan tres historias distintas.
El análisis técnico no fracasó aquí. Hizo exactamente lo que promete: reducir el riesgo.
Simplemente no te hizo más rico.
Si de verdad puedes aguantar un drawdown del 50%, el buy and hold es muy difícil de batir. Si no puedes, una regla simple de momentum podría ser el precio que vale la pena pagar para seguir invertido.
En cualquier caso, la única forma de saberlo es hacer backtesting en Python con reglas honestas, costes reales y un periodo para el que no ajustaste nada. El código de arriba te da las tres cosas.
Ejecuta este backtest con cualquier ticker Cambia
SPY.USpor cualquier acción, ETF o índice. Precios ajustados incluidos. 10% de descuento con el código KEVIN10. → Consigue tu API key de EODHD
Más experimentos como este Python, APIs de datos financieros y herramientas de IA, probados con números reales. → Visita kevinmeneses.com
❓ ¿Qué es el backtesting en Python? ✅ Hacer backtesting en Python significa ejecutar una regla de trading sobre precios históricos para ver cómo habría funcionado. Cargas los datos de precios con pandas, generas señales de compra y venta, las desplazas una vela para evitar el sesgo de look-ahead y calculas la rentabilidad después de costes. No predice el futuro, pero filtra las ideas que nunca funcionaron.
❓ ¿Cómo se hace backtesting de una estrategia de trading? ✅ Define las reglas antes de mirar resultados, consigue precios ajustados por dividendos, aplica las señales con una vela de retraso, resta los costes de operación y compara con el buy and hold. Después prueba en un periodo holdout que no usaste para construir la estrategia. Si solo funciona in-sample, no funciona.
❓ ¿Funciona realmente el análisis técnico? ✅ En esta prueba, los indicadores de seguimiento de tendencia como el momentum, las medias móviles y el MACD redujeron el drawdown máximo de alrededor del -51% a alrededor del -20%. Ninguno superó al buy and hold en rentabilidad total después de costes. Funcionó como gestión del riesgo, no como forma de batir al S&P 500.
❓ ¿Es mejor el buy and hold que hacer trading? ✅ En SPY de 2007 a 2026, el buy and hold tuvo la mayor rentabilidad (10,9% anual) de los ocho enfoques probados, y también ganó en Microsoft, Apple, Amazon, Alphabet e Intel. Las reglas de trading redujeron el riesgo, pero también la rentabilidad. El buy and hold además paga menos comisiones y difiere impuestos, algo que este backtest ni siquiera cuenta.
❓ ¿Funcionan mejor las estrategias de trading en acciones individuales? ✅ No en esta prueba. Entre Microsoft, Apple, Amazon, Alphabet, Nvidia e Intel, solo una de 42 combinaciones de estrategia y acción superó al buy and hold en rentabilidad a 20 años. Las reglas sí recortaron los drawdowns, y ayudaron sobre todo en la acción que se desplomó (Intel), que es justo el caso que no puedes predecir de antemano.
❓ ¿Cuál es la mejor librería de backtesting en Python? ✅ Backtesting.py, Backtrader y vectorbt son las más populares. Para un primer proyecto, pandas a secas como en el código de arriba suele ser mejor, porque cada supuesto queda a la vista. Cuando entiendas la mecánica, una librería te ahorra tiempo en la lógica de cartera y los informes.
❓ ¿Qué estrategia de trading tuvo los mejores resultados en el backtest? ✅ La regla de momentum de 12 meses tuvo el mejor resultado ajustado por riesgo: un ratio de Sharpe de 0,83, un drawdown máximo del -19,5% y solo 15 operaciones en casi 20 años. Aun así terminó con $62.454 frente a los $77.116 del buy and hold partiendo de $10.000.
Este artículo tiene fines exclusivamente educativos y no constituye asesoramiento financiero. Las rentabilidades pasadas no garantizan rentabilidades futuras.
¿Buscas contenido técnico para tu empresa? Puedo ayudarte — LinkedIn · kevinmenesesgonzalez@gmail.com