---
title: "6.4.4 Evidencia y límites de los agentes de trading"
description: "LiveTradeBench, AlphaForgeBench y AlphaCrafter leídos en su fuente y un banco de agentes simulado: rankings que no predicen, ejecuciones que no se repiten."
url: "https://pythonparatrading.com/curso-python-trading/nivel-6/evidencia-y-limites-de-los-agentes-de-trading/"
lang: "es"
image: "https://pythonparatrading.com/og/curso-python-trading/nivel-6/evidencia-y-limites-de-los-agentes-de-trading.png"
---

# 6.4.4 · Evidencia y límites de los agentes

> ¿Opera mejor el modelo que gana los rankings generales? ¿Repite sus decisiones si se le pregunta dos veces? ¿Aguanta en real lo que brilla en el backtest? Esta lección lee tres estudios recientes con sus cifras exactas, mide cuánto se puede concluir de 21 modelos y 50 sesiones, y reproduce los tres problemas con agentes simulados sobre los datos del curso y con el modelo local de 0,5B.

- Curso: [Nivel 6: IA generativa, LLMs, agentes, big data y datos alternativos](https://pythonparatrading.com/curso-python-trading/nivel-6/)
- Módulo: 6.4 · Agentes de IA para trading
- Duración: 70 min
- Requisitos: [6.4.3 · Arquitecturas multiagente tipo TradingAgents](https://pythonparatrading.com/curso-python-trading/nivel-6/arquitecturas-multiagente-tipo-tradingagents/), [6.2.5 · Sesgo de anticipación en LLMs: el modelo que ya conoce el futuro](https://pythonparatrading.com/curso-python-trading/nivel-6/sesgo-de-anticipacion-en-llms/), [6.2.1 · Cómo funciona un LLM: del siguiente token a la API](https://pythonparatrading.com/curso-python-trading/nivel-6/como-funcionan-los-llm-apis-y-modelos-locales/), [5.8.4 · Modelos fundacionales en finanzas: qué dice la evidencia](https://pythonparatrading.com/curso-python-trading/nivel-5/evidencia-de-los-modelos-fundacionales-en-finanzas/), [2.5.4 · Deflated Sharpe Ratio y Probability of Backtest Overfitting (PBO)](https://pythonparatrading.com/curso-python-trading/nivel-2/deflated-sharpe-ratio-y-pbo/)

## Al terminar esta lección

- Resumir con cifras verificadas LiveTradeBench (21 LLM, 50 días en vivo, correlaciones de Spearman de 0,054 y −0,38), AlphaForgeBench (inestabilidad entre ejecuciones con decodificación determinista) y la degradación de backtest a real documentada en AlphaCrafter.
- Calcular el intervalo de confianza de una correlación de rangos con 21 modelos y el error típico de un Sharpe medido en unas 70 sesiones.
- Simular un banco de agentes sobre los datos del curso y comprobar que la correlación entre una puntuación general y la rentabilidad de 50 sesiones es casi ruido, aunque la capacidad ayude a largo plazo.
- Medir la variabilidad entre ejecuciones del mismo agente y compararla con la variabilidad entre agentes.
- Mostrar con un LLM local que un cambio de formato en el prompt invierte una decisión de compra o venta, y diseñar una evaluación honesta de un agente.

## Tres preguntas que un benchmark de agentes debe contestar

Las lecciones 6.4.1 a 6.4.3 construyeron agentes. Esta pregunta qué se sabe de su rendimiento cuando operan, y lo
hace con tres preguntas que cualquier estudio de agentes de trading debería contestar antes de enseñar una cifra:

1. **¿Predice la capacidad general la capacidad para invertir?** Si el modelo que gana los rankings de conversación
   también gana dinero, elegir modelo sería fácil.
2. **¿Se repite el resultado si se repite la ejecución?** Un sistema cuyas decisiones cambian de una ejecución a otra
   no tiene un rendimiento, tiene una distribución de rendimientos.
3. **¿Aguanta en real lo que brilla en el backtest?** Sin una prueba posterior al entrenamiento del modelo y al diseño
   de la estrategia, un backtest mide memoria y selección (lecciones 6.2.5 y 2.5.4).

Cada sección lee un estudio que contesta una de ellas, con las cifras tal como aparecen en el PDF (leídos el
2026-10-23), y después reproduce el problema en los datos del curso, donde la respuesta es conocida.

```mermaid
flowchart TB
  A[Agente] --> B[Tras el corte]
  B --> C[Varias ejecuciones]
  C --> D[Baselines y costes]
  D --> E[Muchas sesiones]
  E --> F[Conclusión]
```

## LiveTradeBench: el ranking general no ordena la rentabilidad

«LiveTradeBench: Seeking Real-World Alpha with Large Language Models», de Haofei Yu, Fenghai Li y Jiaxuan You
(Universidad de Illinois en Urbana-Champaign), arXiv:2511.03628, versión 1 del 5 de noviembre de 2025. El diseño
evita el backtest: los agentes reciben **en vivo** precios, noticias (titulares y resúmenes) y su cartera, y cada día
devuelven una asignación en porcentajes. Hay dos mercados: 15 acciones y ETF de EE. UU. y mercados de predicción de
Polymarket. Cada uno de los **21 LLM** (Claude, Grok, Qwen, Llama, GPT, Gemini, Kimi y DeepSeek: el texto habla de
«six representative model families» y la tabla tiene ocho) va dentro del mismo marco de agente, de tipo ReAct, con el
mismo prompt, y la evaluación dura **del 18 de agosto al 24 de octubre de 2025,
50 días de negociación** según el artículo (en el calendario de la NYSE de los datos del curso, entre esas dos fechas
hay 49 sesiones; la diferencia puede venir de cómo cuentan el primer día o del calendario de Polymarket, y no cambia
nada de lo que sigue).

Las cifras que cita el temario están en el artículo:

- «In the stock market, the Spearman correlation between LMArena scores and cumulative returns is only 0.054—virtually
  no relationship. In Polymarket, the correlation drops to –0.38». La figura siguiente las dibuja.
- GPT-4.1 «achieves the highest cumulative return rate (> 6%) in the stock market but performs poorly in Polymarket
  (return < −30%)». En la tabla 2: +6,25 % y −33,69 %.

*Fig. — LiveTradeBench: correlación entre la puntuación en LMArena y la rentabilidad de 21 LLM.* Dos barras con la correlación de Spearman entre la puntuación general de 21 modelos de lenguaje en LMArena y su rentabilidad acumulada en 50 sesiones en vivo: 0,054 en acciones, casi nula, y −0,38 en Polymarket, negativa.

Y el artículo dice más cosas que conviene leer junto a esas cifras. La correlación del Sharpe entre los dos mercados
«is close to zero»: el buen rendimiento en uno no implica nada en el otro. Los autores atribuyen la pérdida de GPT-4.1
en Polymarket a «overreactive allocation changes under higher volatility». En su sección de limitaciones reconocen que
el entorno no tiene en cuenta comisiones, horquillas ni liquidez, lo que puede sobrestimar el rendimiento de las
estrategias que rebalancean mucho. Los modelos de chat se llaman con temperatura 0,3 y cada uno se evalúa en
una sola trayectoria: una evaluación en vivo no se puede repetir. Y la tabla no incluye una cartera pasiva de referencia con los mismos 15 activos. La figura de la
cabecera pone los 21 modelos en los dos mercados a la vez: en acciones todos ganan, entre un 1,78 y un 6,25 %; en
Polymarket, 17 de 21 pierden.

```python
import numpy as np
import pandas as pd
from scipy import stats

# Tabla 2 de arXiv:2511.03628 v1: rentabilidad acumulada (%) y Sharpe
ltb = pd.DataFrame([
    ("Claude-Sonnet-3.7", 3.63, 1.45, 20.54, 2.38),
    ("Claude-Sonnet-4", 2.45, 0.72, -40.32, -2.40),
    ("Claude-Opus-4", 3.93, 1.72, -2.04, 0.09),
    ("Claude-Opus-4.1", 3.73, 1.51, -25.69, -3.02),
    ("Grok-3", 3.22, 1.26, -8.35, -0.55),
    ("Grok-4", 4.30, 1.75, 7.38, 1.01),
    ("Qwen2.5-72B", 5.15, 2.18, 1.63, 0.43),
    ("Qwen3-235B-Instruct", 3.52, 1.32, -54.24, -2.97),
    ("Qwen3-235B-Thinking", 1.78, 0.60, -57.62, -1.81),
    ("Llama3.3-70B", 2.72, 0.88, 1.58, 0.40),
    ("Llama4-Scout", 4.65, 1.99, -16.05, -1.18),
    ("Llama4-Maverick", 4.46, 1.65, -18.31, -1.92),
    ("GPT-4o", 3.55, 1.39, -30.96, -3.26),
    ("GPT-4.1", 6.25, 2.64, -33.69, -1.74),
    ("GPT-5", 5.31, 2.19, -23.96, -0.49),
    ("GPT-o3", 6.04, 2.57, -54.84, -3.68),
    ("Gemini-2.5-Flash", 2.10, 0.72, -22.40, -0.82),
    ("Gemini-2.5-Pro", 1.95, 0.61, -35.15, -1.65),
    ("Kimi-K2", 3.07, 1.15, -53.44, -5.26),
    ("DeepSeek-V3.1", 2.46, 0.86, -4.68, -0.07),
    ("DeepSeek-R1", 2.10, 0.78, -13.19, 0.14)],
    columns=["modelo", "cr_acc", "sr_acc", "cr_poly", "sr_poly"])
n = len(ltb)
print(n, "modelos | ganan en acciones:", (ltb.cr_acc > 0).sum(),
      "| ganan en Polymarket:", (ltb.cr_poly > 0).sum())
for a, b in [("cr_acc", "cr_poly"), ("sr_acc", "sr_poly")]:
    print(f"Spearman {a} vs {b}: "
          f"{stats.spearmanr(ltb[a], ltb[b])[0]:.2f}")

def ic_spearman(rho, n):
    """IC del 95 % (Fisher con el error de Fieller: 1,06/raíz(n-3))."""
    z, se = np.arctanh(rho), 1.06 / np.sqrt(n - 3)
    return np.tanh(z - 1.96 * se), np.tanh(z + 1.96 * se)

for rho in (0.054, -0.38):
    t = rho * np.sqrt((n - 2) / (1 - rho**2))
    p = 2 * stats.t.sf(abs(t), n - 2)
    lo, hi = ic_spearman(rho, n)
    print(f"rho = {rho:+.3f}: IC 95 % [{lo:+.2f}, {hi:+.2f}], "
          f"p = {p:.2f}")
```
```output
21 modelos | ganan en acciones: 21 | ganan en Polymarket: 4
Spearman cr_acc vs cr_poly: 0.17
Spearman sr_acc vs sr_poly: 0.06
rho = +0.054: IC 95 % [-0.41, +0.50], p = 0.82
rho = -0.380: IC 95 % [-0.71, +0.09], p = 0.09
```

Tres lecturas. Primera: la correlación entre mercados, calculada con la propia tabla, es pequeña tanto en rentabilidad
como en Sharpe, como dicen los autores. Segunda: con 21 modelos, el intervalo del 95 % de una correlación de rangos de
0,054 va de −0,41 a 0,50: **no** descarta una relación moderada en ninguno de los dos sentidos, y la de −0,38 en
Polymarket, con p = 0,09, tampoco es significativa al 5 %. La conclusión que sostienen los datos es la del resumen del
artículo, «high LMArena scores do not imply superior trading outcomes», no que la capacidad no importe. Tercera: que
los 21 ganen en acciones en 50 días dice más del mercado en esas semanas que de los modelos; sin una cartera pasiva
en la tabla no hay forma de separar beta de habilidad.

## La misma pregunta con respuesta conocida

Con datos reales nadie sabe cuánto ayuda de verdad la capacidad de un modelo. Con los datos del curso se puede fijar.
La celda monta un banco de 21 agentes simulados al estilo de LiveTradeBench: las **15 mayores empresas** del nivel 6,
una decisión al cierre de cada sesión con las noticias publicadas hasta las 16:00 de Nueva York y el rendimiento de 5
sesiones, y una asignación diaria entre las 15 acciones y la caja. Cada agente tiene:

- una **puntuación general** simulada (como la de LMArena), entre 1 300 y 1 450;
- una **calidad de lectura** de las noticias que **crece con la puntuación**: la capacidad ayuda de verdad, porque en
  los datos las noticias mueven el precio (el efecto plantado del README);
- un **apetito por el riesgo** (fracción en caja), una **agresividad** y un gusto por el momentum que no tienen nada
  que ver con la puntuación;
- un **ruido de inferencia**: cada decisión lee la evidencia con un error que cambia en cada ejecución.

```python
import re

emp = pd.read_csv("acciones6_empresas.csv")
hist = pd.read_csv("acciones6_tickers.csv")
ID = dict(zip(hist["ticker"], hist["id_empresa"]))
ACTUAL = dict(zip(emp["id_empresa"], emp["ticker"]))
px = pd.read_parquet("acciones6_precios.parquet")
cierres = px.pivot(index="fecha", columns="ticker", values="cierre")
acciones = emp.set_index("ticker")["acciones_millones"]
U = list((cierres.loc["2019-01-02"] * acciones).nlargest(15).index)
r = cierres[U].pct_change().loc["2019-01-02":]
F = r.index
R, R5 = r.to_numpy(), cierres[U].pct_change(5).loc[F].to_numpy()

lex = pd.read_csv("texto6_lexico.csv").query("lista == 'financiera'")
POS = set(lex.query("categoria == 'positiva'")["palabra"])
NEG = set(lex.query("categoria == 'negativa'")["palabra"])
def tono(t):
    pal = re.findall(r"\w+", t.lower())
    p, n_ = sum(w in POS for w in pal), sum(w in NEG for w in pal)
    return (p - n_) / (p + n_ + 1)
nt = pd.read_parquet("noticias6_corpus.parquet")
nt["tk"] = nt["ticker"].map(ID).map(ACTUAL)
nt = nt[nt["tk"].isin(U)]
nt["clave"] = nt["titular"].str.replace(
    r"^(?:ACTUALIZA|Última hora|UPDATE|Breaking):\s*", "",
    regex=True, case=False)
nt = nt.sort_values("ts").drop_duplicates(["tk", "clave"])
nt["tono"] = (nt["titular"] + " " + nt["cuerpo"]).map(tono)
ny = nt["ts"].dt.tz_convert("America/New_York").dt.tz_localize(None)
i = np.searchsorted(F + pd.Timedelta(hours=16), ny, side="left")
nt = nt[i < len(F)].assign(dia=F[i[i < len(F)]])
T = (nt.groupby(["dia", "tk"])["tono"].sum().unstack()
     .reindex(index=F, columns=U).fillna(0).to_numpy())

rng = np.random.default_rng(644)
NA = 21
puntuacion = np.round(1300 + 150 * rng.random(NA))
calidad = 0.2 + 0.6 * (puntuacion - 1300) / 150   # sube con la nota
caja = rng.uniform(0.0, 0.6, NA)                   # no depende de ella
kappa = rng.uniform(0.5, 3.0, NA)
gusto_mom = rng.normal(0, 1, NA)

def ejecutar(a, t0, n=50, semilla=0, ruido=1.0):
    """Rentabilidad acumulada del agente `a` en n sesiones desde t0."""
    g = np.random.default_rng([semilla, a, t0])
    v = 1.0
    for t in range(t0, t0 + n):
        lectura = (calidad[a] * T[t - 1]
                   + ruido * g.standard_normal(len(U)))
        s = kappa[a] * (lectura + 6 * gusto_mom[a] * R5[t - 1])
        w = np.exp(s - s.max())
        w = (1 - caja[a]) * w / w.sum()
        v *= 1 + w @ R[t]
    return v - 1

t0 = F.searchsorted(pd.Timestamp("2025-08-18"))
cr = np.array([ejecutar(a, t0) for a in range(NA)])
print(F[t0].date(), "a", F[t0 + 49].date(), "| noticias en",
      f"{(T != 0).mean():.1%} de los días-acción")
print("Spearman(puntuación, rentabilidad):",
      round(stats.spearmanr(puntuacion, cr)[0], 3))
print("rentabilidades (%):", np.round(100 * np.sort(cr), 1))
```
```output
2025-08-18 a 2025-10-27 | noticias en 9.0% de los días-acción
Spearman(puntuación, rentabilidad): 0.316
rentabilidades (%): [-7.8 -5.3 -4.3 -4.1 -4.  -3.  -2.5 -2.4 -2.3 -1.1 -0.8 -0.7 -0.5 -0.3
  0.   0.2  0.5  1.3  1.6  2.   6.7]
```

En las mismas fechas que LiveTradeBench, el banco simulado da una correlación de 0,32 entre la puntuación y la
rentabilidad, y las rentabilidades de los 21 agentes van del −7,8 al +6,7 %. ¿Es 0,32 la «verdad» del banco? No se
puede saber con una ventana: en 50 sesiones, lo que separa a los agentes es cuánto dinero tienen invertido mientras el
mercado sube o baja y la suerte de sus lecturas, y la ventaja de leer bien solo aparece cuando hay noticias de esas 15
empresas, que son pocas (un 9 % de los días-acción tiene alguna). Para ver el tamaño del ruido, la celda siguiente
repite el banco en todas las ventanas de 50 sesiones sin solapamiento de 2019 a 2025 y lo compara con la correlación a
largo plazo, la de la rentabilidad media de todas las ventanas.

```python
ventanas = list(range(6, len(F) - 50, 50))
CR = np.array([[ejecutar(a, t) for a in range(NA)] for t in ventanas])
rho = np.array([stats.spearmanr(puntuacion, c)[0] for c in CR])
print(len(ventanas), "ventanas | media", round(rho.mean(), 3),
      "| percentiles 5 y 95:", np.round(np.percentile(rho, [5, 95]), 2),
      "| negativas:", f"{(rho < 0).mean():.0%}")
print("a largo plazo: Spearman(puntuación, media) =",
      round(stats.spearmanr(puntuacion, CR.mean(axis=0))[0], 3),
      "| Spearman(caja, media) =",
      round(stats.spearmanr(caja, CR.mean(axis=0))[0], 3))
```
```output
35 ventanas | media 0.049 | percentiles 5 y 95: [-0.29  0.49] | negativas: 43%
a largo plazo: Spearman(puntuación, media) = 0.373 | Spearman(caja, media) = -0.566
```

*Fig. — Banco simulado de 21 agentes: correlación de rangos entre puntuación y rentabilidad en cada ventana de 50 sesiones.* Barras verticales con la correlación de Spearman entre la puntuación general de 21 agentes simulados y su rentabilidad en 35 ventanas de 50 sesiones de 2019 a 2025: van de −0,35 a 0,56, con media 0,05 y un 43 % negativas. Una línea destacada marca la relación a largo plazo, 0,37.

La verdad del banco es positiva: a largo plazo, con las 35 ventanas promediadas, la correlación entre la puntuación y
la rentabilidad media es 0,37. Pero en una ventana de 50 sesiones es una tirada: la media de las 35 es solo 0,05, el
90 % central va de −0,29 a 0,49 y un 43 % de las ventanas da una correlación negativa. Y lo que mejor explica la
rentabilidad media no es la capacidad sino cuánto invierte cada agente: la correlación de la fracción en caja con la
rentabilidad media es −0,57, en un periodo en el que el mercado sube. Un 0,054 o un −0,38 en una sola ventana de 50
días es compatible con casi cualquier relación verdadera.

## AlphaForgeBench: la misma pregunta no da la misma respuesta

«AlphaForgeBench: Benchmarking End-to-End Trading Strategy Design with Large Language Models», de Wentao Zhang y otros
siete autores (Nanyang Technological University, HKUST (Guangzhou) y Hong Kong Polytechnic University),
arXiv:2602.18481, versión 2 del 27 de mayo de 2026, con la cabecera de KDD 2026. Su punto de partida es una crítica a los
benchmarks como LiveTradeBench: cuando un LLM emite directamente las acciones de trading, sus decisiones son
inestables. En sus palabras, los LLM «produce drastically different trading actions across runs even under
deterministic decoding (Section C), rendering single-run live evaluations statistically unreliable».

El experimento del apéndice C es sencillo: BTC con datos diarios de 2025, un prompt con 30 días de precios e
indicadores técnicos, una acción por día (comprar todo, mantener o vender todo), sin costes, y **cinco ejecuciones**
idénticas de cada modelo con temperatura 0 y otras cinco con 0,7. Los resultados para gemini-3-pro-preview:

| Medida | Temperatura 0 | Temperatura 0,7 |
|---|---|---|
| Coincidencia de acciones entre pares de ejecuciones | 0,36 a 0,48 | 0,32 a 0,41 |
| Coincidencia media paso a paso | 61,4 % | — |
| Pasos con algún desacuerdo entre las cinco | 95,7 % | — |
| Trayectorias | una cae cerca de −50 %, otras cerca de cero | — |

Otros modelos son más estables (gemini-3-flash-preview coincide un 85,3 % con temperatura 0), pero incluso así las
curvas de rentabilidad «gradually fan out». Los autores lo atribuyen a la no determinación de la coma flotante y al
enrutado de los modelos de mezcla de expertos, amplificados porque los LLM no tienen memoria propia de sus acciones
anteriores: una decisión distinta al principio cambia todas las siguientes. Y escriben que en los benchmarks de
trading directo «run-to-run variance routinely exceeds intermodel variance». Su propuesta (lección 6.4.6) es que el LLM
escriba **factores y código de estrategia**, que después se ejecutan en un backtest determinista: así la variabilidad
queda en un único paso de generación.

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

Una discrepancia menor en la fuente: el apéndice C dice que se evalúan «seven mainstream closed-source models» y a
continuación enumera seis (gemini-3-flash-preview, gemini-3-pro-preview, grok-4.1-fast, deepseek-v3.2, gpt-5.2 y
claude-sonnet-4.5). Las cifras de esta sección son las de los párrafos de cada figura del apéndice.

</aside>

### Ejecuciones repetidas en el banco simulado

La celda repite cinco veces el banco en la ventana de 2025 con semillas distintas para el ruido de inferencia. Mide la
desviación de la rentabilidad de cada agente entre sus ejecuciones, la compara con la desviación entre agentes y
calcula cuánto se parecen los rankings de dos ejecuciones. Al final quita el ruido de inferencia (el equivalente a una
decodificación de verdad determinista).

```python
runs = np.array([[ejecutar(a, t0, semilla=s) for a in range(NA)]
                 for s in range(5)])
dentro = runs.std(axis=0).mean()           # mismo agente, 5 tiradas
entre = runs.mean(axis=0).std()            # entre agentes
print(f"desv. dentro de cada agente: {100 * dentro:.2f} pp | "
      f"entre agentes: {100 * entre:.2f} pp")
print("Spearman entre el ranking de la ejecución 0 y las demás:",
      [round(float(stats.spearmanr(runs[0], runs[k])[0]), 2)
       for k in range(1, 5)])
sin_ruido = np.array([[ejecutar(a, t0, semilla=s, ruido=0.0)
                       for a in range(NA)] for s in range(2)])
print("sin ruido de inferencia, ¿ejecuciones idénticas?",
      np.array_equal(sin_ruido[0], sin_ruido[1]))
```
```output
desv. dentro de cada agente: 3.58 pp | entre agentes: 2.00 pp
Spearman entre el ranking de la ejecución 0 y las demás: [-0.14, -0.17, 0.17, -0.34]
sin ruido de inferencia, ¿ejecuciones idénticas? True
```

La desviación de un mismo agente entre sus cinco ejecuciones (3,58 puntos) casi duplica la desviación entre agentes
(2,00), y el ranking de una ejecución no predice el de las demás (correlaciones de −0,34 a 0,17): es el patrón que AlphaForgeBench describe en modelos
reales. Sin ruido de inferencia el banco se vuelve reproducible, pero el ranking sigue siendo el de una sola ventana
de 50 sesiones, con todo el ruido de la sección anterior.

### Una decisión sin margen en el modelo local

La decodificación voraz del modelo local del curso es determinista: el mismo texto da siempre la misma respuesta
(lección 6.2.1). El problema es otro: **el texto cambia por motivos irrelevantes**. La celda pregunta al modelo
Qwen2.5-0.5B-Instruct si compraría, mantendría o vendería una acción que ha subido un 1,5 % en una semana con una noticia
de una demanda, escrito de ocho maneras equivalentes, y mira los logits del primer token de la respuesta: la opción
elegida y su margen sobre la segunda.

```python
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

torch.manual_seed(0)
torch.use_deterministic_algorithms(True)
NOMBRE = "Qwen/Qwen2.5-0.5B-Instruct"
tok = AutoTokenizer.from_pretrained(NOMBRE)
llm = AutoModelForCausalLM.from_pretrained(NOMBRE, dtype=torch.float32)

D = "hay una noticia sobre una demanda de un cliente"
variantes = [
    f"La acción ha variado un +1,5 % esta semana y {D}.",
    f"La acción ha variado un +1.5 % esta semana y {D}.",
    f"La acción ha variado un 1,5 % esta semana y {D}.",
    f"La acción ha subido un 1,5 % esta semana y {D}.",
    f"Esta semana la acción ha variado un +1,5 % y {D}.",
    f"La acción ha variado un +1,5 % esta semana; {D}.",
    f"La acción ha variado un +1,50 % esta semana y {D}.",
    f"La acción ha variado un +1,5% esta semana y {D}."]
PIDE = " Responde solo con una palabra: COMPRAR, MANTENER o VENDER."
ids = {o: tok(o, add_special_tokens=False)["input_ids"][0]
       for o in ("COMPRAR", "MANTENER", "VENDER")}
for v in variantes:
    x = tok.apply_chat_template([{"role": "user", "content": v + PIDE}],
                                add_generation_prompt=True,
                                return_tensors="pt", return_dict=True)
    with torch.inference_mode():
        lg = llm(**x).logits[0, -1]
    l = {o: float(lg[i]) for o, i in ids.items()}
    a, b = sorted(l, key=l.get, reverse=True)[:2]
    print(f"{a:8} margen {l[a] - l[b]:.2f} | {v[:46]}")
```
```output
COMPRAR  margen 0.05 | La acción ha variado un +1,5 % esta semana y h
VENDER   margen 0.09 | La acción ha variado un +1.5 % esta semana y h
VENDER   margen 0.07 | La acción ha variado un 1,5 % esta semana y ha
VENDER   margen 0.04 | La acción ha subido un 1,5 % esta semana y hay
VENDER   margen 0.34 | Esta semana la acción ha variado un +1,5 % y h
COMPRAR  margen 0.35 | La acción ha variado un +1,5 % esta semana; ha
COMPRAR  margen 0.14 | La acción ha variado un +1,50 % esta semana y
VENDER   margen 0.02 | La acción ha variado un +1,5% esta semana y ha
```

Con «+1,5 %» el modelo compra; con «+1.5 %», sin el signo, con «subido» en lugar de «variado», con la frase en otro
orden o sin espacio antes del «%», vende; con un punto y coma o con «+1,50 %», vuelve a comprar. Los márgenes entre la
opción elegida y la siguiente van de 0,02 a 0,35 logits: la
«decisión» es casi un empate que resuelve cualquier detalle del texto. Un modelo mayor tendrá márgenes distintos, y la
lección no extrapola este 0,5B a los modelos comerciales; lo que sí enseña es qué medir antes de fiarse de un agente:
**cuánto cambia su decisión ante perturbaciones irrelevantes** del prompt, del formato de los datos y del orden de la
información. Con un modelo servido por API se suman, además, las fuentes de variación que AlphaForgeBench señala y que
el usuario no controla.

## Del backtest al real: la degradación de los modelos de deep learning

El temario afirma que los modelos de deep learning fuertes en backtest se degradan en real. La fuente primaria más
reciente que lo documenta con una fase en vivo es AlphaCrafter (Yishuo Yuan y otros cuatro autores, Universidad de
Nankín, arXiv:2605.05580, versión 2 del 28 de julio de 2026). Su protocolo: carteras diarias sobre el CSI 300 y el
S&P 500, entrenamiento de 2016 a 2022, validación en 2023, **backtest de enero de 2024 a febrero de 2026** (519 y 542
sesiones) y una **fase en vivo con la API de paper trading de un bróker real** de marzo a junio de 2026 (69 y 73
sesiones), posterior al corte de entrenamiento de todos los LLM que usan. Su texto: «Machine learning and deep learning
methods, notably LSTM, demonstrate strong backtesting performance but exhibit pronounced degradation in live trading,
exposing their vulnerability to overfitting and regime shifts. This pattern is consistent across both markets».

```python
# Tabla 2 de arXiv:2605.05580 v2: Sharpe anualizado, métodos sin LLM
ac = pd.DataFrame([
    ("MACD", 0.99, 0.87, 0.72, 1.22),
    ("Grid", 0.33, -0.26, 1.11, 0.39),
    ("LightGBM", 1.22, 0.51, 0.51, 1.19),
    ("XGBoost", 1.24, 0.36, -0.16, 1.01),
    ("LSTM", 1.43, 0.35, 1.38, 0.83),
    ("Transformer", 1.19, -0.32, 0.44, 0.28),
    ("TRA", 1.16, 0.71, 1.01, 1.02)],
    columns=["metodo", "csi_bt", "csi_vivo", "sp_bt", "sp_vivo"])
SES = {"csi": (519, 69), "sp": (542, 73)}       # sesiones bt / vivo
se = lambda n: np.sqrt(252 / n)                 # error típico del SR
for m, (nb, nv) in SES.items():
    d = ac[f"{m}_vivo"] - ac[f"{m}_bt"]
    s = np.hypot(se(nb), se(nv))
    print(f"{m}: bajan {(d < 0).sum()} de 7 | error típico del SR: "
          f"bt {se(nb):.2f}, vivo {se(nv):.2f}, diferencia {s:.2f}")
ac.set_index("metodo")
```
```output
csi: bajan 7 de 7 | error típico del SR: bt 0.70, vivo 1.91, diferencia 2.03
sp: bajan 3 de 7 | error típico del SR: bt 0.68, vivo 1.86, diferencia 1.98
             csi_bt  csi_vivo  sp_bt  sp_vivo
metodo
MACD           0.99      0.87   0.72     1.22
Grid           0.33     -0.26   1.11     0.39
LightGBM       1.22      0.51   0.51     1.19
XGBoost        1.24      0.36  -0.16     1.01
LSTM           1.43      0.35   1.38     0.83
Transformer    1.19     -0.32   0.44     0.28
TRA            1.16      0.71   1.01     1.02
```

*Fig. — AlphaCrafter: Sharpe de backtest (gris) y en vivo (azul) de siete métodos sin LLM, CSI 300 y S&P 500.* Dos paneles de puntos unidos por una línea con el Sharpe de backtest (enero de 2024 a febrero de 2026) y en vivo (marzo a junio de 2026) de MACD, Grid, LightGBM, XGBoost, LSTM, Transformer y TRA. En el CSI 300 bajan los siete; el LSTM, destacado, pasa de 1,43 a 0,35. En el S&P 500 bajan tres, entre ellos el LSTM (de 1,38 a 0,83), y suben MACD, LightGBM y XGBoost.

La lectura cuidadosa tiene dos partes. La que apoya al temario: en el CSI 300 los siete métodos sin LLM bajan del
backtest al real, el LSTM pasa de 1,43 a 0,35 y el Transformer de 1,19 a −0,32; en el S&P 500 el LSTM también baja
(de 1,38 a 0,83). La que obliga a matizar: en el S&P 500 solo bajan tres de siete; MACD, LightGBM y XGBoost **suben**
con claridad en real y TRA queda igual, y
el error típico de un Sharpe anualizado medido en unas 70 sesiones es de casi 1,9, así que ninguna caída concreta es
distinguible del ruido; la diferencia entre backtest y real tiene un error típico de unos 2. Además, los autores
proponen un método competidor, que en su tabla se degrada menos. El
patrón es coherente con lo que el curso ya ha medido por otras vías: el sobreajuste de la validación (lección 5.5.4),
la deriva (lección 5.10.2), el decaimiento de las anomalías publicadas (lección 5.1.1) y el hundimiento de los Sharpe
de los modelos fundacionales con costes (lección 5.8.4). Pero una ventana en vivo de tres meses no lo prueba por sí
sola.

Dos estudios más completan el cuadro de los agentes con LLM. FINSABER (Li, Kim, Cucuringu y Ma, arXiv:2505.07078)
repite estrategias de *timing* con LLM durante dos décadas y con más de 100 acciones, y encuentra que las ventajas
publicadas «deteriorate significantly under broader cross-section and over a longer-term evaluation»; las estrategias
son demasiado conservadoras en mercados alcistas y demasiado agresivas en bajistas. DeepFund (Li et al.,
arXiv:2505.11065) evalúa nueve modelos en vivo, con datos posteriores al corte de cada uno, porque los backtests
permiten a los LLM «time travel», y encuentra que incluso DeepSeek-V3 y Claude-3.7-Sonnet tienen pérdidas netas.

## Cómo evaluar un agente sin engañarse

| Pregunta | Señal de alarma | Qué pedir |
|---|---|---|
| ¿Cuándo se entrenó el modelo? | Backtest anterior al corte | Periodo posterior al corte efectivo, en vivo o en paper trading (lección 6.2.5) |
| ¿Cuántas ejecuciones? | Una | Varias semillas o repeticiones y la distribución del resultado |
| ¿Contra qué se compara? | Reglas técnicas o nada | Cartera pasiva con los mismos activos y la misma información combinada sin LLM |
| ¿Costes? | No se mencionan | Comisiones, horquilla y deslizamiento con la rotación real (lección 2.4.7) |
| ¿Cuántas sesiones y modelos? | 50 días, 21 modelos | Error típico menor que la diferencia que se quiere detectar |
| ¿Cuántas configuraciones se probaron? | No se dice | Deflated Sharpe (lección 2.5.4) |
| ¿Es estable la decisión? | No se mide | Sensibilidad a perturbaciones irrelevantes del prompt y de los datos |

## Errores típicos

- **Elegir el modelo por un ranking general.** En LiveTradeBench la correlación con la rentabilidad fue de 0,054 en
  acciones y de −0,38 en Polymarket.
- **Leer una correlación de 21 puntos como si fuera precisa.** Su intervalo del 95 % mide casi 0,9 de ancho.
- **Publicar una sola ejecución.** La variabilidad de un agente entre ejecuciones puede superar a la que hay entre
  agentes.
- **Confiar en la temperatura 0.** Fija la decodificación, no el texto de entrada, ni la precisión numérica, ni el
  servidor que responde.
- **Tomar tres meses en vivo como prueba.** El error típico de un Sharpe en 70 sesiones es de casi 1,9.
- **Olvidar la beta.** Si todos los agentes ganan en un mercado que sube, nadie ha demostrado habilidad.

## Ejercicios

1. ¿Cuántos modelos haría falta comparar para que una correlación de Spearman verdadera de 0,18 (la del banco
   simulado a largo plazo) se detecte con una potencia del 80 % al 5 % bilateral? Usa la aproximación de Fisher con
   el error de Fieller.

**Solución.**

```python
def modelos_necesarios(rho, alfa=0.05, potencia=0.8):
    z = stats.norm.ppf(1 - alfa / 2) + stats.norm.ppf(potencia)
    return int(np.ceil((1.06 * z / np.arctanh(rho)) ** 2 + 3))

for rho in (0.18, 0.3, 0.5):
    print(rho, "->", modelos_necesarios(rho), "modelos")
```
```output
0.18 -> 270 modelos
0.3 -> 96 modelos
0.5 -> 33 modelos
```

Para una correlación verdadera de 0,18 harían falta del orden de 270 modelos, más de diez veces los de LiveTradeBench;
para 0,5, unos 33. Y eso con el ruido de una ventana fija: en el banco simulado, gran parte de la dispersión viene de
la ventana de 50 sesiones, así que además harían falta más ventanas. Un benchmark de agentes con unas decenas de
modelos solo puede detectar relaciones fuertes.

2. Repite el banco simulado con ventanas de 250 sesiones (un año) en lugar de 50. ¿Cómo cambian la media y los
   percentiles 5 y 95 de la correlación?

**Solución.**

```python
filas = []
for t in range(6, len(F) - 250, 250):
    c = [ejecutar(a, t, n=250) for a in range(NA)]
    filas.append({"inicio": F[t].date(),
                  "mercado_%": 100 * (np.prod(1 + R[t:t + 250]
                                              .mean(axis=1)) - 1),
                  "rho_puntuacion": stats.spearmanr(puntuacion, c)[0],
                  "rho_caja": stats.spearmanr(caja, c)[0]})
v = pd.DataFrame(filas).set_index("inicio")
print("media de rho_puntuacion:", round(v["rho_puntuacion"].mean(), 3))
v.round(2)
```
```output
media de rho_puntuacion: 0.027
            mercado_%  rho_puntuacion  rho_caja
inicio
2019-01-10      17.87            0.07     -0.10
2020-01-08      12.65            0.25     -0.34
2021-01-05      17.37            0.03     -0.06
2021-12-31     -26.11            0.09      0.56
2022-12-29      10.51           -0.13     -0.15
2023-12-28      26.44            0.06     -0.33
2024-12-26       6.44           -0.20     -0.29
```

Con ventanas de un año caben siete en los datos, y la correlación tampoco se estabiliza: va de −0,20 a 0,25, con una
media de 0,03, lejos del 0,37 a largo plazo. La columna de la caja lo explica: en la ventana que empieza a final de
2021, con el mercado de las 15 empresas cayendo un 26 %, la correlación de la caja con la rentabilidad es 0,56. Alargar la ventana no basta cuando la habilidad es pequeña frente al
ruido de inferencia, que se acumula durante todo el año, y frente a la exposición al mercado: en un año bajista los
agentes con más caja ganan, sea cual sea su capacidad. La relación verdadera solo aparece promediando muchos periodos
distintos, y aun así con pocos agentes (ejercicio 1) el error es grande.

3. Sin código: diseña la evaluación de un agente de research que propone cada semana compras y ventas sobre 50
   acciones. Tienes presupuesto para un año de llamadas a un modelo comercial.

**Solución.**

Primero, fechas: solo semanas posteriores al corte efectivo del modelo, en paper trading o en sombra (lección 4.5.3), y
nada de backtest anterior al corte salvo para depurar. Segundo, repetición: cada semana, varias ejecuciones
independientes de la misma decisión (por ejemplo, cinco) para medir la estabilidad y usar la decisión mayoritaria;
el presupuesto se reparte entre ejecuciones y sesiones, no se gasta en una sola tirada larga. Tercero, referencias
calculadas con la misma información sin LLM: la cartera pasiva de las 50 acciones y una regla simple con las mismas
señales (lección 6.4.3). Cuarto, costes con la rotación real. Quinto, perturbaciones: el mismo prompt con cambios
irrelevantes (formato de números, orden de las noticias) en una muestra de decisiones, para estimar cuánto cambia la
decisión. Y al final, la cuenta honesta: con 52 semanas, el error típico de un Sharpe anualizado es de 1; el año
servirá para descartar agentes malos o inestables, no para demostrar que uno es bueno.

## Autoevaluación

1. En LiveTradeBench, la correlación de Spearman entre la puntuación de LMArena y la rentabilidad acumulada en acciones de 21 modelos es 0,054. ¿Qué se puede concluir?

   - A. Que en esa ventana de 50 días el ranking general no ordenó la rentabilidad; con 21 modelos, el intervalo del 95 % de esa correlación va aproximadamente de −0,41 a 0,50, así que tampoco descarta una relación moderada
   - B. Que la capacidad general de un modelo no tiene ninguna relación con su capacidad para invertir
   - C. Que los modelos con más puntuación pierden dinero
   - D. Que hay que elegir el modelo con menos puntuación en LMArena

   *Respuesta A: Que en esa ventana de 50 días el ranking general no ordenó la rentabilidad; con 21 modelos, el intervalo del 95 % de esa correlación va aproximadamente de −0,41 a 0,50, así que tampoco descarta una relación moderada.* Con n = 21 el error típico de una correlación de rangos es del orden de 0,25. La conclusión de los autores, que una puntuación alta no implica mejores resultados, se sostiene; la de que no hay ninguna relación, no. La simulación de la lección muestra cómo una relación positiva verdadera produce en 50 sesiones correlaciones de −0,29 a 0,49 la mayor parte de las veces.

2. GPT-4.1 tuvo la rentabilidad más alta en acciones (6,25 %) y perdió un 33,69 % en Polymarket. ¿Qué lectura apoya el propio artículo?

   - A. Que GPT-4.1 es el mejor modelo para invertir en acciones
   - B. Que Polymarket es un mercado ineficiente para cualquier modelo
   - C. Que el resultado en un mercado no se generaliza al otro: la correlación del Sharpe entre los dos mercados es casi nula, y los autores atribuyen la pérdida a cambios de cartera exagerados con más volatilidad
   - D. Que el artículo descuenta comisiones y por eso las cifras son fiables

   *Respuesta C: Que el resultado en un mercado no se generaliza al otro: la correlación del Sharpe entre los dos mercados es casi nula, y los autores atribuyen la pérdida a cambios de cartera exagerados con más volatilidad.* Los autores escriben que el rendimiento en un mercado no generaliza al otro y que GPT-4.1 rindió mal en Polymarket probablemente por cambios de asignación exagerados. Además, el artículo reconoce que no tiene en cuenta comisiones, horquillas ni liquidez, y en 50 días las 21 carteras de acciones ganaron entre un 1,78 y un 6,25 %.

3. AlphaForgeBench repite cinco veces la misma tarea de trading de BTC con temperatura 0. ¿Qué encuentra en gemini-3-pro-preview?

   - A. Que con temperatura 0 las cinco ejecuciones son idénticas
   - B. Una coincidencia entre pares de ejecuciones de solo 0,36 a 0,48 en las acciones, y trayectorias tan distintas que una ejecución cae cerca de un −50 % mientras otras quedan cerca de cero
   - C. Que la temperatura no influye en nada
   - D. Que el modelo acierta siempre la dirección del BTC

   *Respuesta B: Una coincidencia entre pares de ejecuciones de solo 0,36 a 0,48 en las acciones, y trayectorias tan distintas que una ejecución cae cerca de un −50 % mientras otras quedan cerca de cero.* Los autores atribuyen la variabilidad con decodificación nominalmente determinista a la no determinación de la coma flotante y al enrutado de los modelos de mezcla de expertos, amplificada porque una acción distinta al principio cambia todas las siguientes. Por eso proponen evaluar el código de estrategias que el LLM genera, que después se ejecuta de forma determinista.

4. En AlphaCrafter, el LSTM pasa en el S&P 500 de un Sharpe de 1,38 en backtest (542 sesiones) a 0,83 en vivo (73 sesiones). ¿Qué hay que añadir antes de concluir?

   - A. Nada: la caída prueba que el LSTM está sobreajustado
   - B. Que el LSTM funciona mejor en vivo que en backtest
   - C. Que el resultado demuestra que el deep learning no sirve en finanzas
   - D. Que un Sharpe anualizado medido en 73 sesiones tiene un error típico de casi 1,9, así que esa caída concreta cabe en el ruido; el patrón es más informativo (en el CSI 300 bajan los siete métodos sin LLM) y es coherente con otras pruebas de sobreajuste

   *Respuesta D: Que un Sharpe anualizado medido en 73 sesiones tiene un error típico de casi 1,9, así que esa caída concreta cabe en el ruido; el patrón es más informativo (en el CSI 300 bajan los siete métodos sin LLM) y es coherente con otras pruebas de sobreajuste.* El error típico del Sharpe anualizado es aproximadamente la raíz de 252 entre el número de sesiones: 1,86 con 73. Una sola ventana en vivo de tres meses no basta para medir la degradación de un método; varias señales en la misma dirección, con un mecanismo conocido (sobreajuste y cambio de régimen), sí apuntan a ella.

5. En la lección, el modelo local de 0,5B decide COMPRAR o VENDER ante la misma información según se escriba «+1,5 %» o «+1.5 %». ¿Qué indica?

   - A. Que el modelo no entiende la coma decimal
   - B. Que hay que escribir siempre los números con punto
   - C. Que su decisión se juega en diferencias de centésimas entre los logits de las dos opciones: cualquier cambio irrelevante del texto la invierte, y una decisión así no puede ser la base de una orden
   - D. Que la decodificación voraz es aleatoria

   *Respuesta C: Que su decisión se juega en diferencias de centésimas entre los logits de las dos opciones: cualquier cambio irrelevante del texto la invierte, y una decisión así no puede ser la base de una orden.* En los ocho formatos de la lección, la diferencia entre el logit de la primera opción y el de la segunda va de 0,02 a 0,35, y el modelo elige COMPRAR en tres y VENDER en cinco. La decodificación voraz es determinista para un texto dado, pero el texto mismo cambia por motivos irrelevantes. Un modelo mayor tendrá márgenes distintos, pero el problema de fondo, decisiones sin margen, se mide igual.

## Ideas clave

- LiveTradeBench (Yu, Li y You, arXiv:2511.03628): 21 LLM en vivo del 18 de agosto al 24 de octubre de 2025; Spearman entre LMArena y la rentabilidad, 0,054 en acciones y −0,38 en Polymarket; GPT-4.1, +6,25 % en acciones y −33,69 % en Polymarket; sin costes de transacción.
- Con 21 modelos una correlación de rangos tiene un error típico de unos 0,25: 0,054 no distingue «nada» de «algo moderado». Lo que sí queda claro es que el ranking general no ordena los resultados.
- AlphaForgeBench (arXiv:2602.18481) documenta acciones «drastically different» entre ejecuciones del mismo modelo con decodificación determinista: un backtest de una ejecución no es reproducible.
- AlphaCrafter (arXiv:2605.05580) observa que los métodos de deep learning, en especial el LSTM, rinden bien en backtest y se degradan en vivo; con 69-73 sesiones en vivo cada caída cabe en el ruido, pero el patrón se repite.
- En un banco simulado donde la capacidad ayuda de verdad, 50 sesiones dan correlaciones entre −0,29 y 0,49 y la variabilidad de un mismo agente entre ejecuciones casi duplica la que hay entre agentes.
- Evaluar un agente exige periodos posteriores al corte del modelo, varias ejecuciones, baselines pasivas, costes y bastantes sesiones para que el error típico sea menor que la diferencia que se quiere medir.

## Recursos

### Libros

- [Yu, H., Li, F. y You, J. (2025): LiveTradeBench: Seeking Real-World Alpha with Large Language Models (arXiv:2511.03628, v1)](https://arxiv.org/abs/2511.03628) · arxiv.org
- [Zhang, W. et al. (2026): AlphaForgeBench: Benchmarking End-to-End Trading Strategy Design with Large Language Models (arXiv:2602.18481, v2)](https://arxiv.org/abs/2602.18481) · arxiv.org
- [Yuan, Y. et al. (2026): AlphaCrafter: Harnessing Multi-Agent Workflows for Cross-Sectional Quantitative Trading (arXiv:2605.05580, v2)](https://arxiv.org/abs/2605.05580) · arxiv.org
- [Li, W. W., Kim, H., Cucuringu, M. y Ma, T. (2025): Can LLM-based Financial Investing Strategies Outperform the Market in Long Run? (arXiv:2505.07078)](https://arxiv.org/abs/2505.07078) · arxiv.org
- [Li, C. et al. (2025): Time Travel is Cheating: Going Live with DeepFund for Real-Time Fund Investment Benchmarking (arXiv:2505.11065)](https://arxiv.org/abs/2505.11065) · arxiv.org

### Datos

- [acciones6_precios.parquet: precios de las 120 empresas del nivel 6 (datos sintéticos)](https://pythonparatrading.com/curso/datos/nivel-6/acciones6_precios.parquet) · Descarga · acciones6_precios.parquet

Lección anterior: [6.4.3 · Arquitecturas multiagente tipo TradingAgents](https://pythonparatrading.com/curso-python-trading/nivel-6/arquitecturas-multiagente-tipo-tradingagents/)

Lección siguiente: [6.4.5 · Guardarraíles para agentes: el agente propone, el motor decide](https://pythonparatrading.com/curso-python-trading/nivel-6/guardarrailes-para-agentes/)
