Señales LLM y backtesting riguroso
Del texto a la señal, backtests sin look-ahead, costes realistas y deflated Sharpe ratio.
Objetivos de aprendizaje
Al completar este módulo, el lector será capaz de:
- Evaluar críticamente los resultados autorreportados de los agentes LLM de trading (FinMem, TradingAgents, FinCon, HedgeAgents, entre otros), identificando los sesgos documentados en cada paper y separando el valor arquitectónico del valor de estrategia.
- Integrar una señal de sentimiento generada por LLM en un pipeline cuantitativo clásico: z-scores cross-sectionales, neutralización sectorial, decay temporal y ponderación por novedad.
- Seleccionar el framework de backtesting adecuado por fase (vectorbt para descubrimiento, zipline-reloaded para factores cross-sectionales, LEAN o nautilus_trader para validación de ejecución) y blindarlo contra look-ahead, survivorship y data snooping.
- Aplicar la corrección estadística institucional: PSR y Deflated Sharpe Ratio de Bailey–López de Prado, PBO vía CSCV y haircut de Harvey–Liu.
- Modelar costes de transacción realistas (descomposición del implementation shortfall, trayectoria óptima de Almgren–Chriss, square-root law de impacto, borrow en cortos) y cuantificar el deterioro de una señal bruta.
- Diseñar una arquitectura de ejecución gobernada: señal → RiskGateway determinista → aprobación HITL → broker (Alpaca, ib_async, FIX 4.2) con kill-switch, conforme al espíritu de la SEC 15c3-5.
Los módulos 7 y 8 dotaron al lector del marco de riesgo y de la construcción de carteras con vistas Black–Litterman. Este módulo cierra el Bloque III recorriendo el camino completo que va de la señal a la orden: qué dice realmente la literatura de agentes LLM de trading, cómo se convierte una salida de lenguaje natural en una señal cuantitativa defendible, cómo se valida con los estándares que exigiría un comité de asignación, y cómo se conecta a la ejecución sin ceder el control a un sistema estocástico. El principio rector, ya anticipado en módulos anteriores, se mantiene intacto: el LLM razona, la matemática decide y el humano veta; los papers de agentes se tratan aquí como objeto de estudio, no como estrategia desplegable (ProfitLogic) .
9.1 El estado del arte de los agentes de trading
9.1.1 Panorama verificado: arquitecturas, números estrella y sesgos documentados
Entre 2023 y 2026 la literatura académica produjo una genealogía reconocible de agentes LLM para trading: FinMem (arXiv 2311.13743, AAAI Symposium 2024) introdujo la memoria estratificada por horizonte temporal —capas shallow (noticias diarias, alto decay), intermediate (10-Q) y deep (10-K y reflexiones, bajo decay)— con un perfil de riesgo conmutable, y reportó Sharpe > 2,0 y retornos acumulados > 0,35 en TSLA y NFLX sobre cinco mega-caps en 2021–2022 (pfolio.io) . FinAgent (arXiv 2402.18485, KDD 2024) añadió multimodalidad (texto, series numéricas, gráficos K-line) y doble reflexión; su titular de abstract —92,27 % de retorno— procede de un dataset entre seis, el patrón exacto de selección del mejor resultado (arXiv.org) . TradingAgents (arXiv 2412.20138; repo con más de 65.000 estrellas) simula una firma completa —cuatro analistas, investigadores bull/bear en debate, trader, comité de riesgo, fund manager— y reporta CR 26,62 % y Sharpe 8,21 en AAPL en una ventana de tres meses de 2024, con máximos drawdowns de 0,91 % (🦜️🔗 LangChain) . Los propios autores añaden un pie autocrítico inusualmente honesto: el Sharpe excede su rango empírico esperado (SR > 3 "excelente") y lo atribuyen a la ausencia de correcciones en la ventana; con 11 llamadas LLM y más de 20 llamadas a herramientas por predicción, solo pudieron testear tres meses (langchain.js) .
StockAgent (arXiv 2407.18957, ACM TIST) aporta la contribución metodológica de nombrar el leakage ya en el abstract: es una simulación con order book y personalidades de inversor diseñada explícitamente para impedir que el modelo explote conocimiento previo del periodo de test (Springer) . FinRobot (arXiv 2405.14767, AI4Finance) es una plataforma de análisis en cuatro capas con Smart Scheduler multi-LLM, no un sistema de trading; su valor es arquitectónico, y sus autores critican la obsesión del campo con el backtesting frente a enfoques orientados a proceso (rdrr.io) . FinCon (arXiv 2407.06567, NeurIPS 2024 main track) implementa jerarquía manager–analyst con refuerzo verbal conceptual (CVRF) y gating de riesgo con CVaR, reportando CR 113,84 % y Sharpe 3,269 en una cartera TSLA/MSFT/PFE, y siendo el único agente con retorno positivo en el estrés de TSLA-2022; también admite alucinaciones en la gestión de memoria (Github) . MarketSenseAI (arXiv 2401.03737, ESWA) reporta batir al S&P 100 por 13 puntos con retornos de hasta 40 % en 2023 —año dentro de la ventana de conocimiento de GPT-4— y declara un conflicto de interés: los autores comercializan el framework como startup (skfolio.org) . HedgeAgents (arXiv 2502.13165, WWW 2025 Companion) reporta 70 % anualizado y 400 % en tres años, y en el mismo abstract admite que los agentes LLM convencionales pierden ~−20 % en caídas rápidas (arXiv.org) .
Tabla 9.1 — Agentes LLM de trading publicados: arquitectura, resultado reportado y sesgos documentados
| Paper (venue) | Arquitectura núcleo | Resultado reportado | Sesgos y advertencias documentadas |
|---|---|---|---|
| FinMem (AAAI Symp. 2024) | Memoria por capas + carácter conmutable | SR > 2,0, CR > 0,35 (TSLA, NFLX) (pfolio.io) | 5 mega-caps, 2021–22; sin costes; regla de conmutación de riesgo ajustada ex post; PC = 0,8213 de leakage contrafáctico (arXiv.org) |
| FinAgent (KDD 2024) | Multimodal + doble reflexión | 92,27 % retorno (1 dataset de 6) (arXiv.org) | Selección del mejor resultado en el abstract; recuperación por similitud pura |
| TradingAgents (arXiv, >65k★) | Firma multi-agente bull/bear/risk | CR 26,62 %, SR 8,21 (AAPL) (🦜️🔗 LangChain) | Ventana 3 meses; datos dentro del cutoff de GPT-4; autores: SR "fuera de rango empírico" (langchain.js) |
| StockAgent (ACM TIST) | Simulación order book anti-leakage | N/A (comportamental) (Springer) | No es estrategia; el comportamiento refleja al backbone, no al mercado |
| FinCon (NeurIPS 2024) | Manager–analyst + CVRF + CVaR | CR 113,84 %, SR 3,269 (Github) | Ventana oct-2022→jun-2023; admite alucinaciones de memoria (Github) ; costes parciales |
| MarketSenseAI (ESWA 2024) | GPT-4 CoT stock selection | +13 % vs S&P 100, hasta 40 % (skfolio.org) | Test 2023 in-cutoff; conflicto de interés comercial declarado (Advisor Perspectives) |
| HedgeAgents (WWW 2025) | Fund manager + expertos hedge | 70 % anualizado, 400 %/3 años (arXiv.org) | Sin réplica independiente; el propio paper admite −20 % en estrés (arXiv.org) |
Interpretación. La tabla resume la tesis central del módulo: los números extraordinarios comparten siempre las mismas cuatro debilidades —ventana corta, ausencia de costes, datos dentro del knowledge cutoff del modelo y falta de réplica independiente— y las literaturas entusiasta y escéptica no se contradicen, miden objetos distintos. FINSABER re-evaluó estas estrategias sobre dos décadas y más de 100 símbolos y halló que las ventajas reportadas se deterioran significativamente, con comportamiento procíclico perverso: demasiado conservadoras en mercados alcistas y demasiado agresivas en bajistas (arXiv.org) . DeepFund, en evaluación en vivo post-cutoff, observó pérdidas netas incluso en modelos flagship (arXiv.org) . La lectura profesional correcta no es el cinismo: estas arquitecturas —memoria por capas, debate adversativo, gating de riesgo con CVaR— son patrones de diseño valiosos para el andamiaje de investigación. Lo que no constituyen es evidencia de alfa desplegable; un backtest corto positivo no es alfa robusto, y una narrativa plausible no es una probabilidad operable (ProfitLogic) .
Nota de riesgo El profit mirage es el sesgo más insidioso de esta literatura porque no vive en el pipeline sino en los pesos del modelo: re-evaluados solo con datos posteriores a su knowledge cutoff, casi todos los agentes LLM publicados caen a un baseline aleatorio, y el mejor pierde el 50 % de su rendimiento (arXiv.org) . La revisión de arXiv 2505.07078 documenta además que la mayoría de estudios evalúa menos de un año, menos de diez acciones, sin código publicado y contra benchmarks ingenuos (臺灣博碩士論文知識加值系統) . El look-ahead paramétrico no puede descartarse inspeccionando el código del pipeline (Interactive ML) : la única defensa operativa es backtest estrictamente post-cutoff, benchmarks vivos (DeepFund, StockBench, FinLake-Bench) y tests contrafácticos de sensibilidad a los inputs (arXiv.org) .
En palabras llanas: por qué un Sharpe de 8,21 no es una estrategia
Evaluar a un agente LLM con datos de 2021–2023 es como examinar a un alumno con problemas cuyas soluciones llevaban años publicadas en los libros con los que estudió: no está resolviendo, está recordando. El profit mirage es exactamente eso — el look-ahead no vive en el pipeline, que puede ser impecable, sino en los pesos del modelo. Por eso la tabla 9.1 se lee profesionalmente con cuatro preguntas: ¿la ventana cubre más de un régimen de mercado?, ¿los resultados son netos de costes (spread, impacto, borrow)?, ¿el test es estrictamente posterior al knowledge cutoff?, ¿existe réplica independiente? Ningún paper de la tabla responde que sí a las cuatro, y los propios autores de TradingAgents admiten que su Sharpe está fuera del rango empírico esperado.
La conclusión no es el cinismo: la memoria estratificada de FinMem, el debate bull/bear de TradingAgents o el gating con CVaR de FinCon son patrones de diseño reutilizables en el andamiaje de investigación. Lo que no constituyen es evidencia de alfa desplegable. Aplicado en cascada, el filtro de las cuatro preguntas casi nunca llega a la última — la sección 9.1.1 documenta que, re-evaluados post-cutoff, casi todos los agentes publicados caen al baseline aleatorio, y el mejor pierde el 50 % de su rendimiento. Solo lo que sobrevive a las cuatro merece la siguiente fase: paper trading de 3 a 6 meses con criterio de paridad pre-registrado.
9.2 El sentimiento como señal cuantitativa
9.2.1 Lopez-Lira & Tang, la evidencia PEAD y el pipeline de integración
La señal LLM con mejor evidencia no es una arquitectura de agentes sino un clasificador de titulares. Lopez-Lira y Tang (arXiv 2304.07619) puntuaron con ChatGPT todos los titulares de valores comunes de CRSP entre octubre de 2021 y diciembre de 2022 —posterior al cutoff de ChatGPT, control de contaminación explícito— y construyeron una estrategia long-short autofinanciada: Sharpe 3,8 con GPT-4 en la versión v4 del paper, degradado a 3,28 en la v5 (y GPT-3.5 de 3,1 a 1,79), frente a Sharpes negativos de GPT-1/2 y BERT (arXiv.org) . El retorno acumulado supera el 500 %, pero sin costes de transacción, y con una asimetría reveladora: la pierna corta aporta 29 bps/día frente a 9 bps/día de la larga —la señal es sobre todo un detector de malas noticias, concentrada en small-caps donde los límites al arbitraje encarecen la corrección (arXiv.org) . Que los números cambien entre versiones del mismo paper es en sí mismo una lección metodológica sobre la fragilidad de los backtests. La evidencia PEAD es complementaria y de pedigrí sólido: features contextuales de earnings calls mejoran el retorno por trade de una cartera long-short en 53–354 bps out-of-sample sobre un universo S&P 500 point-in-time 2010–2022 (fgv.br) , aunque existen contraejemplos honestos donde el texto solo no supera al baseline (Advisor Perspectives) .
La integración profesional trata el score del LLM como un factor más, no como una orden. El pipeline de referencia: (1) el LLM emite scores continuos (preferibles a etiquetas discretas, porque preservan intensidad); (2) agregación temporal con decay exponencial —la predictibilidad documentada es a 1–5 días— y ponderación por novedad, descontando titulares duplicados o republicados; (3) winsorización y z-score cross-sectional por fecha; (4) neutralización frente a sector y factores de riesgo (mercado, tamaño, momentum), quedándose con el residual; (5) combinación IC-weighted con el alfa existente; (6) ejecución con lag de ingesta modelado, porque los timestamps de las noticias registran publicación, no disponibilidad para el pipeline (horizontrading.io) .
donde \(s_{i,t}\) es el score agregado de noticias del activo \(i\) y \(h\) es la vida media de la señal (1–3 días en la práctica documentada). La neutralización se implementa como regresión cross-sectional diaria del z-score sobre dummies sectoriales y exposiciones factoriales, usando el residual como señal final.
# --- Pipeline señal sentimiento LLM → factor cuantitativo (pandas) ---
import numpy as np, pandas as pd
def agregar_decay(scores: pd.DataFrame, halflife: float = 2.0) -> pd.DataFrame:
"""scores: DataFrame [fechas x tickers] de scores LLM diarios (NaN = sin noticia).
Decay exponencial con vida media `halflife` días; solo días con noticia pesan."""
lam = np.log(2) / halflife
out = scores.copy().astype(float)
for t in range(1, len(out)):
out.iloc[t] = out.iloc[t].fillna(0) + np.exp(-lam) * out.iloc[t-1].fillna(0)
return out
def zscore_cross_sectional(sig: pd.DataFrame, win: float = 0.01) -> pd.DataFrame:
lo, hi = sig.quantile(win, axis=1), sig.quantile(1 - win, axis=1)
w = sig.clip(lo, hi, axis=0) # winsorizado por fecha
med = w.median(axis=1) # mediana cross-sectional
mad = w.sub(med, axis=0).abs().median(axis=1) # MAD cross-sectional
return w.sub(med, axis=0).div(1.4826 * mad.replace(0, np.nan), axis=0)
def neutralizar(z: pd.DataFrame, sectores: pd.Series) -> pd.DataFrame:
"""Residual de z sobre dummies sectoriales, por fecha (OLS cross-sectional)."""
D = pd.get_dummies(sectores)
def resid(fila):
y = fila.dropna(); Xd = D.loc[y.index]
beta, *_ = np.linalg.lstsq(Xd.values, y.values, rcond=None)
return y - Xd.values @ beta
return z.apply(resid, axis=1)
En la práctica institucional En los desks que sí explotan señales textuales, el LLM nunca toca el motor de carteras directamente: produce un score que entra en la factor library como una columna más, con su IC decay medido semanalmente y su peso decidido por el optimizador existente. La regla operativa que separa research de producción es triple: la señal se construye solo con noticias ingestadas antes del timestamp de decisión (con lag de ingesta explícito, no el timestamp de publicación del titular) (horizontrading.io) ; su evaluación se hace post-cutoff del modelo o con un backbone de corte temporal certificado (arXiv.org) ; y su presupuesto de costes se calcula antes de mirar el Sharpe bruto, porque una señal diaria de alta rotación concentra su alfa exactamente donde los costes son mayores: small-caps con spreads anchos y borrow caro (arXiv.org) .
Ejemplo trabajado: cuatro tickers, tres días y una señal neutralizada
Veamos el pipeline de la sección con números pequeños pero realistas. Universo de cuatro valores —AAA y CCC (tecnología), BBB y DDD (energía)— y scores LLM diarios en [−1, 1] (NaN = sin noticia ese día):
| Día | AAA | BBB | CCC | DDD |
|---|---|---|---|---|
| 1 | +0,9 | −0,6 | — | +0,2 |
| 2 | — | −0,3 | +0,8 | — |
| 3 | −0,4 | — | — | +0,5 |
Paso 1 — Decay temporal. Con vida media \(h=2\) días, el factor diario es \(e^{-\lambda}=2^{-1/2}\approx 0{,}707\): la noticia de ayer pesa un 71 %, la de anteayer un 50 %. La función agregar_decay del módulo da, para el día 3:
| AAA | BBB | CCC | DDD | |
|---|---|---|---|---|
| Score agregado | +0,050 | −0,512 | +0,566 | +0,600 |
Nótese que DDD llega a 0,600 sin noticia el día 3: es \(0{,}5 + 0{,}707 \times 0{,}141\), la memoria del decay. Eso es lo que se busca — la predictibilidad documentada dura 1–5 días, no una sesión.
Paso 2 — Z-score cross-sectional. zscore_cross_sectional winsoriza (1 %/99 %) y normaliza por fecha con mediana y MAD, robustas frente a outliers. Para el día 3 (mediana 0,308; \(1{,}4826 \times\) MAD \(= 0{,}407\)):
| AAA | BBB | CCC | DDD | |
|---|---|---|---|---|
| z-score | −0,634 | −1,974 | +0,634 | +0,715 |
Paso 3 — Neutralización sectorial. neutralizar resta, por fecha, la media del sector (regresión sobre dummies). La media de energía es −0,629 —arrastrada por las malas noticias de BBB— y la de tecnología es 0,000:
| AAA | BBB | CCC | DDD | |
|---|---|---|---|---|
| residual | −0,634 | −1,344 | +0,634 | +1,344 |
La lección está en DDD: su z bruto (0,715) parecía apenas comparable al de CCC (0,634), pero DDD es positivo a pesar de un sector con sentimiento negativo; su componente idiosincrásico (1,344) es el doble que el de CCC. Sin neutralizar habrías repartido la apuesta casi a partes iguales; con el residual, la cartera long-short toma DDD contra BBB dentro del sector energético — una apuesta idiosincrásica, no una apuesta encubierta al petróleo. El código que lo reproduce es exactamente el del módulo:
scores = pd.DataFrame(
[[ 0.9, -0.6, np.nan, 0.2],
[np.nan, -0.3, 0.8, np.nan],
[-0.4, np.nan, np.nan, 0.5]],
index=pd.date_range("2026-07-27", periods=3),
columns=["AAA", "BBB", "CCC", "DDD"])
s = agregar_decay(scores, halflife=2.0) # memoria con decay
z = zscore_cross_sectional(s) # robusto, por fecha
res = neutralizar(z, pd.Series({"AAA": "Tech", "CCC": "Tech",
"BBB": "Energy", "DDD": "Energy"}))
print(res.iloc[-1].round(3)) # AAA -0.634 BBB -1.344 CCC 0.634 DDD 1.344
9.3 Backtesting con estándares institucionales
9.3.1 Frameworks 2026, trampas y corrección estadística
La decisión arquitectónica primera no es qué librería sino qué familia: los motores vectorizados computan la señal sobre arrays completos y simulan fills aproximados al cierre de barra; los motores event-driven procesan eventos ordenados en el tiempo y la estrategia reacciona —fidelidad de ejecución alta, velocidad menor (CSDN博客) . La regla de decisión 2026: descubrimiento masivo de señales en vectorbt/vectorbtpro; validación de microestructura y camino research→live en nautilus_trader o QuantConnect LEAN; factores cross-sectionales en zipline-reloaded (Pipeline API); asignación por pesos en bt (ar5iv) .
Tabla 9.2 — Frameworks de backtesting 2026: arquitectura, velocidad, paridad backtest→live y mantenimiento
| Framework | Arquitectura / núcleo | Velocidad | Multi-activo | Paridad backtest→live | Mantenimiento (2026) |
|---|---|---|---|---|---|
| vectorbt (OSS) / vectorbtpro | Vectorizado NumPy/Numba; pro añade loops Numba | Muy alta–extrema | Sí (columnas = activos) | No nativa ("execute it elsewhere") (Advisor Perspectives) | OSS comunitario; pro activo por suscripción (desde ~25 USD/mes) (ar5iv) |
| zipline-reloaded | Event-driven + Pipeline API (Python) | Baja-media | Sí, cross-sectional | No (solo research) | Comunidad; ritmo "glacial" (quant67.com) |
| backtrader | Event-driven loop, Python puro | Baja (single-threaded) | Sí | Integraciones envejecidas | Legacy: proyecto estancado (ar5iv) |
| QuantConnect LEAN | Event-driven, C# + wrapper Python | Alta (10 años equities ≈ 33 s cloud) (MDPI) | Sí: equities, opciones, futuros, FX, cripto | Nativa: mismo código, 20+ brokers | Muy activo (16.000+ estrellas) (MDPI) |
| nautilus_trader | Event-driven actor/bus, núcleo Rust + PyO3 | Muy alta | Asset-class agnostic, multi-venue | Nativa: código idéntico, solo cambia configuración (CSDN博客) | Muy activo (Nautech Systems) |
| bt | Motor de pesos/rebalanceo (Python) | Media | Sí (cestas ETF/factores) | No | Maduro/estable, baja actividad (ar5iv) |
Interpretación. El patrón profesional consolidado es un pipeline de dos motores, no una apuesta única: barridos paramétricos masivos y research ML en el motor vectorizado (donde la velocidad permite explorar miles de configuraciones —lo que, dicho sea, agrava el problema de selección que trataremos con el DSR—) y, solo si la señal sobrevive a los chequeos de robustez, re-implementación en un motor event-driven con paridad backtest-live para validar supuestos de ejecución: fills, latencia, settlement T+3, fees y slippage realistas (ar5iv) . Nunca se despliega desde el motor vectorizado: sus fills al cierre de barra son una aproximación de descubrimiento, no una simulación de ejecución. La paridad de código de nautilus_trader y LEAN ("identical strategy code" entre backtest, sandbox y live) (CSDN博客) elimina la clase entera de errores de traducción research→producción que históricamente contaminó el despliegue de estrategias.
Las cuatro trampas canónicas tienen cada una su detector. Look-ahead: usar información no disponible en el momento de la decisión —incluido el caso LLM, donde la fuga está en los pesos del modelo— (臺灣博碩士論文知識加值系統) . Survivorship: universos sin delistings, con distorsiones anuales estimadas entre el 0,1 % y el 0,9 % y preinclusion bias al usar constituyentes actuales del índice (臺灣博碩士論文知識加值系統) . Data snooping / multiple testing: probar muchas configuraciones sobre los mismos datos y reportar la mejor; el Sharpe reportado es casi nunca una hipótesis única sino el máximo de muchas estimaciones ruidosas (RDocumentation) . Selección/reporte: McLean y Pontiff documentaron degradaciones medias del −26 % out-of-sample y −58 % post-publicación en predictores publicados (Github) .
La corrección estadística canónica es el Probabilistic Sharpe Ratio, que ajusta el Sharpe estimado por no-normalidad y longitud de muestra con el error estándar de Lo:
donde \(T\) es el número de observaciones, \(\hat{\gamma}_3\) la asimetría muestral, \(\hat{\gamma}_4\) la curtosis (3 = Normal) y \(\Phi\) la CDF Normal. El Deflated Sharpe Ratio sustituye el benchmark \(SR^*\) por el máximo esperado bajo la hipótesis nula de \(N\) estrategias intentadas sin skill:
con \(\gamma_{EM} \approx 0{,}5772\) (constante de Euler–Mascheroni) y \(\mathbb{V}[\cdot]\) la varianza de los Sharpes de las \(N\) configuraciones probadas. Entonces \(\widehat{DSR} = \widehat{PSR}(SR_0)\), con regla operativa DSR > 0,95: incluso admitiendo cuántas estrategias se probaron, hay un 95 %+ de probabilidad de que el edge sea real (PyPI) . Complementos: la PBO (Probability of Backtest Overfitting) vía CSCV —partir la matriz de P&L en \(S\) bloques, tomar las \(\binom{S}{S/2}\) combinaciones mitad IS / mitad OOS, seleccionar la configuración óptima IS y medir su rango OOS— es la probabilidad de que la mejor configuración in-sample quede por debajo de la mediana out-of-sample, y tiende a 1 cuando \(N\) crece con independencia de que exista poder predictivo genuino (PyPI) . El haircut de Harvey–Liu convierte el Sharpe a t-ratio, ajusta el p-valor por el número de tests (Bonferroni, Holm, BHY) y re-convierte; es marcadamente no lineal —la regla del "50 % de haircut" es un error; Sharpe 1,0 con 120 meses y 100 tests queda en 0,438 (BHY) o 0,232 (Bonferroni)— (博客园) :
# --- Deflated Sharpe Ratio (Bailey & López de Prado 2014) ---
import numpy as np
from scipy.stats import norm
def probabilistic_sharpe(sr, sr_star, n_obs, skew, kurt):
se = np.sqrt(1 - skew * sr + (kurt - 1) / 4 * sr**2) # error estándar de Lo (2002)
return norm.cdf((sr - sr_star) * np.sqrt(n_obs - 1) / se)
def expected_max_sharpe(n_trials, var_sr, euler=0.5772156649):
return np.sqrt(var_sr) * ((1 - euler) * norm.ppf(1 - 1 / n_trials)
+ euler * norm.ppf(1 - 1 / (n_trials * np.e)))
def deflated_sharpe(sr, n_obs, skew, kurt, n_trials, var_sr):
return probabilistic_sharpe(sr, expected_max_sharpe(n_trials, var_sr),
n_obs, skew, kurt)
# Sharpe 1.2 anual, 3 años diarios, 100 trials, skew=-1, kurt=6
dsr = deflated_sharpe(1.2/np.sqrt(252), 756, -1.0, 6.0, 100, 0.10/252)
print(f"DSR = {dsr:.3f} -> {'edge plausible' if dsr > 0.95 else 'indistinguible de ruido'}")
# --- Backtest con costes en vectorbt (API real) ---
import vectorbt as vbt
data = vbt.YFData.download("AAPL", start="2020-01-01", end="2023-01-01")
close = data.get("Close")
fast, slow = vbt.MA.run(close, 20), vbt.MA.run(close, 50)
pf = vbt.Portfolio.from_signals(
close,
entries=fast.ma_crossed_above(slow),
exits=fast.ma_crossed_below(slow),
init_cash=10_000,
fees=0.001, # 0,1% comisión por lado
slippage=0.001, # 0,1% slippage por lado
freq='D',
)
print(pf.stats()) # comparar con fees=0, slippage=0 para cuantificar el drag
Trampa común: «yo solo probé tres configuraciones»
El \(N\) del Deflated Sharpe Ratio no es el número de backtests que guardaste en disco: es el número de decisiones de diseño que tomaste mirando los datos. Cada vuelta de tuerca a un parámetro tras ver el equity curve, cada cambio de universo o de periodo «porque quedaba raro», cada idea descartada a ojo —todo eso son trials, te hayas dado cuenta o no. Y la velocidad del motor vectorizado lo agrava: cuando un barrido de mil configuraciones cuesta un café, es fácil probar doscientas variantes en una tarde y reportar la mejor como si fuera una hipótesis única.
El castigo es brutalmente no lineal. Con los parámetros del ejemplo del módulo (Sharpe 1,2 anual, 756 días, asimetría −1, curtosis 6), el PSR clásico contra \(SR^*=0\) da 0,977 —aprobado—, pero el DSR cae a 0,939 admitiendo apenas 3 trials, a 0,818 con 30 y a 0,747 con 100. No hace falta un data mining escandaloso para invalidar un resultado: basta una exploración honesta pero no contabilizada. La defensa operativa es triple: registra \(N\) con honestidad (incluidos los trials de tu equipo y los de la literatura que leíste antes de diseñar), pre-registra la configuración final antes del walk-forward, y reporta el DSR junto al Sharpe — nunca solo.
9.3.2 Costes de transacción realistas y capacidad
La medida canónica de coste de ejecución es el implementation shortfall (Perold 1988): la brecha entre el precio a la llegada de la orden y el precio efectivamente conseguido (LangChain) :
El componente más olvidado en los papers LLM es el borrow en cortos: el vendedor en corto paga una tasa anual sobre el valor de la posición, con coste diario
donde \(r_b\) es el borrow fee anual. Magnitudes reales: un ETF general collateral como SMH cotizaba a 0,7 % anual (IBKR, jul-2026); los valores hard to borrow superan el 10–100 % anual e inviabilizan estrategias de cortos de alta rotación (CSDN博客) . Recordando que la pierna corta aportaba el triple que la larga en Lopez-Lira & Tang (arXiv.org) , omitir el borrow no es un detalle: es omitir el coste principal de la señal.
El modelo puente teoría-práctica es Almgren–Chriss (2001): liquidar \(X\) acciones en \([0,T]\) con \(N\) pasos de longitud \(\tau = T/N\), precio con impacto permanente \(\gamma\) y temporal \(\eta\), minimizando \(E(x) + \lambda V(x)\) con
La solución cerrada es una trayectoria hiperbólica con parámetro de urgencia \(\kappa\) (Blockchain News) :
Dos límites docentes: con \(\kappa T \ll 1\) la trayectoria degenera en TWAP lineal (minimiza impacto); con \(\kappa T \gg 1\) la liquidación es front-loaded exponencial con vida media \(\theta = 1/\kappa\). Y como la frontera eficiente es diferenciable en el punto de coste mínimo, la estrategia ingenua (\(\lambda = 0\)) nunca es óptima para un trader averso al riesgo: reducciones significativas de varianza cuestan solo incrementos marginales de coste esperado (Github) .
Sobre el impacto, la ley empírica dominante para metaórdenes es la square-root law (🦜️🔗 LangChain) :
con \(\sigma_D\) la volatilidad diaria, \(Q\) el volumen de la metaorden y \(V_D\) el volumen diario medio —regla mnemotécnica: cuesta aproximadamente un día de volatilidad operar un día de volumen (🦜️🔗 LangChain) . El impacto es cóncavo en \(Q\): las estrategias de alta rotación sobre posiciones pequeñas apenas lo sufren, pero cualquier escalado institucional lo convierte en el límite de capacidad de la estrategia. La aritmética agregada es letal para señales diarias de alta rotación:
Con rotación diaria completa, incluso 5 bps por lado suponen ~25 puntos porcentuales de drag anual (\(250 \times 2 \times 5\,\text{bps}\)): un Sharpe bruto de 2,0 colapsa por debajo de 0,5. El gráfico siguiente ilustra el efecto sobre una señal de sentimiento sintética: la versión bruta muestra un Sharpe de 1,44; la neta de 6 bps por lado con rotación del 35 % diario cae a 0,67.

Figura 9.1. Sharpe bruto (1,44) frente a neto (0,67) de una señal de sentimiento sintética con 6 bps por lado y rotación diaria del 35%. Elaboración propia con datos sintéticos, jul-2026.
# --- Almgren-Chriss: trayectoria óptima de liquidación ---
import numpy as np
def almgren_chriss_trajectory(X, T, N, sigma, eta, lam):
tau = T / N
kappa = np.sqrt(lam * sigma**2 / eta) # urgencia κ ≈ sqrt(λσ²/η)
t = np.arange(N + 1) * tau
x = X * np.sinh(kappa * (T - t)) / np.sinh(kappa * T)
return t, x, -np.diff(x), kappa # ventas n_j por intervalo
t, x, n, k = almgren_chriss_trajectory(1e6, T=1.0, N=390,
sigma=0.02, eta=1e-7, lam=1e-6)
print(f"Vida media de la liquidación θ=1/κ = {1/k:.3f} días")
# --- Coste total en bps: spread + impacto sqrt + borrow ---
def coste_total_bps(Q, V_dia, sigma_dia, spread_bps, comision_bps,
Y=0.6, r_borrow=0.0, dias_corto=0, direccion=1):
impacto = Y * sigma_dia * np.sqrt(Q / V_dia) * 1e4
borrow = r_borrow / 360 * dias_corto * 1e4 if direccion < 0 else 0.0
return 0.5 * spread_bps + impacto + comision_bps + borrow
FINSABER aporta la verificación empírica a escala: en backtests sistemáticos de dos décadas y más de 100 símbolos, las ventajas de las estrategias LLM basadas en timing se deterioran significativamente respecto a las ventanas estrechas reportadas, y el análisis por régimen muestra el patrón perverso de exceso de cautela en mercados alcistas y exceso de agresividad en bajistas (arXiv.org) . La tabla siguiente condensa el checklist de validación que un comité de asignación institucional exige antes de capital real.
Tabla 9.3 — Checklist institucional de validación de estrategias antes de asignar capital real
| # | Punto de control | Estándar mínimo |
|---|---|---|
| 1 | Costes completos | Comisiones, spread, slippage calibrado, impacto (√ o Almgren–Chriss), borrow, impuestos (Blockchain News) |
| 2 | Datos point-in-time | Universos con delistings; fundamentales con fecha real de publicación (臺灣博碩士論文知識加值系統) |
| 3 | Validación OOS estricta | Walk-forward anclado/rodante; CPCV con purge + embargo (arXiv.org) |
| 4 | Corrección de selección | N trials reportado; DSR > 0,95 o haircut Harvey–Liu; PBO vía CSCV (PyPI) |
| 5 | Disciplina anti-leakage LLM | Backtest solo post-cutoff; tests contrafácticos; baseline aleatorio (arXiv.org) |
| 6 | Lag de ingesta modelado | Timestamps de disponibilidad, no de publicación (horizontrading.io) |
| 7 | Paper trading prolongado | ≥ 3–6 meses; slippage realizado vs. asumido; criterio de paridad pre-registrado (ResearchGate) |
| 8 | Controles pre-trade | RiskGateway determinista, kill-switch, HITL, audit trail (piso 15c3-5) (skywork.ai) |
| 9 | Capacidad | AUM máximo antes de que el impacto cóncavo se coma el alfa (🦜️🔗 LangChain) |
| 10 | Reproducibilidad y despliegue gradual | Código, datos y seeds; paper → micro-capital → escalado con TCA continuo (LangChain) |
Interpretación. El checklist no es burocracia: cada punto neutraliza un modo de fallo documentado en la literatura revisada en la sección 9.1. Los puntos 1–4 son el estándar clásico que ya exigiría cualquier asignador a un gestor cuantitativo tradicional; los puntos 5–6 son la adición específica de la era LLM, porque el leakage paramétrico y el desfase publicación/disponibilidad son canales de look-ahead sin análogo clásico que la inspección del código no puede descartar (horizontrading.io) . El punto 7 opera como prueba de fuego temporal: una señal con edge real degrada suavemente en paper trading, mientras que un artefacto de backtest colapsa en semanas. Los puntos 8–10 conectan con la sección 9.4 y con los módulos 10 y 12 del curso, donde el RiskGateway y este checklist se formalizan como entregables del capstone. La regla de decisión final es binaria: si alguno de los diez puntos no puede verificarse, la estrategia no recibe capital — independientemente de lo impresionante que sea el equity curve bruto.
En palabras llanas: la ley de la raíz cuadrada y el alquiler invisible de los cortos
La square-root law dice algo antiintuitivo pero empíricamente robusto: mover el doble de papel no cuesta el doble, cuesta \(\sqrt{2} \approx 1{,}41\) veces más — y la regla mnemotécnica del módulo lo hace tangible: operar un día de volumen cuesta aproximadamente un día de volatilidad. Piensa en cruzar un río: si tu orden es un vaso de agua, el cauce ni se inmuta; si es comparable al caudal diario, eres tú quien mueve el nivel del agua. Por eso el impacto es irrelevante para una cartera pequeña y, a la vez, es el límite de capacidad de cualquier estrategia que escale: el alfa que sobra a 1 M USD puede no existir a 500 M USD, no porque la señal se deteriore, sino porque tu propia ejecución se lo come.
El segundo coste olvidado es el borrow: vender en corto es alquilar las acciones, y el alquiler se paga a diario (\(r_b/360\) por día sobre el valor de la posición). Un ETF general collateral como SMH cotiza al 0,7 % anual, pero un valor hard to borrow supera el 10–100 % — y recuerda la asimetría de Lopez-Lira & Tang: la pierna corta aportaba el triple que la larga (29 frente a 9 bps/día). Omitir el borrow en el backtest de una señal de sentimiento no es una simplificación menor: es omitir el coste principal de la fuente de alfa.
La doble erosión, en cifras: trials y rotación
Las dos fuerzas que separan un backtest bonito de una estrategia real caben en un gráfico. A la izquierda, el DSR del ejemplo del módulo (Sharpe 1,2 anual, 3 años diarios, asimetría −1, curtosis 6) en función del número de configuraciones probadas: el umbral institucional de 0,95 se pierde ya entre 2 y 3 trials. A la derecha, el drag anual de costes según los bps por lado y la rotación diaria: con rotación completa, 5 bps por lado son ~25 puntos porcentuales al año (\(250 \times 2 \times 5\) bps), y con la rotación del 35 % de la figura 9.1, 6 bps por lado explican el salto de Sharpe 1,44 a 0,67.

Figura 9.2. Izquierda: DSR de Bailey–López de Prado para un Sharpe de 1,2 (skew −1, kurt 6, 756 obs.) según N trials; el umbral 0,95 se cruza entre 2 y 3 configuraciones. Derecha: drag anual en puntos porcentuales según bps por lado para rotación diaria del 10 %, 35 % y 100 %. Elaboración propia con las funciones del módulo, jul-2026.
La lectura conjunta es la tesis del módulo: una señal de alta rotación necesita un Sharpe bruto muy alto para sobrevivir a los costes, y un Sharpe alto obtenido explorando mucho necesita un DSR que casi nunca sobrevive a la contabilidad honesta de los trials.
9.4 De la señal a la ejecución gobernada
9.4.1 Brokers, protocolos y la arquitectura RiskGateway + HITL
En el mundo retail-prosumer, Alpaca ofrece API REST/WebSocket comission-free con entorno paper idéntico al live, buying power 4x intradía / 2x overnight, venta en corto y órdenes avanzadas (bracket, OCO, trailing stop); la práctica estándar de idempotencia es el client_order_id único, que evita duplicar órdenes si el agente reintenta tras un timeout (LangChain) . Interactive Brokers es la referencia institucional-retail (acceso global multi-activo, feed público de borrow (CSDN博客) ), y el stack Python vigente es ib_async, sucesor mantenido de ib_insync (archivado) (LangChain) :
from ib_async import *
ib = IB()
ib.connect('127.0.0.1', 7497, clientId=1) # 7497 = TWS paper
contract = Stock('TSLA', 'SMART', 'USD')
parent = LimitOrder('BUY', 100, 250.00)
parent.orderId = ib.client.getReqId(); parent.transmit = False
stop = StopOrder('SELL', 100, 240.00)
stop.orderId = ib.client.getReqId(); stop.parentId = parent.orderId; stop.transmit = False
tp = LimitOrder('SELL', 100, 260.00)
tp.orderId = ib.client.getReqId(); tp.parentId = parent.orderId; tp.transmit = True
for o in (parent, stop, tp):
ib.placeOrder(contract, o)
En el mundo institucional la estrategia no habla con el broker: habla con el OMS (ciclo de vida de la orden, compliance, asignación, auditoría —el system of record), que enruta al EMS (smart order routing, algos VWAP/TWAP/IS, TCA), que ejecuta contra venues vía FIX (langchain.com) . FIX 4.2 sigue desplegado masivamente para equities: mensajes tag=value delimitados por SOH, con 35=D NewOrderSingle, 35=8 ExecutionReport, 35=F OrderCancelRequest y 35=G Cancel/Replace, sesión con Logon (35=A) y Heartbeat (35=0), y números de secuencia (tag 34) estrictamente monotónicos —un gap dispara ResendRequest (35=2)— (arXiv.org) :
8=FIX.4.2|49=CLIENT|56=EXCHANGE|34=1|52=20260729-13:00:00|35=D|11=LLM-7F3A|55=AAPL|54=1|38=500|40=2|44=212.50|10=123|
El piso regulatorio es la SEC Rule 15c3-5 (Market Access Rule): tras el Flash Crash, los broker-dealers deben aplicar controles pre-trade automatizados e indelegables —límites de capital y crédito, tamaño máximo de orden, prevención de órdenes erróneas y, para DMA, monitorización en tiempo real y kill-switch— (skywork.ai) . La lección para sistemas con LLM es directa: la regulación asume que el algoritmo fallará y obliga a que el guardrail sea independiente del generador de órdenes. La arquitectura que se enseña en este curso implementa exactamente ese principio: el agente nunca tiene credenciales de trading; tiene una herramienta submit_order envuelta en un RiskGateway determinista (límites en código, nunca en el prompt), un interrupt HITL para órdenes sobre umbral y un kill-switch que nunca pide permiso (🦜️🔗 LangChain) .
class RiskGateway:
"""Capa de riesgo pre-trade determinista (estilo 15c3-5)."""
def __init__(self, api, max_notional=25_000, max_daily_loss=5_000, max_orders_min=10):
self.api, self.max_notional = api, max_notional
self.max_daily_loss, self.max_orders_min = max_daily_loss, max_orders_min
self.kill = False # kill-switch global
def check(self, symbol, qty, price, side):
if self.kill:
raise RiskBlock("KILL-SWITCH ACTIVO: toda nueva orden bloqueada")
if qty * price > self.max_notional:
raise RiskBlock(f"Notional {qty*price:.0f} > límite {self.max_notional}")
if self.daily_realized_pnl() < -self.max_daily_loss:
self.kill = True # auto-kill por pérdida diaria
self.cancel_and_flatten()
raise RiskBlock("Límite de pérdida diaria: posiciones cerradas")
if self.orders_last_minute() >= self.max_orders_min:
raise RiskBlock("Rate limit interno excedido (anti runaway-loop)")
if side == "sell" and not self.is_shortable(symbol):
raise RiskBlock(f"{symbol} no shortable / borrow no disponible")
return True
class RiskBlock(Exception): pass
La integración con LangChain usa HumanInTheLoopMiddleware: interrumpe la ejecución en llamadas a herramientas configuradas, persiste el estado con un checkpointer y admite decisiones approve/edit/reject/respond, con interrupts condicionales (when) para exigir aprobación humana solo por encima de un notional dado (🦜️🔗 LangChain) :
from langchain.agents import create_agent
from langchain.agents.middleware import HumanInTheLoopMiddleware, ToolCallRequest
def big_order(request: ToolCallRequest) -> bool:
a = request.tool_call["args"]
return a.get("qty", 0) * a.get("limit_price", 0) > 10_000 # HITL condicional
agent = create_agent(
model="gpt-5.5",
tools=[get_market_data, compute_signal, submit_order, cancel_all_orders],
middleware=[HumanInTheLoopMiddleware(
interrupt_on={
"submit_order": {"allowed_decisions": ["approve", "reject"], "when": big_order},
"cancel_all_orders": False, # el kill-switch NUNCA pide permiso
"get_market_data": False,
},
description_prefix="ORDEN PENDIENTE DE APROBACIÓN",
)],
checkpointer=AsyncPostgresSaver(...), # obligatorio para HITL
)
Los disparadores del kill-switch son concretos y monitorizables: pérdida diaria, desviación del slippage realizado frente al asumido en el backtest, latencia anómala, errores de datos (gaps, timestamps futuros), halts LULD, o el botón manual del operador. El equivalente FIX es un 35=F masivo seguido de cierre de sesión (35=5). La métrica honesta de cierre del módulo es, por tanto, única: el Sharpe neto de costes, deflactado por los N trials, validado post-cutoff y ejecutado bajo controles estilo 15c3-5. Todo lo demás es marketing del backtest.
Trampa común: el HITL decorativo
Un human-in-the-loop mal diseñado da falsa sensación de control y ninguno real. Tres modos de fallo documentados en la práctica:
- Fatiga de aprobación. Si el umbral salta con cada orden, el operador acaba aprobando mecánicamente en segundos lo que debería revisar en minutos; el interrupt existe, pero el juicio ya no está. El umbral de
whendebe saltar raramente — para eso está el RiskGateway absorbiendo el caso rutinario. - Smurfing algorítmico. Con un HITL que salta por encima de 10.000 USD de notional por orden, un agente que quiere comprar 60.000 USD aprende a trocear en seis órdenes de 9.999. La defensa no está en el prompt sino en el gateway: agregar notional por símbolo y ventana temporal (el
max_orders_miny los límites diarios delRiskGatewaydel módulo son exactamente eso). - Kill-switch que pide permiso. Si cancelar todo requiere aprobación humana, no es un kill-switch: es una sugerencia. Por eso en el código del módulo
cancel_all_orderstieneinterrupt_on: False— el espíritu de la SEC 15c3-5 es que el guardrail sea independiente del generador de órdenes, precisamente porque la regulación asume que el algoritmo fallará.
La prueba de fuego es sencilla: simula en paper un agente en bucle emitiendo 200 órdenes por minuto (ejercicio 5 del módulo) y cuenta cuántas revisó el humano con criterio. Si la respuesta avergüenza, el HITL era decorativo.
El ciclo de vida de una orden gobernada
El diagrama del módulo muestra la arquitectura estática; esta secuencia muestra la dinámica temporal — dónde se persiste estado, dónde entra el humano y qué viaja por FIX en cada sentido:
Dos detalles que importan en producción: el client_order_id hace idempotente el reintento tras un timeout (sin él, la misma orden se duplica), y los números de secuencia FIX (tag 34) son monótonos — un gap dispara ResendRequest (35=2), así que la sesión y su estado también son parte del sistema de riesgo.
Ejercicios
- Backtest de señal de sentimiento con vectorbt. Construya una señal sintética de scores LLM sobre 50 tickers (o descargue titulares reales y puntúelos con un modelo vía batch API), agréguela con decay de vida media 2 días y conviértala en entradas/salidas long-only del quintil superior. Ejecute
Portfolio.from_signalsconfees=0, slippage=0y confees=0.001, slippage=0.001; reporte Sharpe bruto, neto y turnover implícito. Repita confees=0.003y discuta a qué nivel de fricción la señal deja de ser viable. - Cálculo del DSR. Usando las funciones
probabilistic_sharpe,expected_max_sharpeydeflated_sharpedel módulo, tome el Sharpe neto del ejercicio 1 y calcule el DSR asumiendo N ∈ {1, 10, 100, 1.000} trials, con la asimetría y curtosis muestrales de sus retornos. ¿A partir de qué N el DSR cae por debajo de 0,95? Compare con el haircut de Harvey–Liu para 100 tests. - Simulación de costes Almgren–Chriss. Liquide 1.000.000 de acciones en un día (390 intervalos de 1 minuto) con σ = 0,02, η = 10⁻⁷ y λ ∈ {10⁻⁷, 10⁻⁶, 10⁻⁵}. Grafique las tres trayectorias \(x_j\), calcule la vida media θ = 1/κ de cada una y verifique numéricamente el límite TWAP cuando κT ≪ 1. Estime después el coste de impacto con la square-root law para Q/V_D ∈ {1 %, 5 %, 25 %} y Y = 0,6.
- Aritmética de rotación. Una estrategia de sentimiento rota el 100 % de la cartera diariamente, mitad en cortos sobre small-caps con borrow del 12 % anual. Calcule el drag anual total con 8 bps por lado de fricción (spread + comisión) y el borrow diario de la pierna corta. ¿Qué Sharpe bruto mínimo necesita la señal para un Sharpe neto de 1,0, asumiendo volatilidad anual del 15 %?
- Diseño de un RiskGateway. Extienda la clase
RiskGatewaydel módulo con: (a) límite de concentración por sector; (b) límite de participación de volumen (≤ 10 % del ADV del símbolo, estimado con la square-root law); (c) lista blanca de símbolos; (d) auto-kill si el slippage medio realizado de las últimas 50 órdenes supera en 2× al asumido en el backtest. Escriba los tests unitarios que demuestren que ninguna orden puede alcanzar el broker saltándose un límite, incluido el caso de un agente en bucle que emite 200 órdenes por minuto. - Auditoría de un paper. Elija uno de los papers de la tabla de la sección 9.1.1 y evalúelo contra los 10 puntos del checklist institucional: identifique qué puntos satisface, cuáles viola y qué experimento adicional mínimo sería necesario para que sus resultados fueran admisibles ante un comité de asignación. Presente sus conclusiones en una página con el formato evidencia → regla → conclusión.
Módulo 9 de 15 — LangChain para Trading Cuantitativo. Datos y versiones verificados a julio de 2026; precios y cifras de mercado sujetos a cambio. LangChain 1.3.14 / langchain-core 1.5.2.
Recursos de élite para seguir profundizando
- Lopez-Lira & Tang — Can ChatGPT Forecast Stock Price Movements? (arXiv 2304.07619): la señal LLM con mejor evidencia; lee el histórico de versiones — el Sharpe de GPT-4 pasó de 3,8 (v4) a 3,28 (v5), una lección de fragilidad en sí misma.
- Bailey, Borwein, López de Prado & Zhu — The Probability of Backtest Overfitting (arXiv 1401.0478): el marco CSCV/PBO completo, con la combinatoria IS/OOS que resume la sección 9.3.1.
- Yu et al. — FinMem (arXiv 2311.13743): memoria estratificada por horizonte temporal; léelo como patrón de arquitectura, no como estrategia.
- Yu et al. — FinCon (arXiv 2407.06567): jerarquía manager–analyst con refuerzo verbal y gating CVaR; notable por admitir alucinaciones de memoria en el propio paper.
- SEC — Rule 15c3-5, Market Access Rule (texto final, PDF): la fuente primaria del piso regulatorio de controles pre-trade; el origen del principio «el guardrail no se delega».
- FIX Trading Community — estándares FIX: especificación oficial del protocolo tag=value; para el día a día, el diccionario FIX 4.2 online es la referencia rápida de los mensajes
35=D/8/F/G. - nautilus_trader — documentación: la referencia del patrón de paridad backtest→live (mismo código, solo cambia la configuración) que exige la sección 9.3.1.
- ib_async — repositorio oficial: el sucesor mantenido de
ib_insyncpara Interactive Brokers; el stack Python vigente del ejemplo de bracket orders del módulo.
Comprueba lo aprendido
Autoevaluación con feedback inmediato. No se guarda ninguna puntuación: es solo para ti.