Contenido solo educativo, no asesoramiento financiero. El trading conlleva un riesgo sustancial de pérdida.
Referencia avanzada · Librerías y modelos de ML/IA · Trading algorítmico
Guía avanzada de trading con IA: La referencia completa de librerías, modelos y frameworks de ML para cuants
Un mapa de nivel profesional del ecosistema de código abierto y Hugging Face para el trading sistemático: gradient boosting, arquitecturas profundas de series temporales, modelos base zero-shot, PLN financiero, aprendizaje por refuerzo, el kit de validación de López de Prado, motores de backtesting y MLOps, con notas de arquitectura, licencias, benchmarks y código para cada uno.
Prueba gratuita de 5 días
Sin tarjeta requerida
Operaciones ilimitadas
Ejecución instantánea
👋
¿Nuevo en el trading con IA/ML? Esta página presupone fluidez en ML y Python y omite los fundamentos. Si prefieres empezar con la versión en lenguaje sencillo (qué es el meta-etiquetado, cómo encaja el pipeline, cómo automatizar la ejecución con PickMyTrade), lee la Guía de trading con IA para principiantes primero, y luego vuelve aquí.
01
ML clásico / tabular: los caballos de batalla
Los árboles de decisión con gradient boosting (GBDT), no las redes profundas, son la familia de modelos por defecto para cada tarea tabular de clasificación/regresión de este pipeline: meta-etiquetado, características de régimen, puntuación de factores. Una comparación de 2024 ampliamente citada sobre más de 100-300 benchmarks tabulares halló que los GBDT igualan o superan al deep learning en datos tabulares con mucho menos ajuste (arXiv:2402.03970). Los datos financieros tabulares son exactamente el régimen donde esto se cumple con más fuerza: baja relación señal-ruido, características mixtas continuas/categóricas/dispersas, fuerte no estacionariedad y tamaños de muestra efectivos pequeños, condiciones en las que la flexibilidad de las redes profundas compra sobre todo varianza, no señal.
Por qué los GBDT dominan en datos financieros tabulares
Compromiso sesgo-varianza. Con unos pocos miles de filas efectivas (ponderadas por unicidad) y una señal débil y ruidosa, la baja sesgo de una red de alta capacidad tiene un coste de varianza que no puedes permitirte. Los árboles poco profundos con fuerte regularización (número de hojas, min-data-in-leaf, bagging) se sitúan en un punto mucho mejor de ese compromiso.
Características mixtas y dispersas de forma nativa. Los árboles dividen sobre valores de características en bruto: sin escalado, sin estrategia de imputación, sin tabla de embeddings para categóricas poco pobladas (sector, exchange, indicador de proximidad al vencimiento). El esfuerzo de ingeniería de características va a la señal, no a la fontanería de preprocesamiento.
Las restricciones monótonas codifican priores financieros directamente. LightGBM/XGBoost/CatBoost admiten todos monotone_constraints: p. ej. forzar que P(ganancia) sea no decreciente en la fuerza de la tendencia y no creciente en la volatilidad realizada. Esto regulariza hacia modelos con sentido de dominio y no está disponible, o es mucho más engorroso, en un MLP estándar.
Valores faltantes y no estacionariedad. Los árboles enrutan los valores faltantes de forma nativa (sin imputación propensa a fugas ajustada sobre todo el conjunto de datos), y los árboles poco profundos y reentrenados con frecuencia se adaptan más rápido a los cambios de régimen que una red grande que necesita muchas épocas para desaprender patrones obsoletos.
Library
License
Maturity / stars*
Categorical handling
Speed
Best fit here
LightGBM
MIT
Mature · moved microsoft/LightGBM → lightgbm-org/LightGBM Mar 2026, still MIT
Native (histogram-based, leaf-wise growth)
Fastest of the three on CPU, large-N
Default meta-label / primary classifier
XGBoost
Apache-2.0
Mature, dmlc-maintained, huge ecosystem
Needs one-hot or target-encoding (or enable_categorical)
Slightly slower than LightGBM on CPU histogram mode
When you have many high-cardinality categoricals (symbol, sector, exchange)
scikit-learn
BSD-3-Clause
Foundational, ~19+ years
Via ColumnTransformer/OneHotEncoder
N/A — utility layer
CV splitters, metrics, pipelines, calibration, GMM — the glue, not the model
*Los recuentos de estrellas son orientativos, comprobados a mediados de 2026: trátalos como "orden de magnitud", no como cifras exactas.
LightGBM
MIT
Mecanismo: gradient boosting basado en histogramas con crecimiento del árbol por hojas (best-first) en lugar de por niveles: converge más rápido y normalmente a una pérdida menor que el crecimiento por niveles para un presupuesto de hojas dado, a costa de ser más propenso al sobreajuste en datos pequeños (contrólalo con num_leaves/min_data_in_leaf).
Cuándo usarlo: opción por defecto para el filtro de meta-etiqueta y cualquier clasificación/regresión tabular de este stack: entrenamiento en CPU más rápido, enrutamiento nativo de valores faltantes, restricciones monótonas nativas. Cuándo no: muestras muy pequeñas (< ~500 filas) donde el crecimiento por hojas sobreajusta rápido; prefiere XGBoost por niveles o una simple regresión logística ahí.
Python · Entrenamiento de meta-etiqueta con LightGBM sobre etiquetas de triple barrera
import lightgbm as lgb
from sklearn.model_selection import train_test_split
# X: one row per primary-strategy signal date. Columns e.g.
# log_ret_5d, log_ret_20d, realized_vol_20d, atr_14, frac_diff_price,
# ema_slope, rsi_14, bb_pctb, obv_z, dist_200ma
# y: triple-barrier label from mlfinpy -> 1 = profit barrier hit first, 0 = stop/time first
# w: sample weight from mlfinpy uniqueness/time-decay (NEVER plain 1s -- labels overlap)
X, y, w = features_df[feature_cols], labels_df["tb_label"], labels_df["sample_weight"]
X_train, X_val, y_train, y_val, w_train, w_val = train_test_split(
X, y, w, test_size=0.2, shuffle=False # never shuffle time series
)
params = {
"objective": "binary", "metric": "auc",
"num_leaves": 31, "learning_rate": 0.03,
"feature_fraction": 0.7, "bagging_fraction": 0.7, "bagging_freq": 5,
"min_data_in_leaf": 50,
# financial priors: e.g. [trend, vol, ...] -> win-prob non-decreasing in trend,
# non-increasing in realized vol, unconstrained (0) elsewhere
"monotone_constraints": [1, 0, -1, 0, 0, 1, 0, 0, 0, -1],
"verbosity": -1,
}
train_set = lgb.Dataset(X_train, label=y_train, weight=w_train)
val_set = lgb.Dataset(X_val, label=y_val, weight=w_val, reference=train_set)
model = lgb.train(params, train_set, num_boost_round=2000,
valid_sets=[val_set], callbacks=[lgb.early_stopping(100)])
meta_label_proba = model.predict(X_new) # P(this signal hits the profit barrier first)
XGBoost
Apache-2.0
Mecanismo: árboles con boosting por niveles (depth-wise) con un objetivo regularizado (L1/L2 sobre los pesos de las hojas) integrado en el propio criterio de búsqueda de divisiones, además de un algoritmo de división por histograma/quantile-sketch bien optimizado para datos grandes.
Cuándo usarlo: como un segundo modelo con sesgo distinto para hacer ensembling con LightGBM (el crecimiento por niveles vs. por hojas decorrelaciona los errores de forma útil); entrenamiento en GPU si superas la CPU. Cuándo no: si necesitas un manejo nativo de primera clase de las categóricas sin preprocesamiento; CatBoost es mejor ahí.
Mecanismo: ordered boosting (un esquema basado en permutaciones que evita la fuga de objetivo que sufre el clásico target-encoding voraz) más estadísticas de objetivo ordenadas nativas para características categóricas: sin paso de codificación manual y menos propenso al desplazamiento de predicción que el target encoding ingenuo.
Cuándo usarlo: modelos transversales de cestas de acciones con muchas características categóricas (sector, industria, exchange, indicadores de pertenencia a índices) donde de otro modo tendrías que hacer target encoding a mano. Cuándo no: presupuestos ajustados de tiempo de entrenamiento en CPU; CatBoost suele ser el más lento de los tres en ajustarse, aunque rápido en puntuar.
Su papel aquí: no una familia de modelos competidora, sino el tejido conectivo: Pipeline para el preprocesamiento dentro del fold sin fugas, GroupKFold/particionadores purgados personalizados, GaussianMixture para una línea base ligera de régimen, CalibratedClassifierCV para convertir las puntuaciones de GBDT en probabilidades honestas antes de dimensionar posiciones a partir de ellas (las salidas en bruto de GBDT ordenan bien pero están mal calibradas).
Calibra antes de dimensionar
La salida de predict_proba de un GBDT es una buena señal de ranking, pero normalmente no es una probabilidad bien calibrada de fábrica: los GBDT tienden a empujar las predicciones hacia 0/1. Si tu dimensionador de posición consume la "confianza" directamente (fractional-Kelly, tamaño escalado por meta-etiqueta), envuelve el modelo en sklearn.calibration.CalibratedClassifierCV (isotónica o Platt) ajustado dentro del fold de CV, o tu dimensionamiento tendrá un exceso de confianza sistemático.
02
Arquitecturas de series temporales con deep learning
Estas son las arquitecturas neuronales desde cero que entrenarías tú mismo (normalmente vía neuralforecast, Apache-2.0, que las implementa todas), a diferencia de los modelos base preentrenados de la §3. Todas ellas fueron evaluadas para su creación en M4/M3/electricity/traffic/ETT: ninguna se diseñó frente a series de retornos financieros, y el veredicto honesto por arquitectura lo refleja.
Architecture
Year / venue
Core idea
Problem vs. plain LSTM
Financial-data verdict
LSTM / GRU
1997 / 2014
Gated recurrent units carry a cell state across time steps to fight vanishing gradients.
— (baseline)
Still a reasonable baseline for sequence classification (e.g. regime state); rarely beats GBDT on tabular-framed return prediction and is slower to train/tune.
TCN
Bai et al. 2018
Stacked causal, dilated 1-D convolutions (WaveNet-style) give an exponentially growing receptive field with fully parallel training.
Parallelizable (no sequential recurrence) and avoids vanishing/exploding gradients over long lookbacks.
Solid, fast baseline in neuralforecast; no documented financial edge over GBDT, but useful when you specifically need a long causal receptive field cheaply.
N-BEATS
Oreshkin et al. 2020 (ICLR)
Pure fully-connected stacks with backward/forward residual "basis expansion" blocks; interpretable trend/seasonality decomposition, no recurrence or attention.
Much simpler and more parallel than RNN/attention stacks; beat the M4-competition winner by ~3% and a statistical benchmark by ~11%.
Benchmarks are M3/M4/tourism — non-financial. Useful as a fast, interpretable univariate baseline; not evidence of edge on returns.
N-HiTS
Challu et al. 2023 (AAAI)
Extends N-BEATS with hierarchical interpolation and multi-rate input sampling so different blocks specialize in different frequency bands.
Cuts long-horizon compute and reportedly beats Transformer baselines by >25% on long-horizon benchmarks.
Same caveat as N-BEATS — a strong long-horizon forecaster on benchmark data, unproven on financial returns specifically.
Temporal Fusion Transformer (TFT)
Lim et al. 2021 (Int. J. Forecasting)
LSTM encoder for local processing + interpretable multi-head self-attention for long-range dependencies + a variable-selection gating network that also yields feature-importance-like interpretability.
Natively handles static covariates, known-future inputs (e.g. expiry date), and produces quantile forecasts with built-in interpretability — none of which vanilla LSTM offers.
The most finance-plausible of the deep architectures because of native covariate support; still no peer-reviewed evidence of consistent OOS financial-return edge over GBDT meta-labeling.
Informer
Zhou et al. 2021 (AAAI, best paper)
ProbSparse self-attention selects only the top-scoring queries, cutting attention cost from O(L²) to O(L log L) for very long sequences.
Makes long-sequence (thousands of steps) transformer forecasting computationally tractable.
Designed for long-horizon benchmark forecasting, not noisy short-memory financial returns; see the DLinear caveat below.
Autoformer
Wu et al. 2021 (NeurIPS)
Replaces standard attention with an auto-correlation mechanism plus built-in series decomposition (trend/seasonal) between blocks.
Captures periodicity more directly than dot-product attention; more robust on strongly seasonal series.
Financial returns have weak/no reliable seasonality at daily/swing frequency — decomposition assumption is a weaker fit than on electricity/traffic data.
FEDformer
Zhou et al. 2022 (ICML)
Performs attention in the frequency domain (via Fourier/wavelet transforms) with a mixture-of-experts decomposition for trend.
Frequency-domain attention scales sub-quadratically and captures global periodic structure.
Same seasonality-dependence caveat as Autoformer; frequency-domain priors are a mismatch for near-random-walk return series.
PatchTST
Nie et al. 2023 (ICLR)
Splits each series into subseries "patches" as transformer tokens (like ViT for time series) and treats each channel independently, sharing one transformer backbone across all channels.
Patch tokenization retains local semantics and cuts attention cost quadratically vs. point-wise tokens; channel-independence avoids spurious cross-channel overfitting. Reported ~21% MSE reduction over prior transformer SOTA on long-horizon benchmarks.
The architectural basis for several foundation models below (see §3); channel-independence is a genuinely useful inductive bias, but the MSE gains are on ETT/weather/traffic, not equities.
iTransformer
Liu et al. 2024 (ICLR spotlight)
"Inverts" the standard transformer: each variate's whole time series becomes one token, and attention runs across variates instead of across time steps, with a per-series FFN handling temporal encoding.
Captures multivariate correlations directly via attention without modifying core transformer components; generalizes to unseen variate counts.
Notably, in a 2026 financial-return benchmark (arXiv:2606.27100, see §3), iTransformer beat the pretrained foundation models on META — a rare case of a from-scratch architecture outperforming zero-shot foundation models on a specific liquid single-name equity.
La advertencia de DLinear: léela antes de recurrir a cualquier transformer
Zeng et al., "Are Transformers Effective for Time Series Forecasting?" (AAAI-23 Oral; código: cure-lab/LTSF-Linear) demostraron que una sola capa lineal con descomposición de tendencia/estacionalidad (DLinear) superó a Informer, Autoformer y FEDformer en casi todos los benchmarks estándar de horizonte largo, argumentando que sus mejoras reportadas provenían sobre todo de la estrategia de entrenamiento directo multi-paso no autorregresivo, no de la atención en sí. El análisis de seguimiento de Hugging Face lo matizó en parte (los transformers con parámetros equiparados lo hacen mejor), pero la lección práctica se mantiene: evalúa siempre cualquier arquitectura profunda frente a una línea base lineal/ARIMA (Nixtla statsforecast, §11) antes de fiarte de una mejora de precisión impulsada por la complejidad. Esto es doblemente cierto en datos financieros, donde el ruido domina la señal mucho más que en datos de electricidad o tráfico.
03
Modelos base de series temporales en Hugging Face
Los pronosticadores de series temporales preentrenados y zero-shot son reales y útiles, para la volatilidad, no para la dirección del precio. Un estudio de junio de 2026 construido específicamente para probar esto, "Pretrained Time-Series Foundation Models for Financial Return Forecasting" (Noguer i Alonso y Pereira Franklin, AI Finance Institute), evaluó TimeGPT, TimesFM-2.5, Moirai-2.0, Chronos y Chronos-2 frente a NBEATS/NHITS/PatchTST/iTransformer/KAN desde cero sobre cinco acciones estadounidenses líquidas (AAPL, AMZN, GOOG, JPM, META) con un protocolo de origen móvil frente a un benchmark de paseo aleatorio. El resultado: entre diez combinaciones de activo/tarea, solo dos mostraron un rendimiento superior estadísticamente significativo frente al paseo aleatorio: Chronos en AMZN y Moirai-2.0 en GOOG, y los autores afirman llanamente que "las ganancias sobre el benchmark de paseo aleatorio son pequeñas y escasas", concluyendo que los TSFM son "priores prácticos útiles que reducen los costes de desarrollo de modelos", pero explícitamente "no motores universales para la generación de alpha estadísticamente fiable". Trata cada modelo de abajo en consecuencia: motores excelentes, ejecutables en CPU, para entradas de volatilidad/pronóstico de vol a una capa de dimensionamiento; débiles frente al paseo aleatorio para la dirección del precio.
Model
Org
Architecture family
Params
Context
License
Chronos / Chronos-Bolt
Amazon Science
T5-style encoder-decoder over quantized/tokenized values (Chronos) or direct patch-based multi-step regression heads (Bolt)
Masked-encoder transformer with "any-variate" attention (flattens multiple series into one token sequence so it natively handles arbitrary channel counts and covariates)
Small/Base/Large (14M–311M)
Flexible, any positive length
CC BY-NC-4.0
Lag-Llama
ServiceNow / Morgan Stanley / Mila et al.
LLaMA-style decoder-only transformer fed engineered lag features (not raw tokenized values) as its "vocabulary"
~2.45M (deliberately tiny)
Recommended 32–1024 pts, tunable
Apache-2.0
MOMENT
Auton Lab, CMU
Transformer trained multi-task (forecast + classify + detect anomalies + impute) on the "Time-series Pile" corpus
Small/Base/Large (~40M–341M)
Task-dependent
MIT
IBM Granite-TimeSeries (PatchTSMixer / PatchTST / TTM)
IBM Research
PatchTSMixer = all-MLP mixer over patches (no attention); PatchTST variant = patch-transformer; TTM = "Tiny Time Mixer," a very small pretrained mixer
PatchTSMixer ~1M (task head), TTM sub-5M
512-in / 96-out typical configs
Apache-2.0
Amazon Chronos / Chronos-Bolt
Apache-2.0 · 205M
Ficha del modelo:huggingface.co/amazon/chronos-bolt-base (la familia incluye también chronos-t5-{tiny,mini,small,base,large} y el más reciente amazon/chronos-2).
Arquitectura: el Chronos original tokeniza valores de series temporales escalados y cuantizados en un vocabulario fijo y los pasa por un codificador-decodificador T5 estándar, es decir, trata el pronóstico como modelado de lenguaje sobre un alfabeto numérico discretizado. Chronos-Bolt reemplaza la decodificación autorregresiva token a token por regresión directa multi-paso por parches, reportada como hasta ~250× más rápida y ~20× más eficiente en memoria con una precisión comparable o mejor (medida vía WQL/MASE en 27 conjuntos de datos de benchmark), entrenada con del orden de ~100.000 millones de observaciones de series temporales.
Veredicto: la mejor opción polivalente para una entrada de pronóstico de volatilidad solo en CPU: Apache-2.0, rápido, zero-shot, y el único modelo del benchmark 2606.27100 que alcanzó la significancia (en AMZN). Aun así: un resultado significativo de diez pruebas no es evidencia de una ventaja direccional repetible.
Python · pronóstico de volatilidad zero-shot con Chronos-Bolt
pip install chronos-forecasting torch
import torch
from chronos import BaseChronosPipeline
pipeline = BaseChronosPipeline.from_pretrained(
"amazon/chronos-bolt-base", # T5-style encoder-decoder, 205M params, Apache-2.0
device_map="cpu", # CPU is fine for daily-bar, small-batch inference
torch_dtype=torch.bfloat16,
)
# Feed REALIZED VOLATILITY, not raw price -- this is a vol forecaster, not an oracle
context = torch.tensor(realized_vol_20d.values[-512:])
quantiles, mean = pipeline.predict_quantiles(
context=context,
prediction_length=10, # 10-day-ahead vol forecast
quantile_levels=[0.1, 0.5, 0.9],
)
vol_forecast_median = quantiles[0, :, 1] # feed straight into GARCH/vol-target sizing (see §10)
Google TimesFM
Apache-2.0 · 200M/500M
Ficha del modelo:huggingface.co/google/timesfm-2.0-500m-pytorch (ICML 2024). Arquitectura: transformer solo decodificador entrenado para consumir parches de entrada de longitud fija (32 puntos) y emitir directamente parches de salida más largos (128 puntos), más cercano al objetivo de siguiente token de un modelo de lenguaje que al enfoque de valores tokenizados de Chronos, pero operando sobre embeddings de parches continuos en lugar de un vocabulario discretizado.
Veredicto: junto con Moirai-2.0, tuvo el rango medio más fuerte en el benchmark de cinco acciones (liderando en AAPL/JPM/GOOG/AMZN), pero según el propio planteamiento del paper, un rango fuerte ≠ una ventaja significativa; ninguna de las victorias de TimesFM superó el listón de significancia del paseo aleatorio. Bueno, bien mantenido, Apache-2.0, adecuado para volatilidad; no luz verde para la dirección del precio.
Ficha del modelo:huggingface.co/Salesforce/moirai-1.0-R-large. Arquitectura: transformer de codificador enmascarado con "any-variate attention": en lugar de un embedding fijo por canal, aplana un número arbitrario de variables (objetivos + covariables dinámicas/estáticas) en una sola secuencia de tokens, de modo que un único modelo preentrenado maneja de forma nativa cualquier tarea de pronóstico multivariante sin reentrenamiento por conjunto de datos. Moirai-MoE cambia la FFN densa por una capa de mezcla de expertos para una mejor especialización con un coste de inferencia similar.
Bloqueo de licencia: léelo antes de tocar esto en un sistema en vivo
Los pesos de Moirai y Moirai-MoE se publican bajo CC BY-NC 4.0, solo uso no comercial. Usarlos (incluso solo para inferencia) dentro de un sistema que gestiona tu propio capital de trading es discutiblemente un uso comercial y no está cubierto por esta licencia sin un acuerdo aparte con Salesforce. Chronos, TimesFM, Lag-Llama y MOMENT son Apache-2.0/MIT y no conllevan tal restricción: prefiere esos para cualquier cosa que toque capital en vivo. Moirai está bien solo para investigación/backtesting personal.
Veredicto: Moirai-2.0 produjo el otro resultado significativo del benchmark (GOOG) y empató con TimesFM en el rango medio más fuerte: técnicamente interesante, pero las reglas de licencia lo descartan de un pipeline en vivo en cualquier caso.
Lag-Llama
Apache-2.0 · ~2.45M
Ficha del modelo:huggingface.co/time-series-foundation-models/Lag-Llama. Arquitectura: un transformer solo decodificador estilo LLaMA, pero en lugar de alimentarlo con valores en bruto o parches, cada token de entrada es un vector de lag features clásicas (valores en t-1, t-2, t-7, t-30, ...) más covariables de fecha/hora, es decir, pone un transformer encima de una representación con ingeniería de características que recuerda al modelado autorregresivo clásico, deliberadamente mantenido diminuto (~2,45 M de parámetros) frente a las demás entradas aquí.
Veredicto: no forma parte directamente del benchmark 2606.27100, pero arquitectónicamente es el más cercano a una línea base autorregresiva "transparente" del grupo: una segunda opinión razonable para pronosticar volatilidad cuando quieres algo más pequeño/rápido que Chronos-Bolt/TimesFM, y sigue siendo Apache-2.0 sin problemas.
MOMENT
MIT · ~341M
Ficha del modelo:huggingface.co/AutonLab/MOMENT-1-large (ICML 2024; Auton Lab, Carnegie Mellon). Arquitectura: un único backbone transformer preentrenado multitarea en pronóstico, clasificación, detección de anomalías e imputación sobre el curado "Time-series Pile", lo que lo hace el más generalista del grupo en lugar de un especialista en pronóstico.
Cuándo usarlo: sus cabezas de detección de anomalías e imputación son posiblemente más diferenciadas para un pipeline de trading que su cabeza de pronóstico, p. ej. señalar velas intradía anómalas en una compuerta de calidad de datos, o imputar huecos en un feed de datos alternativos, más que como el pronosticador de volatilidad en sí. Licencia: MIT, sin restricción.
IBM Granite-TimeSeries
Apache-2.0
Ficha del modelo:huggingface.co/ibm-granite/granite-timeseries-patchtsmixer (véase también ibm-granite/granite-timeseries-patchtst y la línea "Tiny Time Mixer" TTM). Arquitectura: PatchTSMixer reemplaza la atención por completo con un MLP-Mixer sobre parches, sin ningún coste de atención cuadrática, reportando 2-3× menos memoria/tiempo de ejecución que los patch-transformers con una precisión comparable o mejor en benchmarks públicos de horizonte largo (p. ej. 0,37 de MSE en el pronóstico a 96 pasos de ETTh1).
Cuándo usarlo: la opción más barata de ejecutar aquí por un amplio margen (existen variantes TTM de menos de 5 M de parámetros): buena opción si quieres un componente de pronóstico de vol ligero, trivial en CPU, y no necesitas la generalidad zero-shot de Chronos/TimesFM. Licencia: Apache-2.0.
La política en una frase para toda esta sección
Usa cualquier modelo Apache-2.0/MIT de aquí como entrada de volatilidad/covariable a la capa de dimensionamiento determinista de la §10; no uses ninguno de ellos, incluidos los resultados significativos de Chronos/Moirai, como señal de entrada autónoma: los propios autores del benchmark 2606.27100 califican el efecto de "pequeño y escaso", e iTransformer (una arquitectura desde cero, §2) superó a todos los modelos base en META, subrayando que el preentrenamiento no es una ventaja universal en las series financieras.
04
PLN financiero y LLM
El sentimiento/PLN financiero pertenece a la capa de riesgo (una característica de veto/régimen), no a la capa de alpha: según la investigación fuente de la §0, la ventaja del sentimiento de noticias por sí sola es en gran medida un artefacto de anticipación que muere fuera de muestra. Aquí están los tres modelos que realmente vale la pena conocer.
FinBERT (ProsusAI)
Apache-2.0 · ~110M
Ficha del modelo:huggingface.co/ProsusAI/finbert (~7,5 M de descargas/mes en el momento de la investigación). Arquitectura: BERT-base (12 capas, 768 ocultas, 110 M de parámetros) preentrenado adicionalmente sobre un gran corpus financiero (Reuters TRC2) y luego ajustado para sentimiento de 3 clases sobre el Financial PhraseBank. Benchmark: 86 % de precisión en el Financial PhraseBank completo (97 % en el subconjunto de alta concordancia entre anotadores), unos 8 puntos por encima del BERT vanilla (arXiv:1908.10063).
Cuándo usarlo: puntuación de titulares al cierre como característica de veto de blackout de resultados / régimen bajista. Cuándo no: como señal de alpha autónoma, o en titulares extraídos a horizonte de 1 día donde los feeds institucionales ya han movido el precio.
Python · inferencia de sentimiento con FinBERT
pip install transformers torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch
tok = AutoTokenizer.from_pretrained("ProsusAI/finbert")
model = AutoModelForSequenceClassification.from_pretrained("ProsusAI/finbert")
model.eval()
headlines = ["Company X beats earnings estimates, raises guidance",
"Regulators open investigation into Company X"]
with torch.no_grad():
inputs = tok(headlines, return_tensors="pt", padding=True, truncation=True)
probs = torch.softmax(model(**inputs).logits, dim=-1)
# label order per config.id2label: 0=positive, 1=negative, 2=neutral
labels = ["positive", "negative", "neutral"]
scores = [dict(zip(labels, p.tolist())) for p in probs]
# aggregate to a daily sentiment score; use ONLY as a veto/regime feature, not alpha
FinGPT
MIT (code)
Repositorio:github.com/AI4Finance-Foundation/FinGPT. Arquitectura: no un modelo entrenado desde cero, sino una receta de ajuste fino LoRA (Low-Rank Adaptation) aplicada a LLM base abiertos (LLaMA2-7B/13B para FinGPT v3.2/v3.3, ChatGLM2-6B para v3.1). LoRA congela los pesos base y entrena en su lugar pequeñas matrices adaptadoras de bajo rango, reduciendo los parámetros entrenables de ~6,17 B a ~3,67 M: práctico para ajustar en una sola GPU de consumo.
Casos de uso: análisis de sentimiento financiero, Q&A estilo robo-advisor y experimentos de pronóstico usando señales ingeniadas por LLM (también la base de la pista de "señales ingeniadas por LLM" de FinRL Contest). Matiz de licencia: el código de entrenamiento/inferencia de FinGPT es MIT, pero los pesos base subyacentes de LLaMA conllevan los propios términos de licencia comunitaria de Meta: compruébalos por separado antes de cualquier despliegue comercial de un checkpoint ajustado.
FinBERT-tone
Apache-2.0 · ~110M
Ficha del modelo:huggingface.co/yiyanghkust/finbert-tone (Huang, Wang y Yang, Contemporary Accounting Research 2022). Arquitectura: también BERT-base (12 capas / 768 ocultas / 12 cabezas), pero entrenado sobre un linaje de corpus diferente: preentrenado sobre texto de 10-K/10-Q/earnings calls y luego ajustado sobre 10.000 frases de informes de analistas anotadas manualmente, lo que le da un comportamiento de clasificación de tono algo distinto al del FinBERT de ProsusAI pese al nombre similar.
Cuándo usarlo: una segunda opinión de sentimiento entrenada de forma distinta para hacer ensembling con FinBERT específicamente sobre texto de informes de analistas o earnings calls (en lugar de titulares de noticias generales).
05
Aprendizaje por refuerzo para trading
El RL es el elemento más sobrevalorado y menos fiable de toda esta página para un motor de trading principal. El instrumental es genuinamente bueno; el veredicto honesto, respaldado por el propio concurso de benchmark de la comunidad de RL, es confinarlo a subproblemas estrechos y estrictamente validados (p. ej. el momento de ejecución) en lugar de un motor principal o a nivel de cartera.
Dynamic market-environment and dataset layer for FinRL (hundreds of market simulators)
Active, smaller community (~1–2k★)
Stable-Baselines3
MIT
Reliable, well-tested implementations of the underlying RL algorithms (PPO, SAC, DQN, A2C, TD3, DDPG, HER) that FinRL wraps
Actively maintained, the de facto standard PyTorch RL library
TensorTrade
Apache-2.0
RL trading-environment framework (Gym-style)
Maintenance stalled — a community fork, TensorTrade-NG, was created explicitly because the original "needed a lot of refactoring, was outdated, and looked not really maintained." Treat as unmaintained for planning purposes.
Las cuatro familias de algoritmos (una línea cada una)
PPO (Proximal Policy Optimization): on-policy, acciones discretas o continuas; recorta el paso de actualización de la política para mantenerse cerca de la política anterior, sacrificando algo de eficiencia de muestra por estabilidad de entrenamiento. La primera opción por defecto en la mayoría de ejemplos de FinRL.
SAC (Soft Actor-Critic): off-policy, solo acciones continuas; objetivo de máxima entropía (premia explícitamente la exploración) con un búfer de repetición, generalmente más eficiente en muestra que PPO pero más sensible a los hiperparámetros.
DQN (Deep Q-Network): off-policy, solo acciones discretas; aprende una función de valor de acción mediante un búfer de repetición y una red objetivo. Necesita un espacio de acción discretizado (p. ej. comprar/mantener/vender), lo que encaja mal con el dimensionamiento continuo de posición.
A2C (Advantage Actor-Critic): on-policy, discreto o continuo; un primo más simple y síncrono de A3C, generalmente el más débil de los cuatro en tareas financieras en los propios benchmarks de FinRL.
Por qué el RL es concretamente frágil para el trading, no solo "difícil"
Panorama de recompensa no estacionario: la función de valor de un agente de RL se aprende frente a un régimen histórico específico; cuando el régimen cambia (como hacen constantemente los mercados financieros), la política aprendida optimiza para una superficie de recompensa que ya no existe. A diferencia de un meta-etiquetador GBDT reentrenado, no hay un arreglo simple de "reajustar sobre la última ventana" para una red de política sin arriesgar un olvido catastrófico. Ineficiencia de muestra: el RL profundo suele necesitar millones de interacciones con el entorno para converger; tú tienes exactamente una historia no repetible del mercado, así que "más datos" significa o bien simulación (que codifica tus propias suposiciones como verdad absoluta) o años de espera adicional de reloj. Reward-hacking en los backtests: un agente que optimiza el PnL simulado acumulado aprenderá con gusto a explotar las peculiaridades del simulador (suposiciones de ejecución irreales, impacto de mercado nulo, redondeo exacto del motor de backtest) en lugar de una verdadera ventaja de mercado, precisamente el modo de fallo que documenta el artículo de FinRL Contests (arXiv:2504.02281): los agentes enviados con una alta probabilidad de sobreajuste al backtest son explícitamente rechazados a un nivel de significancia del 10 % por los propios organizadores del concurso; las personas que construyen el ecosistema de trading con RL consideran que la mayoría de los agentes de trading con RL enviados son estadísticamente indistinguibles del ruido sobreajustado por defecto.
Alcance práctico, si usas RL en absoluto: un subproblema estrecho con una recompensa naturalmente en forma de MDP (p. ej. el momento de ejecución de órdenes dentro de una orden padre fija, seguimiento de VWAP), evaluado con la misma disciplina de PBO/DSR que todo lo demás en la §14, nunca como el motor principal de entrada/salida/dimensionamiento.
06
Pipelines completos de ML cuant: Microsoft Qlib
Qlib es lo más parecido a una plataforma de investigación IA-cuant llave en mano en código abierto: una capa de datos, un DSL de ingeniería de características, un zoo de modelos y un arnés de backtest walk-forward/análisis de cartera, conectados entre sí mediante configuraciones de flujo de trabajo YAML. Licencia MIT (microsoft/qlib), decenas de miles de estrellas en GitHub, MIT desde su apertura en septiembre de 2020, con lanzamientos activos (v0.9.7, agosto de 2025) y ahora emparejado con RD-Agent de Microsoft para experimentación automatizada de bucles de investigación.
Alpha158 vs. Alpha360: los dos conjuntos de características integrados
Raw normalized OHLCV history flattened over a 60-day lookback (6 fields × 60 days = 360 columns), essentially no feature engineering
Feature relationships
Low spatial/temporal structure between columns — a classic tabular feature matrix
Strong spatial-temporal structure — designed for models that learn their own representation from raw sequences
Best-paired models
LightGBM, XGBoost, CatBoost, linear/MLP models
GRU, LSTM, Transformer-family, ALSTM, GATs — sequence models that benefit from raw structure
Sistema de flujo de trabajo/configuración y zoo de modelos integrado
Los experimentos de Qlib se conducen normalmente mediante un único archivo YAML consumido por la CLI qrun, que declara el manejador de datos (Alpha158/360 o personalizado), el modelo, la división del conjunto de datos, la estrategia de cartera y los parámetros de backtest: esto hace que cambiar LightGBM por un GRU o un wrapper de TFT sea un cambio de configuración de una línea, no una reescritura. El zoo de modelos integrado abarca enfoques clásicos y profundos: LGBModel (LightGBM), XGBModel, CatBoostModel, MLP, GRU/LSTM/ALSTM (recurrentes), Transformer, wrapper de TFT, TabNet, HIST, IGMTF y varios modelos de investigación de grafos/atención (GATs, KRNN, Localformer), todos entrenados y evaluados a través del mismo arnés de flujo de trabajo con un informe compartido de backtest walk-forward/análisis de IC.
YAML · configuración mínima de flujo de trabajo de Qlib (LightGBM sobre Alpha158)
qlib_init:
provider_uri: "~/.qlib/qlib_data/custom_nse" # see note below on pointing Qlib at NSE data
region: in # generic region tag; India isn't a stock Qlib region out of the box
market: &market custom_nse_500
benchmark: &benchmark NIFTY500
data_handler_config: &data_handler_config
start_time: 2010-01-01
end_time: 2025-12-31
fit_start_time: 2010-01-01
fit_end_time: 2019-12-31
instruments: *market
task:
model:
class: LGBModel
module_path: qlib.contrib.model.gbdt
kwargs:
loss: binary
num_leaves: 31
learning_rate: 0.03
monotone_constraints: [1, 0, -1, 0]
dataset:
class: DatasetH
module_path: qlib.data.dataset
kwargs:
handler:
class: Alpha158
module_path: qlib.contrib.data.handler
kwargs: *data_handler_config
segments:
train: [2010-01-01, 2019-12-31]
valid: [2020-01-01, 2021-12-31]
test: [2022-01-01, 2025-12-31]
# run with: qrun this_config.yaml
Apuntar Qlib a datos personalizados (p. ej. NSE)
Qlib incluye proveedores de datos de EE. UU. y China de fábrica; NSE/BSE requiere que construyas tu propio almacén de datos binario con scripts/dump_bin.py, alimentándolo con archivos Parquet/CSV de OHLCV point-in-time que ya hayas ensamblado (según la disciplina del plan de datos libre de sesgo de supervivencia). También necesitarás un calendario de trading personalizado (los festivos de NSE difieren de los de NYSE/China) y registrar tu archivo de universo de instrumentos: la capa de datos de Qlib es agnóstica al formato una vez convertida, así que Alpha158/360 y todo el zoo de modelos funcionan sin modificaciones sobre datos de NSE una vez hecho el paso de volcado.
07
Métodos de ML financiero de López de Prado: mlfinpy y skfolio
El conjunto de herramientas de Advances in Financial Machine Learning de López de Prado solía significar una licencia de pago de mlfinlab: ya no. Dos paquetes gratuitos y con licencia permisiva cubren ahora el etiquetado de triple barrera, el meta-etiquetado, la diferenciación fraccional, la ponderación de unicidad de muestras, CPCV y HRP.
Package
License
Covers
mlfinpy
MIT
Triple-barrier labeling, meta-labeling, fractional differentiation, sample-weight/uniqueness utilities — a modern Pythonic re-implementation of the AFML code snippets
skfolio
BSD-3-Clause
scikit-learn-compatible portfolio optimization and model selection: CombinatorialPurgedCV out of the box, plus HRP, HERC, risk-budgeting, CVaR/CDaR optimization
mlfinlab (paid)
Commercial
The original, packaged, paid version — only worth it if you specifically want Hudson & Thames' maintained extras beyond what the two free packages cover
Python · etiquetado de triple barrera con mlfinpy
pip install mlfinpy
from mlfinpy.labeling import get_events, add_vertical_barrier, get_bins
from mlfinpy.util import get_daily_vol
# causal, EWMA-based daily volatility -- uses data strictly up to t, no leakage
daily_vol = get_daily_vol(close=prices, lookback=50)
vertical_barriers = add_vertical_barrier(
t_events=signal_dates, close=prices, num_days=10 # time-limit barrier
)
triple_barrier_events = get_events(
close=prices,
t_events=signal_dates, # your primary (Pine) strategy's signal dates
pt_sl=[2.0, 1.5], # profit-take / stop-loss as multiples of daily_vol
target=daily_vol,
min_ret=0.0005,
num_threads=4,
vertical_barrier_times=vertical_barriers,
)
labels = get_bins(triple_barrier_events, prices)
# labels['bin'] -> 1 = profit barrier hit first, 0 = stop/time barrier hit first
# labels['ret'] -> realized return at the barrier that was hit
# labels['t1'] -> the barrier-touch timestamp (needed for purging downstream)
Python · CombinatorialPurgedCV de skfolio para el modelo de meta-etiqueta
pip install skfolio
from skfolio.model_selection import CombinatorialPurgedCV, cross_val_predict
from sklearn.pipeline import Pipeline
import lightgbm as lgb
meta_label_pipeline = Pipeline([
("model", lgb.LGBMClassifier(num_leaves=31, learning_rate=0.03,
min_child_samples=50)),
])
# n_folds=10, n_test_folds=2 -> C(10,2) = 45 combinatorial train/test paths
# purged_size / embargo_size sized to the max holding horizon (t1 - t0), NOT a flat 1%
cv = CombinatorialPurgedCV(n_folds=10, n_test_folds=2,
purged_size=10, embargo_size=10)
# returns an empirical DISTRIBUTION of out-of-sample paths, not one score --
# use it to compute PBO and the Deflated Sharpe Ratio, not a single train/test split
oos_paths = cross_val_predict(estimator=meta_label_pipeline, X=X, y=y,
cv=cv, sample_weight=w)
Qué te aporta cada técnica
Diferenciación fraccional (mlfinpy.features.frac_diff / variante FFD de ancho fijo): halla el orden mínimo de diferenciación d (a menudo 0,2-0,5) que pasa un test de estacionariedad ADF conservando una correlación >0,9 con la serie de niveles, dando una entrada estacionaria que conserva memoria: estrictamente mejor para modelos de árbol/lineales que los retornos en bruto (memoria cero) o el precio en bruto (no estacionario).
Ponderación de unicidad de muestras: las etiquetas de triple barrera se solapan en el tiempo (un periodo de mantenimiento de 10 días significa que señales adyacentes comparten ventanas de etiqueta), violando la suposición IID en la que se basa la mayoría de la teoría de ML. Pondera cada muestra por su unicidad media (inverso del recuento de etiquetas concurrentes) más decaimiento temporal, o tu tamaño de muestra efectivo será una fracción de tu recuento de filas y cada test de significancia posterior estará sobrestimado.
Validación cruzada purgada combinatoria (CPCV): genera muchas combinaciones de rutas train/test (no una sola ruta walk-forward), purga las filas de entrenamiento cuya ventana de etiqueta se solapa con el fold de test, y aplica un embargo de margen tras cada fold de test. Produce una distribución completa de ratios de Sharpe fuera de muestra (que alimenta PBO y DSR) en lugar de una estimación puntual: por eso es estructuralmente más fiable que el walk-forward simple.
HRP (Hierarchical Risk Parity) (skfolio.optimization.HierarchicalRiskParity): asigna mediante agrupamiento jerárquico de la matriz de correlación en lugar de invertir una matriz de covarianza ruidosa (lo que hace la optimización media-varianza), lo que lo hace mucho más robusto al error de estimación en una cesta de acciones correlacionadas.
08
Detección de regímenes: hmmlearn y ruptures
Esta es la sección donde vive el error de fuga silenciosa más común en el gating de régimen minorista, y donde mostrar el patrón equivocado junto al correcto es más útil que describirlo en prosa.
Library
License
Maturity
Role
hmmlearn
BSD
Mature, scikit-learn-style API, ~3k★
Gaussian/GMM/Categorical HMMs for a discrete calm/stormy regime state
ruptures
BSD-2-Clause
Mature, academic (ENS Paris-Saclay/CNRS)
Offline changepoint detection — PELT (exact, linear-cost, unknown number of changes), binary segmentation (BinSeg, greedy/approximate), and sliding-window methods
El error de anticipación silencioso número 1: decodificación HMM suavizada de muestra completa
La forma por defecto y más fácil de llamar a hmmlearn (ajustar GaussianHMM sobre todo tu historial y luego llamar a .predict() para obtener las etiquetas de régimen) usa por debajo la decodificación Viterbi/suavizada. La etiqueta de régimen en el tiempo t se elige usando la secuencia completa, incluyendo todo lo posterior a t. La compuerta "sabe" efectivamente que se acerca una crisis antes de que ocurra. Cada cifra deslumbrante publicada de reducción de drawdown con HMM (56 %→24 % de DD máximo, etc.) que no controle explícitamente esto está muy probablemente construida así. Abajo: el patrón con fugas, y el patrón causal, walk-forward, de posterior filtrada que sí es desplegable.
Python · INCORRECTO: decodificación suavizada de muestra completa con fugas (no desplegar)
from hmmlearn.hmm import GaussianHMM
model = GaussianHMM(n_components=2, covariance_type="diag", n_iter=1000)
model.fit(X_full) # fit on the ENTIRE history -- future leaks into the fit
regimes = model.predict(X_full) # Viterbi = globally-smoothed decode over the whole path
# regimes[t] used information from t+1 ... T. This is look-ahead bias.
# Any backtest of a regime gate built this way is invalid and will not reproduce live.
Python · CORRECTO: compuerta de régimen causal, walk-forward, de posterior filtrada
from hmmlearn.hmm import GaussianHMM
import numpy as np
regime_at_t = np.full(len(X), np.nan)
model, refit_every, min_train = None, 63, 500 # e.g. refit quarterly
for t in range(min_train, len(X)):
if model is None or t % refit_every == 0:
model = GaussianHMM(n_components=2, covariance_type="diag", n_iter=200)
model.fit(X[:t]) # ONLY data strictly before t
# forward-algorithm FILTERED posterior using data up to and including t --
# no smoothing, no future information, no re-fit on data that includes t's label use
posteriors = model.predict_proba(X[:t + 1])
regime_at_t[t] = posteriors[-1].argmax() # today's regime, knowable today
# regime_at_t is safe to merge into the feature frame for both backtest and live use.
# Expect a MUCH smaller, laggier drawdown benefit than the full-sample-smoothed version --
# that gap IS the size of the leakage bug you just closed.
ruptures es la herramienta complementaria cuando quieres puntos de cambio en lugar de un estado de régimen persistente, p. ej. señalar una ruptura de régimen de volatilidad en una serie EWMA para disparar un reajuste del HMM, o como detector alternativo de límites de régimen para contrastar las transiciones del HMM. Pelt (búsqueda exacta de coste lineal, número desconocido de puntos de ruptura, necesita un parámetro de penalización) es el predeterminado; Binseg sacrifica exactitud por velocidad en series más largas; los métodos basados en ventana son los más baratos pero los menos precisos en rupturas sutiles. Como el HMM, ejecútalo en una ventana expansiva/móvil para uso en vivo: la API estándar de ruptures también es un método offline de serie completa por defecto.
09
Motores de backtesting y ejecución
Ningún motor único es el adecuado para cada etapa. Usa un motor vectorizado para cribar miles de combinaciones de parámetros, y luego revalida cada superviviente en un motor basado en eventos con ejecuciones realistas antes de arriesgar capital: confundir las dos etapas (confiar en un backtest de motor vectorizado como tu respuesta final) es un error común y caro.
Engine
Speed
Fill realism
License
Maintenance
Best-fit use case
vectorbt (community)
Extremely fast (Numba-vectorized, thousands of configs at once)
Weak — vectorized fills, easy to fool yourself
Apache-2.0 + Commons Clause
Community edition maintenance-frozen; active dev moved to paid vectorbtPRO
Fast first-pass parameter sweep / triage only
backtrader
Moderate (pure Python, event-driven)
Moderate (configurable slippage/commission, but manual)
GPL-3.0
Stalled ~2021 — open PRs/issues unmerged for years
Legacy strategies only; don't start new work here
Zipline-reloaded
Moderate
Good (Quantopian-derived fill/slippage models)
Apache-2.0
Community-maintained fork (stefan-jansen), modest but real activity
Research backtests wanting the original Zipline/Quantopian API and pipeline model
NautilusTrader
Fast (Rust core)
High — same strategy code path for backtest and live
LGPL-3.0-or-later
Very active, ~24k★, production-grade
Final realistic-fill re-validation and the bridge to live — the one tool built for research-to-live parity
QuantConnect LEAN
Fast (C#/.NET core, Python API)
High — institutional-grade fill/slippage/margin models
Apache-2.0
Very active, ~19k★, backs a commercial cloud platform
Full-featured alternative to NautilusTrader, especially with QuantConnect's hosted data/cloud/live options
bt
Moderate
Moderate (higher-level "Algo" abstraction over vectorized fills)
MIT
Actively maintained (releases into 2026)
Fast, readable portfolio-level (multi-asset allocation) backtests, less suited to per-trade microstructure realism
backtesting.py
Fast (single-asset, vectorized-ish)
Basic (simple slippage/commission model)
AGPL-3.0
Active, small footprint, ~2.4k★
Quick single-asset prototyping only — AGPL is a real constraint if you build a hosted/SaaS product on it
Por qué la arquitectura de NautilusTrader realmente importa
La mayoría de los fracasos de "gran backtest, real decepcionante" no son fallos del modelo: son bugs de sesgo entre investigación y producción: tu motor de backtest y tu código de ejecución en vivo son dos bases de código separadas que se separan silenciosamente (una suposición de precio de ejecución aquí, un bug de timing de vela por uno allá), y nada las obliga a mantenerse consistentes. El diseño basado en eventos con núcleo en Rust de NautilusTrader ejecuta el mismo código de estrategia (las mismas clases, los mismos manejadores de eventos) en modo backtest, paper y en vivo; solo cambian los adaptadores de datos/ejecución. Esa elección arquitectónica elimina toda una clase de bugs por construcción en lugar de por disciplina, por lo que es la herramienta adecuada para el papel de "revalidación final con ejecución realista y puente a producción" en lugar de un lujo prescindible.
Nota de licencia: LGPL-3.0, no GPL
NautilusTrader es LGPL-3.0-or-later, no la más estricta GPL-3.0 que rige backtrader y freqtrade. LGPL permite enlazar/usar la librería desde código propietario sin liberar tu código de estrategia, siempre que las modificaciones al propio NautilusTrader (si las hay) se compartan de vuelta: materialmente menos restrictivo que una dependencia GPL directa para un sistema de trading de código cerrado. Aun así, confirma los términos de licencia actuales en el repositorio antes de un despliegue comercial.
10
Construcción de carteras y riesgo
Aquí es donde el "control de drawdown" se implementa realmente: como matemática determinista que consume pronósticos de volatilidad y confianza de meta-etiqueta, no como otra tarea de predicción.
Library
License
Role
PyPortfolioOpt
MIT
Classical mean-variance / efficient frontier, Black-Litterman, shrinkage covariance estimators, and HRP — the most approachable API of the three
Riskfolio-Lib
BSD-3-Clause
Deeper risk-based allocation: HRP/HERC, ~24 risk measures including CVaR/CDaR/EVaR, risk-parity/risk-budgeting, built on CVXPY convex optimization
arch
NCSA
GARCH/EGARCH/GJR-GARCH/TARCH volatility-family models — the standard econometric volatility forecaster feeding vol-targeted sizing
Python · pronóstico de volatilidad GJR-GARCH → tamaño de posición con objetivo de vol (arch)
pip install arch
from arch import arch_model
import numpy as np
returns_pct = 100 * log_returns.dropna() # arch expects % returns for numerical stability
# GJR-GARCH(1,1,1) with Student-t errors -- captures the leverage effect (vol reacts more to
# negative returns than positive ones), which plain GARCH(1,1) misses
am = arch_model(returns_pct, vol="GARCH", p=1, o=1, q=1, dist="t")
res = am.fit(disp="off", last_obs=train_end_date) # fit only on data up to the current date
fcast = res.forecast(horizon=10, reindex=False)
vol_forecast_daily = np.sqrt(fcast.variance.values[-1]) / 100 # back to decimal daily vol
target_vol_daily = 0.10 / (252 ** 0.5) # ~10% annualized portfolio vol target
position_scale = target_vol_daily / vol_forecast_daily[0]
position_size = base_size * min(position_scale, max_leverage_cap) # always cap leverage
PyPortfolioOpt
MIT
Cuándo usarlo: asignación rápida HRP o de covarianza con shrinkage sobre una cesta sin arrastrar un stack completo de dependencias de optimización convexa. Cuándo no: si necesitas objetivos CVaR/CDaR o medidas de riesgo más exóticas; ese es el trabajo de Riskfolio-Lib.
Python · asignación HRP
from pypfopt import HRPOpt
hrp = HRPOpt(returns=daily_returns_df) # NOT prices -- pass returns
weights = hrp.optimize() # hierarchical-clustering-based, no covariance inversion
Riskfolio-Lib
BSD-3
Cuándo usarlo: siempre que el objetivo sea explícitamente consciente del riesgo de cola (CVaR/CDaR) en lugar de la varianza: mejor encaje para un mandato de "mínimo drawdown" que la media-varianza.
Python · cartera óptima CVaR
import riskfolio as rp
port = rp.Portfolio(returns=daily_returns_df)
port.assets_stats(method_mu="hist", method_cov="hist")
weights = port.optimization(model="Classic", rm="CVaR", obj="MinRisk", rf=0, l=0)
11
Ingeniería de características y utilidades de pronóstico
Antes de fiarte de cualquier resultado de GBDT o de un modelo base, compáralo con la línea base aburrida. Estas dos librerías cubren la extracción automatizada de características y las líneas base de pronóstico clásicas que nunca deberías saltarte.
Library
License
Role
tsfresh
MIT
Automated extraction of hundreds of statistical/signal-processing time-series features, with a built-in hypothesis-testing-based relevance filter (the "FRESH" algorithm) to control false-discovery rate on the feature explosion
Nixtla statsforecast
Apache-2.0
Fast classical/econometric baselines — AutoARIMA, AutoETS, AutoCES, Theta — the mandatory benchmark before believing any ML "edge"
Nixtla mlforecast
Apache-2.0
Machine-learning forecasting at scale (pandas/polars/Spark/Dask/Ray backends) with the same lag-feature-engineering plumbing regardless of backend
Nixtla neuralforecast
Apache-2.0
30+ neural architectures under one API — every model in §2 (NBEATS, NHITS, TFT, Informer, Autoformer, FEDformer, PatchTST, iTransformer, TimeLLM, ...) available without hand-rolling each paper's code
Python · extracción de características automatizada + filtrada con tsfresh
pip install tsfresh
from tsfresh import extract_relevant_features
# long-format df: columns [id, time, value]; y indexed by id (e.g. triple-barrier label)
features = extract_relevant_features(
long_format_df, y=labels_by_id, column_id="id", column_sort="time",
fdr_level=0.01, # false-discovery-rate control -- do NOT skip this on financial data
)
# re-run the relevance filter INSIDE each CV fold in production, never on the full dataset
Python · línea base obligatoria antes de fiarte de la "ventaja" de cualquier modelo
pip install statsforecast
from statsforecast import StatsForecast
from statsforecast.models import AutoARIMA, AutoETS
sf = StatsForecast(models=[AutoARIMA(), AutoETS()], freq="D", n_jobs=-1)
sf.fit(train_df)
baseline_forecast = sf.predict(h=10)
# your GBDT / foundation-model forecast must beat THIS, net of cost, or there is no edge
12
MLOps para un sistema de trading en vivo
El instrumental de MLOps aquí no va de escala: va de honestidad. La función de MLOps más determinante de todo este stack es la disciplina de recuento de pruebas para el Deflated Sharpe Ratio: cada configuración de backtest que hayas probado, registrada, para siempre, de modo que la corrección por pruebas múltiples se calcule frente a tu recuento de pruebas real, no el subconjunto halagador que recuerdas.
Tool
License
Role
When to adopt
MLflow
Apache-2.0
Experiment tracking (params/metrics/artifacts) + model registry with stage transitions
Early — every single backtest run, from day one, feeds the DSR trial count
Once a strategy is running on a schedule against live data
NannyML
Apache-2.0
Label-free live performance estimation — CBPE for classifiers, DLE for regressors — estimates real-world accuracy before ground-truth labels are even available
Once paper/live trading is running and labels arrive with a lag (exactly the triple-barrier situation)
Prefect
Apache-2.0
Pythonic pipeline orchestration: scheduling, retries, caching, event-driven triggers for the nightly ingest→feature→predict→size→alert DAG
Once a plain cron script becomes unwieldy — not needed for an MVP
Dagster
Apache-2.0
Alternative orchestrator with stronger data-asset lineage/typing — heavier but better observability at scale
If you outgrow Prefect's simplicity and want asset-level lineage across many pipelines
Python · registro con MLflow que realmente impone la disciplina de recuento de pruebas del DSR
pip install mlflow
import mlflow
with mlflow.start_run(run_name="lgbm_meta_label_v37"):
mlflow.log_params(params) # every hyperparameter tried
mlflow.log_param("cv_scheme", "CombinatorialPurgedCV(10,2)")
mlflow.log_param("feature_set_hash", feature_set_hash) # so re-used feature sets don't double count
mlflow.log_metric("oos_sharpe_median", oos_sharpe_median) # across the CPCV path distribution
mlflow.log_metric("pbo", pbo_value)
mlflow.log_metric("trial_number_in_family", trial_counter) # THIS feeds the Deflated Sharpe N
mlflow.lightgbm.log_model(model, "model")
# Query the full run history to compute N for the Deflated Sharpe Ratio -- include prior
# Pine-Script optimization trials too (see §14), not just the ML runs.
Por qué esto es innegociable, no un lujo prescindible
El Deflated Sharpe Ratio necesita un recuento honesto de cada configuración que hayas probado alguna vez contra estos datos, no solo el modelo final. Sin un sistema de registro, el recuento de pruebas se reconstruye de memoria en el momento exacto en que más motivado estás para subestimarlo. MLflow (o un equivalente) convierte "cuántas cosas probé realmente" de una conjetura autoinformada en un hecho consultable.
13
Datos y conjuntos de datos alternativos en Hugging Face
Más allá de los hubs de modelos, el Datasets Hub de Hugging Face alberga un conjunto creciente de datasets relevantes para las finanzas que vale la pena conocer para prototipado y trabajo de sentimiento: trátalos todos como fuentes de prototipado/respaldo, no como datos de producción libres de sesgo de supervivencia (véase la disciplina del Plan de Datos en el informe de investigación fuente).
Labeled Twitter/X financial and crypto sentiment — useful for fine-tuning or validating a FinBERT-style veto filter
huggingface.co/datasets?search=finance
Hub search
The Hub's finance-tagged dataset list changes frequently — always re-search rather than trusting a static list; verify licensing per-dataset before any commercial use
Numerai: un juego diferente, no una fuente de datos para tu propio sistema
Numerai se entiende mejor como un mercado de habilidad de modelado, no como un dataset para enchufar a tu propio pipeline. El torneo principal ofrece características gratuitas, preprocesadas y ofuscadas: con PCA, z-scored y segmentadas en el tiempo para que puedas modelar datos financieros de clase mundial sin saber nunca qué acciones o fechas estás mirando (cada "era" semanal tiene IDs que no se corresponden entre eras, por diseño). Numerai Signals es el producto complementario: envías predicciones sobre tu propio universo/características, buscando señales ortogonales a lo que el stack de modelos existente de Numerai ya captura. Todos los modelos enviados alimentan un meta-modelo ponderado por stake que a su vez impulsa el propio hedge fund de Numerai. Enmárcalo como opcionalidad para monetizar la habilidad de modelado (evaluado sobre rendimiento plurianual e inclusivo de drawdown, no como una vía rápida hacia ingresos) y como un ecosistema adyacente interesante en lugar de un componente del pipeline de la §14.
14
Arquitectura de referencia: pipeline completo
Cómo un usuario avanzado conecta cada librería anterior en un solo pipeline, de principio a fin. Ingesta de datos → características de Qlib/tsfresh → diferenciación fraccional (mlfinpy) → modelo de meta-etiqueta LightGBM validado con validación cruzada purgada combinatoria anidada (skfolio) → compuerta de régimen causal con hmmlearn → dimensionamiento con objetivo de vol basado en GARCH (arch) → backtest con NautilusTrader → registro con MLflow → webhook de PickMyTrade para la ejecución.
Cada flecha es un traspaso de datos entre una librería intercambiable de forma independiente: ninguna etapa depende de una elección específica en otra.
Python · esqueleto del pipeline de referencia de principio a fin
"""
Reference pipeline skeleton: data ingestion -> PickMyTrade execution.
Every preprocessing step is fit INSIDE the CPCV training fold only -- never on
the full dataset. Illustrative structure; wire in your own data store / config.
"""
import numpy as np
import pandas as pd
import lightgbm as lgb
import mlflow
import requests
from hmmlearn.hmm import GaussianHMM
from arch import arch_model
from mlfinpy.labeling import get_events, add_vertical_barrier, get_bins
from mlfinpy.util import get_daily_vol
from mlfinpy.features import frac_diff_ffd
from skfolio.model_selection import CombinatorialPurgedCV, cross_val_predict
from sklearn.pipeline import Pipeline
from qlib.contrib.data.handler import Alpha158
from tsfresh import extract_relevant_features
from nautilus_trader.backtest.engine import BacktestEngine
from nautilus_trader.trading.strategy import Strategy
# 1. DATA INGESTION -- point-in-time, survivorship-bias-free universe only
def load_point_in_time_universe(as_of_date, min_adv_usd=2_500_000):
"""Never filter by TODAY's liquidity -- that imports survivorship bias."""
raw = data_store.query_asof(as_of_date=as_of_date) # Parquet/DuckDB store
return raw[raw["adv_20d_asof"] > min_adv_usd]
# 2. FEATURES -- Qlib Alpha158 for technicals, tsfresh + mlfinpy for the rest
def build_features(prices: pd.DataFrame) -> pd.DataFrame:
alpha158 = Alpha158(instruments=prices["symbol"].unique().tolist(),
start_time=prices.index.min(), end_time=prices.index.max())
tech_features = alpha158.fetch()
tsfresh_features = extract_relevant_features(
prices.reset_index(), y=None, column_id="symbol", column_sort="date", fdr_level=0.01,
)
d = find_min_ffd_order(prices["close"], adf_pvalue=0.05, min_corr=0.9) # search d in [0.1, 1.0]
frac_diff_price = frac_diff_ffd(prices["close"], d=d, threshold=1e-4) # stationary, RETAINS memory
return tech_features.join(tsfresh_features, how="inner").assign(frac_diff_price=frac_diff_price)
# 3. LABELS -- causal EWMA vol -> ATR-scaled triple barrier (mlfinpy)
def label_events(prices: pd.Series, signal_dates: pd.DatetimeIndex) -> pd.DataFrame:
daily_vol = get_daily_vol(close=prices, lookback=50)
vertical_barriers = add_vertical_barrier(t_events=signal_dates, close=prices, num_days=10)
events = get_events(close=prices, t_events=signal_dates, pt_sl=[2.0, 1.5], target=daily_vol,
min_ret=0.0005, num_threads=4, vertical_barrier_times=vertical_barriers)
return get_bins(events, prices) # -> bin (0/1), ret, t1 (needed for purging)
# 4. META-LABEL MODEL -- LightGBM inside nested Combinatorial Purged CV
def train_meta_label_model(X: pd.DataFrame, y: pd.Series, w: pd.Series, trial_counter: int):
pipeline = Pipeline([("model", lgb.LGBMClassifier(
num_leaves=31, learning_rate=0.03, min_child_samples=50,
monotone_constraints=MONO_CONSTRAINTS))])
cv = CombinatorialPurgedCV(n_folds=10, n_test_folds=2, purged_size=10, embargo_size=10)
oos_paths = cross_val_predict(estimator=pipeline, X=X, y=y, cv=cv, sample_weight=w)
pbo = compute_pbo(oos_paths)
dsr = compute_deflated_sharpe(oos_paths, n_trials=get_trial_count_from_mlflow() + trial_counter)
if pbo > 0.50 or dsr.p_value > 0.05:
raise ValueError(f"Model rejected: PBO={pbo:.2f}, DSR p={dsr.p_value:.3f}")
final_model = pipeline.fit(X, y, model__sample_weight=w)
return final_model, pbo, dsr
# 5. REGIME GATE -- causal, walk-forward, FILTERED (never smoothed) HMM posterior
def causal_regime_state(vol_return_features: np.ndarray, t: int, model_cache: dict,
refit_every: int = 63, min_train: int = 500) -> int:
if t < min_train:
return 1 # default "calm" until enough history exists
if t % refit_every == 0 or "model" not in model_cache:
hmm = GaussianHMM(n_components=2, covariance_type="diag", n_iter=200)
hmm.fit(vol_return_features[:t]) # only data strictly before t
model_cache["model"] = hmm
posteriors = model_cache["model"].predict_proba(vol_return_features[: t + 1])
return int(posteriors[-1].argmax()) # filtered state at t, no look-ahead
# 6. VOL-TARGETED SIZING -- GJR-GARCH forecast -> fractional-Kelly-scaled size
def size_position(returns_pct: pd.Series, meta_label_confidence: float, regime_state: int,
target_vol_annual: float = 0.10, kelly_fraction: float = 0.5,
max_leverage: float = 1.5) -> float:
if regime_state == 0: # 0 = "stormy" -- stand aside
return 0.0
res = arch_model(returns_pct, vol="GARCH", p=1, o=1, q=1, dist="t").fit(disp="off")
vol_fc = np.sqrt(res.forecast(horizon=1, reindex=False).variance.values[-1, 0]) / 100
vol_scale = (target_vol_annual / (252 ** 0.5)) / vol_fc
kelly_scale = kelly_fraction * max(2 * meta_label_confidence - 1, 0) # confidence -> edge proxy
return float(np.clip(vol_scale * kelly_scale, 0, max_leverage))
# 7. BACKTEST -- NautilusTrader (same strategy class runs backtest AND live)
class MetaLabelStrategy(Strategy):
def __init__(self, model, hmm_cache, config):
super().__init__(config)
self.model, self.hmm_cache = model, hmm_cache
def on_bar(self, bar):
feats = self.build_live_features(bar) # same code path as build_features()
confidence = self.model.predict_proba(feats)[:, 1][0]
regime = causal_regime_state(self.vol_history, self.clock.timestamp_ns, self.hmm_cache)
size = size_position(self.returns_pct_history, confidence, regime)
if confidence > 0.55 and size > 0:
self.submit_bracket_order(side="BUY", size=size, sl_atr_mult=1.5, tp_atr_mult=2.0)
def run_backtest(historical_bars, final_model, strat_config):
engine = BacktestEngine()
engine.add_data(historical_bars)
engine.add_strategy(MetaLabelStrategy(model=final_model, hmm_cache={}, config=strat_config))
return engine.run() # the SAME strategy object later promotes to paper/live -- adapters swap only
# 8. MLFLOW LOGGING -- every trial, forever (feeds the Deflated Sharpe trial count)
def log_run(params, pbo, dsr, backtest_results, final_model, trial_counter):
with mlflow.start_run(run_name=f"pipeline_v{trial_counter}"):
mlflow.log_params(params)
mlflow.log_metric("pbo", pbo)
mlflow.log_metric("dsr_p_value", dsr.p_value)
mlflow.log_metric("backtest_sharpe", backtest_results.sharpe_ratio)
mlflow.log_metric("backtest_max_dd", backtest_results.max_drawdown)
mlflow.log_metric("trial_number_in_family", trial_counter)
mlflow.lightgbm.log_model(final_model, "meta_label_model")
# 9. EXECUTION -- PickMyTrade webhook JSON (paper first, then tiny live)
def send_to_pickmytrade(symbol, side, qty, sl_price, tp_price, webhook_url, secret):
payload = {
"secret": secret, "symbol": symbol, "action": side, # "buy" / "sell"
"quantity": qty, "stopLoss": sl_price, "takeProfit": tp_price, "orderType": "market",
}
resp = requests.post(webhook_url, json=payload, timeout=5)
resp.raise_for_status()
return resp.json()
Cada flecha es un punto de intercambio, por diseño
Fíjate en que ninguna etapa está cableada a una elección específica de secciones anteriores: cambia LightGBM por CatBoost, el Alpha158 de Qlib por un conjunto de características hecho a mano, NautilusTrader por QuantConnect LEAN, o PickMyTrade por un puente de ejecución distinto, y nada más en el pipeline necesita cambiar. Ese desacoplamiento es lo que hace que la matriz de decisión de la §15 sea accionable en lugar de prescriptiva.
14.5
Claude Fable como ingeniero de apoyo para este stack
Claude Fable es el modelo de vanguardia de Anthropic (id de modelo claude-fable-5), disponible a través de la app de Claude y de Claude Code. En un stack tan profundo, su valor no es "escríbeme un bot de trading": es el punto intermedio poco glamuroso y propenso a errores: acertar la aritmética de los folds de CPCV, escribir un bucle de decodificación de HMM causal (no con fugas) a la primera, cablear un manejador de datos de Qlib para un mercado que no viene de fábrica, y leer un pipeline multietapa de principio a fin en busca de la única fuga que de otro modo solo saldría a la luz como una brecha entre real y backtest meses después.
Dónde se gana el sueldo en el stack específico de esta página:
Lógica de folds de CPCV: derivar los tamaños de purga/embargo a partir del horizonte de tu etiqueta y del lookback de característica más lento (§7), en lugar de adivinarlos y descubrirlo por un Sharpe de backtest inflado.
Inferencia de régimen causal: escribir el bucle de posterior filtrada, walk-forward, en lugar de la llamada con fugas a decode()/Viterbi de muestra completa mostrada como el ejemplo "incorrecto" en la §8.
Configuración de Qlib: generar y adaptar el YAML de flujo de trabajo Alpha158/Alpha360 a un manejador de datos personalizado para una región que Qlib no incluye, como el ejemplo de NSE en la §6.
Revisión de fugas en todo el pipeline: leer el esqueleto de la §14 etapa por etapa en busca de un bug de ajuste fuera del fold antes de que llegue a tocar capital.
Conversión de Pine Script → Python: portar la lógica de entrada de una estrategia de TradingView a la función de señal primaria que alimenta el modelo de meta-etiquetado.
Pegamento de ejecución: redactar el código del payload del webhook / clave de idempotencia cubierto en la §14.6, y el registro con MLflow que mantiene honesto tu recuento de pruebas del Deflated Sharpe (§12).
Prompts listos para adaptar para cada uno de esos, específicos del stack de esta página, no peticiones genéricas de "constrúyeme un bot":
Prompt 1 · Revisión de purga/embargo de CPCV
Review this skfolio CombinatorialPurgedCV setup [paste code]: 10 folds, 2 test folds, on triple-barrier-labeled
signals where barriers can resolve up to 10 trading days after the signal (get_events num_days=10). Check whether
purged_size and embargo_size are large enough to cover that full label-resolution window plus my slowest feature's
lookback. Flag any fold where a training sample's resolution window overlaps a test sample's, explain the leak, and
give me corrected purge/embargo values with the reasoning shown.
Prompt 2 · Compuerta de régimen HMM causal, no con fugas
Here is my hmmlearn regime-detection code [paste code]. Confirm it only calls predict_proba on data up to and
including index t when producing the label used AT time t, and that it never calls hmm.decode() or reads a Viterbi
path computed over the full series. If it's using the full-sample smoothed posterior, rewrite it as a walk-forward
loop that refits every N bars on strictly past data and returns the filtered (not smoothed) posterior at each step,
matching the causal pattern, not the leaky one.
Prompt 3 · Qlib Alpha158 en un mercado no predeterminado
I want Microsoft Qlib's Alpha158 handler running on NSE (India) equities, not one of Qlib's built-in regions.
Here's my current workflow YAML [paste config]. Write a custom data handler/provider that points Alpha158's feature
computation at my own point-in-time OHLCV store instead of Qlib's default region data, keeping the Alpha158 feature
set intact. Explain specifically what breaks -- calendar, instrument universe, trading-day alignment -- if I just
change the region tag without supplying compatible replacements.
Prompt 4 · Auditoría de fugas de todo el pipeline
Here is my end-to-end pipeline: data ingestion, feature engineering, triple-barrier labeling, LightGBM meta-label
training inside CombinatorialPurgedCV, HMM regime gate, GARCH-based sizing, and NautilusTrader backtest [paste code].
Walk it stage by stage and flag every point where a transform -- scaler, feature selector, frac-diff order search, HMM
fit -- is fit on data outside the current CV training fold, or a feature could see information unavailable at signal
time. Rank findings by how much each would inflate the backtest Sharpe if left uncorrected.
Prompt 5 · Pine Script → función de señal primaria
Here is my TradingView Pine Script strategy [paste script]. Convert its entry logic into a Python function that
takes a pandas DataFrame of OHLCV bars and returns a boolean signal series, matching the Pine version bar-for-bar on
identical historical data. This becomes the primary-model signal feeding my meta-labeling filter, so flag anything --
security() calls with lookahead, use of the current bar's close before it closes -- that would make the two versions
diverge.
Prompt 6 · Payload de webhook + clave de idempotencia
Write a Python function that takes a meta-label confidence score, ATR-based stop/target multiples, and a
position size from my vol-targeted sizing calc, and builds the JSON payload for a PickMyTrade webhook POST -- symbol,
side, quantity, stopLoss, takeProfit. Add a deterministic idempotency key (hash of symbol + signal timestamp + bar
index) as a payload field, and wrap the POST in retry-with-backoff logic that treats a timeout as "unknown, reconcile
before retrying" rather than blindly resubmitting.
Fable redacta, tú fusionas
Ninguno de los prompts anteriores reemplaza la lectura del diff por ti mismo. Claude Fable es rápido en las partes mecánicas (aritmética de folds de CV, lógica de reintentos repetitiva, convertir Pine a pandas), pero los tamaños de purga/embargo, los umbrales de rechazo de PBO/DSR y la decisión de enrutar capital a través de un webhook dado siguen siendo tuyos para firmarlos, cada vez, antes de que nada toque una cuenta de paper o real.
14.6
Puente de ejecución: construir vs. comprar para el último salto
La misma decisión de construir vs. comprar que toma cualquier equipo de sistemas, aplicada al último salto del pipeline de la §14: ¿tus escasas horas de ingeniería van a la fontanería de enrutamiento de órdenes, o a las capas de modelo que sí son tuyas? Esta sección defiende tratar la ejecución en vivo como una dependencia comprada de interfaz estrecha, y muestra cómo se ve la interfaz desde el lado del pipeline.
1 · La fontanería de enrutamiento de órdenes tiene un gran radio de impacto para bugs silenciosos
Lógica de reintentos, reautenticación de sesión del bróker, reconciliación de ejecuciones parciales, máquinas de estado de brackets OCO, deduplicación de webhooks: cada una es un problema bien entendido de forma aislada, y cada una es exactamente el tipo de código donde un bug no lanza una excepción. Silenciosamente duplica una orden, descarta un stop o deja una máquina de estado en el nodo equivocado. Un listener caído manteniendo una posición de futuros abierta de un día para otro no es un stack trace; es una llamada a la mesa de tu bróker.
2 · Un bug de ejecución silencioso es un evento de P&L, no una excepción capturada
Los errores de tu modelo aparecen como un Sharpe más bajo a lo largo de miles de operaciones: ruidosos pero acotados y diagnosticables. Un error de la capa de ejecución aparece como un stop concreto que falta o una ejecución duplicada, realizado en dólares, normalmente la única vez que la volatilidad se dispara y no estás mirando el terminal. Los tests unitarios atrapan los bugs para los que pensaste escribir un test; rara vez atrapan un token de sesión que expira a media jornada o un webhook entregado dos veces durante un fallo de red.
3 · Las horas que vale la pena invertir son las que solo tú puedes invertir
Reintentos/backoff, máquinas de estado OCO y traducción de órdenes específica del bróker son el mismo problema para cada trader que enruta a Rithmic o IB, y por eso están comoditizadas. Tu modelo de meta-etiquetado, tu compuerta de régimen y tu validación CPCV no están resueltos en ningún otro sitio; son la única capa donde una hora extra puede realmente mover tu Sharpe. Una hora endureciendo un enrutador de órdenes casero frente a casos límite contra los que alguien ya se endureció es una hora no invertida ahí.
4 · La separación de responsabilidades es un patrón de fiabilidad, no un adorno
Una interfaz HTTP estrecha y tonta (un POST, una forma de payload) entre estrategia y bróker significa que tu código de investigación puede ser tan experimental como quieras sin llegar nunca a mantener un token de sesión en vivo. Si la infraestructura del proveedor de ejecución tiene un incidente, esa es su rotación de guardia, no un aviso a las 2 de la mañana para ti ni un bug en tu modelo. Es la misma razón por la que los equipos de plataforma no dejan que el código de aplicación abra sockets en bruto a una base de datos.
Dónde encaja esto en el pipeline de la §14
El pipeline de referencia termina en "registro con MLflow → webhook de PickMyTrade para la ejecución" porque ese es el límite de confianza natural. Tu modelo emite una señal → se dispara una alerta de TradingView, o (dado que una configuración avanzada puede saltarse TradingView por completo) tu propio servicio Python construye y hace POST del JSON directamente al endpoint del webhook de PickMyTrade → PickMyTrade se encarga de la colocación de brackets OCO, la traducción de órdenes específica del bróker, el fan-out multicuenta y el bucle de reconexión/reintento contra el mercado al que enrutes. Esa división del trabajo significa que tu servicio solo tiene que ser fiable hasta "enviar un POST HTTP idempotente": nunca tiene que mantener una conexión con estado, de varias semanas, a la API de sesión de un bróker, refrescar tokens de autenticación según un horario ni reconciliar el estado de las órdenes tras una partición de red. Toda esa categoría de problema se retira de tu plato.
JSON · forma ilustrativa del payload de un webhook (genérica — verifica los nombres de los campos con la documentación actual del proveedor)
Deliberadamente genérico — no es un esquema verificado de PickMyTrade (consulta la llamada operativa send_to_pickmytrade() en §14 para los nombres de campo que ya se usan en el pipeline de referencia de esta página). quantity sale directamente del cálculo de sizing con objetivo de volatilidad de §11/§14; stopLoss/takeProfit son la entrada ± ATR × los múltiplos de barrera ya validados en el etiquetado de triple barrera (§7); idempotencyKey — ausente del ejemplo mínimo de §14 — es lo que convierte una entrega de webhook «al menos una vez» en una orden «efectivamente una vez».
Los modos de fallo que conviene contemplar desde el principio
La entrega de webhooks es «al menos una vez», no «exactamente una vez» — de lo contrario, un POST reintentado tras un tiempo de espera puede duplicar una orden; una clave de idempotencia es lo que hace seguros los reintentos. Los límites de tasa de las API de los brókeres y los ciclos de renovación de tokens de autenticación son detalles propios de cada bróker (tokens de sesión de Rithmic, reconexiones de IB Gateway, renovación OAuth de Tradovate) con los que una capa de ejecución compartida ya ha tropezado miles de veces en las cuentas de otros usuarios. La reconciliación del estado de las órdenes tras una partición de red — ¿se llegó a colocar esa orden bracket, o se cayó la conexión antes del ack? — implica consultar el estado de las órdenes en el bróker y contrastarlo con lo que crees que enviaste, en cada reconexión. Por debajo de todo ello: tu código de investigación no tiene requisitos de SLA — un kernel caído te cuesta una reejecución — mientras que tu código de ejecución necesita una fiabilidad cercana a los cinco nueves, porque «el listener estuvo caído cuatro minutos» es indistinguible, en sus consecuencias, de «el stop-loss no existía».
Mantén el radio de impacto del entorno de investigación en cero
Tu código de backtest, reentrenamiento y experimentos rastreados con MLflow (§12) no debería tener ninguna ruta de código capaz de colocar una orden real — ni un feature flag, ni un valor por defecto dry_run=False a la espera de que alguien lo cambie por error. Enrutar cada orden real a través de una única frontera HTTP externa y estrecha impone esa separación de forma estructural: la única manera de que el código de investigación pudiera colocar una operación real sería construyendo deliberadamente exactamente el mismo POST de webhook que hace tu estrategia en vivo. Es la misma razón por la que los runners de CI no reciben credenciales de la base de datos de producción — aquí cuesta una suscripción en lugar de una segunda rotación de guardias.
Infraestructura mercantilizada, consumida vía API
Trata la ejecución igual que ya tratas la computación: no montas tus propios servidores para conseguir una GPU, y tampoco hay alfa en montar tu propio enrutador de órdenes. PickMyTrade es infraestructura que llamas, no un componente de tu ventaja competitiva — el modelo, la puerta de régimen y la validación son las partes de este stack que vale la pena defender.
15
Matriz de decisión — qué herramienta para qué trabajo
Una única tabla de consulta para «necesito… → usa esto → porque…».
I need to…
Use
Why
Filter trade quality (meta-label)
LightGBM + mlfinpy triple-barrier
Highest-ROI, lowest-risk ML addition; GBDT dominates tabular financial data
Statistical drift tests (KS, PSI, Wasserstein) across features and predictions
Estimate live performance before labels arrive
NannyML (CBPE/DLE)
Label-free — critical since triple-barrier outcomes only resolve after the barrier is hit
Use financial sentiment as a risk veto
FinBERT (ProsusAI)
Apache-2.0, CPU, sub-second — defensive filter, not an alpha engine
Cheaply fine-tune an LLM on financial text
FinGPT (LoRA on LLaMA)
~3.67M trainable params vs. 6.17B full fine-tune — fits on one consumer GPU
Orchestrate the nightly pipeline
Prefect (Dagster at scale)
Scheduling/retries/caching once a cron script becomes unwieldy — not needed pre-MVP
Avoid a non-commercial license trap
Prefer Chronos / TimesFM / Lag-Llama / MOMENT over Moirai
Moirai is CC BY-NC-4.0 — not usable in a system that manages your own capital
Find structural breaks / changepoints
ruptures (PELT)
Linear-cost exact search, no assumed number of breakpoints
Use RL without it blowing up your backtest
Stable-Baselines3 (PPO) on a narrow sub-problem, PBO-tested
FinRL's own contests reject overfit agents at 10% significance — confine RL accordingly
Execute live orders
PickMyTrade webhook
Execution is a solved, hardened problem — your edge lives in the model layers, not order plumbing
Draft / review pipeline code quickly
Claude Fable (claude-fable-5)
Pair-engineer for CPCV fold math, causal HMM decoding, and leakage review — see §14.5; every merge is still a human decision
Bridge a model signal to a live broker order
PickMyTrade (webhook execution bridge)
One idempotent POST replaces weeks of broker auth, retry, and OCO state-machine engineering — see §14.6
16
Apéndice de licencias
Cada herramienta y modelo tratado en esta página, con su licencia y un indicador claro. Segura = permisiva, sin restricción significativa para el uso comercial o de trading en vivo. Precaución = usable, pero lee los términos (obligaciones de copyleft, cláusulas de código disponible pero restringido, o una preocupación por el estado de mantenimiento más que por la licencia). Restringida = un obstáculo real para un sistema comercial o en vivo sin restricciones si no media un acuerdo aparte.
Covers §2's from-scratch DL architectures via one API
Nixtla TimeGPT
Proprietary / paid API
Caution
Closed, vendor lock-in; prefer open Chronos/TimesFM instead
Amazon Chronos / Chronos-Bolt
Apache-2.0
Safe
—
Google TimesFM
Apache-2.0
Safe
—
Salesforce Moirai / Moirai-MoE
CC BY-NC-4.0
Restricted
Non-commercial only — do not use in a system managing your own capital without a separate license
Lag-Llama
Apache-2.0
Safe
—
MOMENT
MIT
Safe
—
IBM Granite-TimeSeries (PatchTSMixer/PatchTST/TTM)
Apache-2.0
Safe
—
FinBERT (ProsusAI)
Apache-2.0
Safe
—
FinBERT-tone
Apache-2.0
Safe
—
FinGPT (code)
MIT
Caution
Code is MIT, but fine-tuned checkpoints inherit the base LLaMA weights' separate Meta community license — check that independently
FinRL / FinRL-Meta
MIT
Safe
—
Stable-Baselines3
MIT
Safe
—
TensorTrade
Apache-2.0
Caution
License is permissive, but maintenance has stalled enough that a community fork (TensorTrade-NG) exists specifically to address it — plan accordingly
Microsoft Qlib
MIT
Safe
—
mlfinpy
MIT
Safe
—
skfolio
BSD-3-Clause
Safe
—
mlfinlab (paid)
Commercial
Caution
Paid license required — the two free packages above already cover the essentials
hmmlearn
BSD
Safe
—
ruptures
BSD-2-Clause
Safe
—
vectorbt (community)
Apache-2.0 + Commons Clause
Caution
Commons Clause blocks selling a product/service whose value derives primarily from the software itself; fine for internal use, and maintenance-frozen
backtrader
GPL-3.0
Restricted
Strong copyleft; also stalled since ~2021 — avoid for new work on both grounds
Zipline-reloaded
Apache-2.0
Safe
—
NautilusTrader
LGPL-3.0-or-later
Caution
Permits linking from closed-source strategy code; modifications to NautilusTrader itself must be shared back — verify current terms before commercial deployment
QuantConnect LEAN
Apache-2.0
Safe
—
bt
MIT
Safe
—
backtesting.py
AGPL-3.0
Restricted
Network-use copyleft — a real constraint if you build a hosted/SaaS product on it; fine for private, non-distributed use
freqtrade
GPL-3.0
Restricted
Crypto-only bot; strong copyleft restricts closed-source commercial derivatives — flagged since it's a common trap
PyPortfolioOpt
MIT
Safe
—
Riskfolio-Lib
BSD-3-Clause
Safe
—
arch
NCSA
Safe
Permissive, commercial-OK
tsfresh
MIT
Safe
—
MLflow
Apache-2.0
Safe
—
Evidently AI
Apache-2.0
Safe
—
NannyML
Apache-2.0
Safe
—
Prefect
Apache-2.0
Safe
—
Dagster
Apache-2.0
Safe
—
PickMyTrade
Proprietary / paid SaaS
Caution
Execution API, not an installable library — no open-source or self-hosted option; a subscription gates access (see §14.6), a vendor-dependency call rather than an OSS-license one
Esto no es asesoramiento legal
Las licencias y su interpretación pueden cambiar, y los límites del «uso comercial» (especialmente en CC BY-NC y AGPL) son genuinamente específicos de cada caso. Trata esta tabla como un mapa de partida para la debida diligencia, no como un sustituto de leer tú mismo el texto actual de la licencia — o la opinión de un abogado — antes de cualquier despliegue que implique capital real o que se distribuya a terceros.
Aviso financiero importante
Solo con fines educativos. Todo el contenido de esta página se ofrece con fines educativos e informativos generales y no constituye asesoramiento de inversión, financiero, legal ni fiscal, ni una recomendación o solicitud de compra o venta de ningún valor, contrato de futuros u otro instrumento financiero.
Riesgo sustancial de pérdida. Operar con futuros, derivados y otros productos apalancados conlleva un riesgo sustancial de pérdida y no es adecuado para todos los inversores. Puedes perder más que tu inversión inicial. Para operar solo debe utilizarse capital de riesgo — dinero que puedas permitirte perder sin que afecte a tu nivel de vida.
Los resultados pasados no son indicativos de resultados futuros. Los resultados de rendimiento hipotéticos y de backtest tienen limitaciones inherentes: se elaboran con la ventaja de la retrospectiva, no implican riesgo financiero y no pueden dar cuenta de todos los factores — incluida la capacidad de soportar pérdidas — que afectan a la operativa real. Cada cifra de benchmark y cada recuento de estrellas o descargas citado en esta página refleja una instantánea puntual tomada durante la investigación de mediados de 2026 y puede haber cambiado para cuando lo leas — verifica las cifras actuales frente a la fuente primaria (repositorio de GitHub, tarjeta de modelo de Hugging Face o artículo citado) antes de basarte en ellas.
Sin garantías. Nada en esta página garantiza beneficios ni protección frente a pérdidas. Los modelos de aprendizaje automático — incluidos los modelos fundacionales de series temporales tratados en §3 — pueden equivocarse, las condiciones del mercado cambian y los sistemas automatizados pueden fallar.
No es un asesor registrado. El autor y el editor de esta página no son un asesor de inversiones registrado, un bróker-dealer, un asesor de trading de materias primas (CTA) ni un planificador financiero. Antes de tomar cualquier decisión financiera, consulta a un asesor financiero autorizado que pueda evaluar tus circunstancias individuales.
No es asesoramiento legal sobre licencias. El apéndice de licencias de §16 se ofrece por comodidad y refleja una lectura de buena fe de los archivos de licencia públicamente disponibles en el momento de la investigación; no es asesoramiento legal. Confirma los términos actuales de cada licencia directamente con cada proyecto antes de cualquier uso comercial o en producción.
Acerca de las herramientas mencionadas. PickMyTrade es una herramienta de automatización de la ejecución de terceros que enruta alertas a los brókeres; no proporciona asesoramiento, señales ni estrategias de trading. Todas las bibliotecas, modelos y frameworks nombrados (Hugging Face, Amazon, Google, Salesforce, IBM, Microsoft, Meta/LLaMA, AI4Finance Foundation y todo proyecto de código abierto referenciado) son propiedad de sus respectivos dueños; esta página es contenido educativo independiente y no está respaldada por ninguno de ellos ni afiliada a ellos. Los datos fácticos (licencias, recuentos de estrellas, cifras de benchmark) se tomaron de repositorios oficiales, tarjetas de modelo y artículos citados en el momento de la investigación y pueden cambiar — verifícalos siempre en la fuente primaria.
Tu ventaja competitiva reside en las capas del modelo, la puerta de régimen y la validación. Deja que PickMyTrade se encargue de la fontanería de la ejecución — un único webhook idempotente hacia más de 60 brókeres y prop firms, con órdenes bracket adjuntas.