Datos de mercado y documentales para sistemas LLM
Fuentes 2026, SEC EDGAR programático, noticias y sentimiento, y pipelines point-in-time sin trampas.
Objetivos de aprendizaje
Al completar este módulo, el lector será capaz de:
- Distinguir las familias de fuentes de datos financieras de 2026 (terminales institucionales, feeds empresariales, APIs developer-first, fuentes regulatorias públicas) y dimensionar su coste real, incluidos acceso programático y tarifas non-display de los exchanges.
- Evaluar si una fuente está licenciada para alimentar prompts y vector stores en producción comercial, y descartar las que no lo están (el caso yfinance).
- Consumir SEC EDGAR mediante sus endpoints JSON reales (
submissions,companyfacts,companyconcept,frames, full-text search), respetando rate limits y la política de User-Agent. - Construir tools de LangChain sobre esas fuentes, listas para los agentes de los módulos posteriores.
- Diseñar un pipeline point-in-time —WebSocket → Kafka → TimescaleDB (serving) + Parquet/DuckDB (backtest) + Feast— aplicando la regla "texto al vector store, números a SQL".
- Detectar y neutralizar las trampas que invalidan backtests con fundamentales: look-ahead por restatements, reporting lag y survivorship bias.
El Módulo 3 dotó a los agentes de orquestación: grafos de estado, herramientas, persistencia e interrupciones humanas. Pero un agente es tan bueno como los datos que sus herramientas le sirven. Este módulo abre el Bloque II (comprender) construyendo esa base: qué fuentes de mercado y documentales existen en 2026, qué licencia hace falta para alimentar un LLM con ellas, cómo se consumen programáticamente y cómo se organizan en una arquitectura point-in-time que el RAG del Módulo 5 y los cálculos de los Módulos 7 y 8 puedan auditar.
4.1 El mapa de fuentes en 2026
4.1.1 Institucional vs accesible
El mercado de datos financieros en 2026 se estratifica en dos mundos que apenas se tocan. En el primero, los terminales institucionales: Bloomberg Terminal cotiza a julio de 2026 en torno a \(31{,}980 por asiento y año (\)28{,}320 en configuración multi-asiento), tras el incremento del 6,5 % aplicado a renovaciones desde enero de 2025 (Github) . LSEG Workspace (sucesor de Refinitiv Eikon) se sitúa por encima de $22{,}000 por asiento en su versión completa, con una edición reducida cercana a $4{,}000 anuales (Github) . FactSet, con precio de lista histórico de $12{,}000, muestra contratos reales con media próxima a $45{,}000 anuales según datos transaccionales de compradores (arXiv.org) . S&P Capital IQ Pro se mueve en la banda \(12{,}000–\)20{,}000 por asiento (arXiv.org) . Estas cifras son estimaciones de industria —ninguno de los cuatro vendors publica tarifas—, pero convergen en dos fuentes independientes y se aceptan como referencia presupuestaria (arXiv.org) .
El dato decisivo para un ingeniero de sistemas LLM es otro: la suscripción al terminal no incluye acceso programático. Alimentar un pipeline automatizado —y, por tanto, un agente LangChain— con datos Bloomberg exige B-PIPE (\(2{,}000–\)3{,}000/mes) o Data License (\(5{,}000–\)50{,}000+/año); extraer contenido del terminal a un vector store o a un prompt sin esa licencia viola el contrato (arXiv.org) .
En el segundo mundo, las APIs developer-first han alcanzado una cobertura que hace cinco años era exclusiva del buy-side. El hito estructural es el renombrado de Polygon.io como Massive.com, efectivo el 30 de octubre de 2025: las claves y endpoints api.polygon.io siguen operativos en paralelo con api.massive.com, y se añadieron futuros CME/CBOT/COMEX/NYMEX, datos Benzinga y un fichero llms.txt en la documentación para consumo por asistentes de IA (Quant Memo) . Sus planes van del EOD gratuito a $199/mes en tiempo real y $2{,}000/mes en Business con licencia comercial (Picture Perfect Portfolios) . Alpha Vantage da 25 peticiones diarias gratis y premium de $49,99 a $249,99/mes escalados por req/min, con la salvedad de que el tiempo real estadounidense exige un entitlement adicional (MDPI) . Tiingo cubre EOD de más de 30 años por \(30/mes (\)50/mes el Business de uso comercial) (A.L. Capital Advisory) . Databento distribuye datos directos de exchange (no SIP) con normalización de 6,1 microsegundos y esquemas MBO/MBP-10 en nanosegundos, desde \(199/mes [(pfolio.io)](https://www.pfolio.io/academy/tangency-portfolio) . Nasdaq Data Link opera como *marketplace* con datasets económicos gratuitos y premium a la carta (\)50–$500+/mes) (Entropy Method: Solving RL Without Gradients) .
Tabla 4.1 — Vendors institucionales vs APIs accesibles (precios a julio de 2026)
| Fuente | Cobertura principal | Latencia | Precio de referencia | Licencia para uso con LLM |
|---|---|---|---|---|
| Bloomberg Terminal + B-PIPE/Data License | Global multi-activo, noticias, estimados | Tiempo real (ms) | ~$31{,}980/asiento/año + \(2{,}000–\)3{,}000/mes (B-PIPE) (Github) | Solo vía licencia de datos explícita; addenda de IA a negociar (confianza media-alta: estimación de industria) |
| LSEG Workspace + Data Platform | Global multi-activo, Reuters News | Tiempo real | ~$22{,}000+/asiento/año; APIs aparte (Github) | Requiere licencia de redistribución/API (confianza media-alta) |
| FactSet | Fundamentales "scrubbed", estimados, supply chain | Tiempo real / EOD | Lista ~\(12{,}000; media contractual real ~\)45{,}000/año (arXiv.org) | Tarifas adicionales por integración en sistemas propios y usuarios no licenciados (arXiv.org) |
| Massive (antes Polygon.io) | Acciones, opciones, forex, crypto, futuros | EOD gratis; 15 min $29/mes; RT $199/mes | \(0–\)2{,}000/mes (Picture Perfect Portfolios) | Uso comercial/redistribución solo en plan Business; llms.txt en docs (Picture Perfect Portfolios) |
| Alpha Vantage | Acciones, forex, crypto, indicadores, noticias | EOD gratis; RT vía entitlement | \(0 (25 req/día)–\)249,99/mes (MDPI) | Términos comerciales bajo consulta; servidor MCP oficial (MDPI) |
| Tiingo | EOD ajustado 30+ años, IEX intraday | EOD; IEX tiempo real | $30/mes (Power); $50/mes (Business) (A.L. Capital Advisory) | Plan Business cubre uso comercial interno (A.L. Capital Advisory) |
| Databento | L0–L3 directo de exchange, 21.000+ productos | Nanosegundos (6,1 µs normalización) | $199/mes (Standard); $4{,}000/mes (US Equities ilimitado) (pfolio.io) | Grado institucional; términos por plan (pfolio.io) |
| Nasdaq Data Link | Marketplace: económicos, fundamentales, alternativos | Variable por dataset | Gratis (FRED)–$500+/mes por dataset (Entropy Method: Solving RL Without Gradients) | Licencia por dataset; revisar cada uno (Entropy Method: Solving RL Without Gradients) |
| yfinance (Yahoo, no oficial) | EOD e intraday limitado | Delayed | $0 (Ask Everything) | No: solo uso personal según ToS; sin SLA (Ask Everything) |
Interpretación. La tabla revela tres asimetrías. Primera: el factor de escala entre ambos mundos es de dos a tres órdenes de magnitud —un desk con Tiingo + Massive Business cuesta menos al año que un solo asiento de Bloomberg—, pero lo que se compra con el sobreprecio institucional no es el dato sino la licencia, el soporte y la cobertura consolidada. Segunda: la columna "licencia LLM" decide la viabilidad de un proyecto agéntico, no el precio: todas las filas institucionales exigen negociación explícita antes de meter un token en un prompt, y solo algunas APIs accesibles (Massive Business, Tiingo Business) la incluyen de fábrica. Tercera: la latencia a precio developer ya cubre cualquier estrategia por debajo del intra-día agresivo; Databento incluso abre la puerta a microestructura. Conclusión operativa: los pipelines de los módulos 5 a 8 pueden construirse sobre la mitad accesible de la tabla, dejando los vendors institucionales como ruta de escalado una vez aprobada la licencia.
En palabras llanas: no compras el dato, compras la licencia
Piensa en la diferencia entre comprar un libro y comprar los derechos para fotocopiarlo y repartirlo dentro de tu empresa. El precio de un terminal Bloomberg no paga información que no exista en otra parte —los precios de las acciones son los mismos en todas las pantallas del mundo—; paga el derecho contractual a usarla, el soporte cuando un campo falla un domingo por la noche y la cobertura consolidada de millones de instrumentos. Por eso la Tabla 4.1 muestra un factor de dos a tres órdenes de magnitud entre los dos mundos sin que ninguno sea «mejor» en abstracto: un desk cuantitativo pequeño puede operar legalmente con Tiingo Power y Massive Business por menos al año que lo que cuesta un solo asiento de Bloomberg, siempre que su estrategia no exija la cobertura o la latencia institucional.

La figura usa escala logarítmica a propósito: en escala lineal las tres barras developer-first serían invisibles junto a las institucionales. Fíjate también en el salto dentro del propio mundo Bloomberg: el asiento solo (sin acceso programático) y el asiento más B-PIPE son productos distintos, y solo el segundo puede alimentar legalmente un pipeline automatizado.
4.1.2 Licencias para uso con LLMs: non-display, addendas de IA y el caso yfinance
Tres mecanismos contractuales determinan si un dato puede entrar en un sistema LLM de producción.
El primero es la tarifa non-display de los exchanges: el consumo de datos de mercado por máquinas —algoritmos, servidores y, explícitamente, agentes LLM que generan señales— en lugar de por un humano mirando una pantalla. La guía oficial de NYSE fija $3{,}000/mes para non-display de categoría 1 sobre NYSE Trades y $5{,}000/mes sobre el Integrated Feed de NYSE National, con una categoría 3 que cubre señales de trading y ATS (alanhou.org) . Un agente LangChain cuya tool consulta un feed en tiempo real cae, a ojos del exchange, en esta definición: es la sorpresa presupuestaria más frecuente en proyectos de IA con market data (alanhou.org) .
El segundo mecanismo son las addendas de IA de los vendors. Los contratos de Bloomberg, LSEG, FactSet y S&P licencian datos para uso interno por usuarios licenciados; enviar ese contenido a un LLM de tercero (donde puede quedar en logs) o a un vector store accesible por personal no licenciado entra en zona prohibida salvo addenda explícita de "AI/derived data use" (arXiv.org) . La contrapartida: los vendors accesibles formalizan el canal inverso —servidores MCP oficiales de Alpha Vantage y Benzinga, llms.txt en Massive— que convierte sus APIs en fuentes descubribles por agentes (Quant Memo) .
El tercero es la prueba del algodón negativa: yfinance. Yahoo cerró su API pública en 2017; la librería hace scraping de endpoints no oficiales, se satura bajo carga (~2{,}000 peticiones/hora estimadas antes del error 429), sus términos de servicio la limitan a uso personal y carece de cualquier SLA (Ask Everything) .
Nota de riesgo. Usar yfinance como tool de un agente en producción comercial viola los términos de servicio de Yahoo (uso personal únicamente) y es estructuralmente frágil: el rediseño web de febrero de 2025 rompió scripts en producción de la noche a la mañana, y el intradía de 1 minuto solo cubre 7 días (Ask Everything) . Para docencia y prototipado es válido; para sistemas que alimenten decisiones reales, la fuente mínima defensible es una API con licencia comercial (Massive Business, Tiingo Business, Databento) o EDGAR, pública por ley. Migrar a Tiingo Power cuesta $30/mes: no hay justificación económica para asumir el riesgo contractual.
En la práctica institucional. En los desks que han industrializado LLMs, la revisión de licencias ocurre antes que la de arquitectura. El checklist de aprobación de un pipeline agéntico incluye: (1) entitlement y categoría non-display declarada al exchange; (2) addenda de IA firmada o confirmación de que el plan cubre redistribución interna; (3) segregación del almacenamiento —el vector store con datos licenciados solo es accesible por usuarios licenciados—; (4) linaje: cada respuesta del agente debe trazarse a la fuente y a su licencia. Un pipeline técnicamente perfecto sobre datos mal licenciados es un pasivo regulatorio, no un activo.
Trampa común: «tengo API key» no significa «puedo meterlo en un prompt»
El error presupuestario más frecuente en proyectos de IA con market data es asumir que pagar un feed da derecho a consumirlo con máquinas. A ojos del exchange, un agente LangChain cuya tool consulta cotizaciones en tiempo real es consumo non-display —lo mismo que un algoritmo de ejecución— y se tarifa aparte: la guía de NYSE citada en §4.1.2 fija 3.000 USD/mes en categoría 1 sobre NYSE Trades y 5.000 USD/mes sobre el Integrated Feed de NYSE National, con una categoría 3 que cubre explícitamente señales de trading. El equipo lo descubre cuando llega la carta del exchange o la auditoría del vendor, nunca durante el desarrollo.
La versión simétrica en el lado vendor: volcar contenido licenciado a un vector store accesible por personal no licenciado, o enviarlo a un LLM de terceros donde pueda quedar en logs, viola el contrato salvo addenda explícita de «AI/derived data use». El checklist institucional del módulo existe precisamente porque estas dos sorpresas —non-display y addenda— aparecen después de construir el pipeline, cuando rehacerlo cuesta meses. Lección operativa: la pregunta «¿está este dato licenciado para entrar en un prompt?» va antes que cualquier decisión de arquitectura, y su respuesta se documenta junto al linaje de cada fuente.
4.2 SEC EDGAR como fuente programática
4.2.1 Endpoints reales: submissions, companyfacts, companyconcept, frames y full-text search
EDGAR es la única gran fuente financiera que combina tres propiedades: gratuita, sin API key y con valor legal directo (los filings son documentos regulatorios). La SEC pide a cambio un User-Agent descriptivo con correo de contacto y un máximo de 10 peticiones por segundo; para backfills masivos recomienda los ZIP nocturnos en lugar de martillear endpoints por compañía (arXiv.org) . El primer paso de cualquier pipeline es cachear https://www.sec.gov/files/company_tickers.json, que resuelve ticker → CIK localmente (ResearchGate) .
Tabla 4.2 — Endpoints SEC EDGAR (verificados a julio de 2026)
| Endpoint | URL | Propósito | Rate limit |
|---|---|---|---|
| Submissions | https://data.sec.gov/submissions/CIK##########.json |
Metadata de la empresa + historial completo de filings (formularios, fechas, accession numbers, enlaces) (TL;DR Filing) | 10 req/s global SEC (arXiv.org) |
| CompanyFacts (XBRL) | https://data.sec.gov/api/xbrl/companyfacts/CIK##########.json |
Todos los hechos XBRL (us-gaap, dei, ifrs-full, srt) jamás presentados, con filed por hecho (ResearchGate) |
10 req/s (arXiv.org) |
| CompanyConcept | https://data.sec.gov/api/xbrl/companyconcept/CIK{cik}/{taxonomía}/{tag}.json |
Historia de un único concepto (payload pequeño) (ResearchGate) | 10 req/s (arXiv.org) |
| Frames | https://data.sec.gov/api/xbrl/frames/{taxonomía}/{concepto}/{unidad}/{periodo}.json |
Un concepto para todas las empresas en un periodo (cross-section, ej. CY2023Q4I) (ResearchGate) |
10 req/s (arXiv.org) |
| Full-Text Search (EFTS) | https://efts.sec.gov/LATEST/search-index?q=... |
Búsqueda booleana en el texto de todos los filings; filtros forms, dateRange, size ≤ 100 (Apify) |
10 req/s (arXiv.org) |
| Ticker→CIK | https://www.sec.gov/files/company_tickers.json |
Lookup local ticker/CIK/nombre (ResearchGate) | Cachear (cambia poco) |
| Bulk archives | ZIPs nocturnos en data.sec.gov | Backfills históricos masivos (arXiv.org) | Uso recomendado para carga inicial |
Interpretación. La familia XBRL (XBRL: eXtensible Business Reporting Language, el estándar de etiquetado de hechos financieros exigido por la SEC) convierte a EDGAR en fuente de primer orden para sistemas LLM: cada cifra llega estructurada con taxonomía, unidad, periodo y —crítico para el apartado 4.4— la fecha filed en que fue pública, base de toda reconstrucción point-in-time (ResearchGate) . companyfacts es el caballo de batalla para fundamentales de una empresa; companyconcept minimiza tokens cuando el agente solo necesita una métrica (un companyfacts completo puede exceder la ventana de contexto); frames habilita screening cross-sectional —comparar NetIncomeLoss de todo el universo en un trimestre con una llamada—, el patrón exacto de las queries cuantitativas (ResearchGate) . EFTS es el índice de descubrimiento del pipeline documental del Módulo 5: localizar todos los filings que mencionan "material weakness" en factores de riesgo cuesta una petición HTTP (Apify) .
El siguiente snippet implementa el acceso a submissions respetando la política de la SEC:
import time
import requests
SEC_HEADERS = {"User-Agent": "QuantResearch [email protected]"} # obligatorio
RATE_LIMIT_S = 0.12 # ~8 req/s, margen bajo el máximo oficial de 10 req/s
def get_submissions(cik: int) -> dict:
"""Historial completo de filings de una empresa (arrays paralelos columnares)."""
url = f"https://data.sec.gov/submissions/CIK{cik:010d}.json"
resp = requests.get(url, headers=SEC_HEADERS, timeout=20)
resp.raise_for_status()
time.sleep(RATE_LIMIT_S)
return resp.json()
subs = get_submissions(320193) # Apple
recent = subs["filings"]["recent"]
# form[i], filingDate[i] y accessionNumber[i] comparten índice (formato columnar)
primer_10k = next(
i for i, f in enumerate(recent["form"]) if f == "10-K"
)
print(recent["form"][primer_10k], recent["filingDate"][primer_10k],
recent["accessionNumber"][primer_10k])
# URL del documento: https://www.sec.gov/Archives/edgar/data/
# {cik_sin_ceros}/{accession_sin_guiones}/{primaryDocument}
Y este es el patrón de tool LangChain sobre companyconcept —la primera tool real del curso, que los agentes de los módulos 3 y 7 consumirán directamente:
from langchain.tools import tool
import requests
@tool
def get_xbrl_concept(ticker: str, concept: str = "NetIncomeLoss") -> str:
"""Devuelve la historia de un concepto XBRL us-gaap de una empresa (SEC EDGAR).
Cada hecho incluye periodo (end), valor (val), formulario (form) y,
críticamente, la fecha de publicación (filed) para joins point-in-time.
"""
cik = resolve_cik(ticker) # lookup en caché desde company_tickers.json
url = (f"https://data.sec.gov/api/xbrl/companyconcept/"
f"CIK{cik:010d}/us-gaap/{concept}.json")
r = requests.get(url, headers={"User-Agent": "QuantApp [email protected]"},
timeout=20)
r.raise_for_status()
units = r.json()["units"]
return str(units)[:4000] # truncar: control de tokens y coste
Las buenas prácticas separan una tool de producción de una demo: docstring preciso (el LLM elige la tool por su descripción), validación de entradas con pydantic, truncado de salidas, JSON compacto en lugar de HTML, errores accionables y reintentos con backoff ante los 429 de GDELT, Yahoo o Alpha Vantage (Apify) .
Ejemplo trabajado: de ticker a URL de filing en cuatro pasos
El snippet de get_submissions del módulo esconde cuatro detalles que conviene fijar antes de escribir tools propias. Recorrido completo con Apple, usando las mismas piezas del curso (requests, SEC_HEADERS, pausa de rate limit):
import time
import requests
SEC_HEADERS = {"User-Agent": "QuantResearch [email protected]"} # obligatorio
RATE_LIMIT_S = 0.12 # ~8 req/s, margen bajo el máximo oficial de 10 req/s
# PASO 1 — ticker → CIK con el fichero cacheado: una descarga, mil lookups
tickers = requests.get("https://www.sec.gov/files/company_tickers.json",
headers=SEC_HEADERS, timeout=20).json()
cik = next(v["cik_str"] for v in tickers.values() if v["ticker"] == "AAPL")
# cik == 320193 (entero, sin ceros a la izquierda)
# PASO 2 — submissions: el CIK se formatea a 10 dígitos con ceros a la izquierda
subs = requests.get(f"https://data.sec.gov/submissions/CIK{cik:010d}.json",
headers=SEC_HEADERS, timeout=20).json()
time.sleep(RATE_LIMIT_S)
# PASO 3 — formato columnar: form[i], filingDate[i], accessionNumber[i]
# y primaryDocument[i] son arrays paralelos que se recorren con el mismo índice
recent = subs["filings"]["recent"]
i = next(j for j, f in enumerate(recent["form"]) if f == "10-K")
# PASO 4 — URL del documento: CIK SIN ceros y accession SIN guiones
accn = recent["accessionNumber"][i].replace("-", "")
url = (f"https://www.sec.gov/Archives/edgar/data/{cik}/"
f"{accn}/{recent['primaryDocument'][i]}")
Tres fallos reales al implementarlo por primera vez: olvidar el formato de diez dígitos en la URL de submissions (404 inmediato), tratar recent como una lista de objetos cuando son arrays paralelos, y construir la URL de Archives con el accession number todavía con guiones. La misma disciplina del módulo se aplica después a companyconcept: docstring preciso (el LLM elige la tool por su descripción), salida truncada a 4.000 caracteres y la fecha filed siempre visible en el payload, porque es la llave de los joins point-in-time del Módulo 8.
4.3 Noticias, sentimiento y datos alternativos
4.3.1 GDELT, Benzinga, Alpha Vantage; MCP; Form 4 y 13F; deduplicación y alpha decay
El ecosistema de noticias presenta un precipicio de precio conocido: NewsAPI.org es gratuita solo en desarrollo (100 req/día, 24 h de retardo) y salta a $449/mes en Business —y ni en pago entrega el cuerpo completo de los artículos (Github) . La alternativa estructural es GDELT, gratuita y sin clave: la DOC 2.0 API (https://api.gdeltproject.org/api/v2/doc/doc) monitoriza prensa, web y broadcast en más de 100 idiomas con cadencia de 15 minutos, modos ArtList, TimelineVol (detección de breaking news por volumen) y ToneChart, con 250 registros por consulta y rate limits agresivos que exigen caché (Fundamentals Hub) . En pago accesible, Benzinga distribuye su wire en tiempo real, ratings con historia desde 2012, earnings y guidance vía Massive por $99/mes por paquete, y lanzó su servidor MCP en noviembre de 2025 (templates) . En el segmento institucional, RavenPack procesa más de 40{,}000 fuentes con más de veinte indicadores de sentimiento y 20+ años de archivo por un estimado de \(50{,}000–\)100{,}000+ anuales (confianza media: sin precio público), sin cubrir redes sociales (TL;DR Filing) .
Tabla 4.3 — Fuentes de noticias y sentimiento (a julio de 2026)
| Fuente | Cobertura / latencia | Precio | ¿Servidor MCP? | Notas para agentes |
|---|---|---|---|---|
| GDELT DOC 2.0 API | 100+ idiomas, cadencia 15 min, modos ArtList/Timeline/ToneChart | $0, sin key; 429 frecuentes (Fundamentals Hub) | Sí (MissionSquad/mcp-gdelt, comunitario) (Fundamentals Hub) | Caché y dedupe obligatorios; ventana ~3 meses en DOC API |
| Benzinga (vía Massive) | Wire real-time, ratings desde 2012, earnings, guidance | $99/mes por paquete; Pro \(37–\)197/mes (templates) | Sí, oficial (nov-2025) (Cambridge University Press & Assessment) | JSON estructurado por evento; cliente Python oficial |
| Alpha Vantage NEWS_SENTIMENT | Titulares + scores de sentimiento por ticker | Incluida en premium $49,99+/mes (MDPI) | Sí, oficial (MDPI) | Cómoda para prototipos; revisar profundidad de archivo |
| NewsAPI.org | Titulares/descripciones; archivo 1 mes (gratis) a 5 años | $0 dev → $449/mes Business; sin full-text (Github) | Comunitarios | Precipicio dev→producción; scraping aparte para cuerpo |
| RavenPack / Bigdata.com | 40{,}000+ fuentes, ESS, 13 idiomas, latencia ms | ~$50–100K+/año estimado (TL;DR Filing) | Plataforma agéntica propia | Estándar en hedge funds sistemáticos; sin redes sociales |
| SEC Form 4 / 13F (EDGAR) | Insiders (2 días hábiles) / holdings (45 días de retardo) | $0 (Apify) | No | Señal regulatoria; ver advertencias temporales abajo |
Interpretación. La lectura de la tabla es que el coste de las noticias no está en la API sino en el procesamiento posterior: GDELT es gratis pero devuelve ruido y republicaciones que hay que deduplicar antes de que un LLM cuente volumen como señal; Benzinga cobra por entregar el evento ya estructurado (acción de rating, price target, firma) (templates) . La disponibilidad de servidores MCP oficiales en tres filas accesibles es el cambio de 2026 con mayor impacto arquitectónico: un agente LangGraph descubre GDELT, Benzinga y Alpha Vantage como tools sin wrappers propios, aunque la cuota y el entitlement subyacentes siguen aplicando (MDPI) . Finalmente, la elección GDELT-vs-Benzinga-vs-RavenPack no es de calidad sino de presupuesto y latencia: para research diario, GDELT con dedupe basta; para señal intra-día con valor de tiempo, el wire estructurado justifica su precio.
Consulta GDELT real:
import requests
def gdelt_artlist(query: str, timespan: str = "1week", maxrecords: int = 50) -> list[dict]:
"""Artículos recientes de GDELT DOC 2.0 (sin API key; respetar ~6 s entre llamadas)."""
params = {"query": query, "mode": "artlist", "format": "json",
"timespan": timespan, "maxrecords": maxrecords}
r = requests.get("https://api.gdeltproject.org/api/v2/doc/doc",
params=params, timeout=30)
r.raise_for_status()
arts = r.json().get("articles", [])
seen, out = set(), []
for a in arts: # dedupe por URL/título: las wires republican la misma noticia
key = a.get("url", a.get("title"))
if key not in seen:
seen.add(key)
out.append(a)
return out
Dos fuentes regulatorias merecen mención aparte. El Form 4 de insiders se presenta en dos días hábiles desde la transacción: es la señal legalmente mandatada más fresca del mercado estadounidense —el comportamiento insider aparece ahí antes que en 13F, notas de research o prensa—, con XML gratuito en EDGAR y APIs como sec-api.io que lo estructuran (Apify) . El 13F, en cambio, refleja posiciones de cierre de trimestre publicadas con 45 días de retardo, solo largos en valores 13(f) —sin cortos ni la mayoría de derivados—: contexto histórico, nunca posicionamiento actual (TL;DR Filing) .
Sobre la explotación del sentimiento, dos advertencias empíricas. La primera es la deduplicación: las agencias wire republican la misma noticia decenas de veces, y contar volumen sin dedupe por URL/título infla la señal (orthogonal.info) . La segunda es el alpha decay: el rendimiento de una señal de sentimiento decae con su adopción, lo que obliga a regenerar variantes continuamente (orthogonal.info) . Un modelo de trabajo habitual es el decaimiento exponencial
donde \(\lambda\) crece con la difusión de la señal; la semivida \(t_{1/2}\) de señales de sentimiento públicas se mide en meses, no en años (orthogonal.info) .
Trampa común: medir «volumen de noticias» sin deduplicar
Una señal tan ingenua como «número de artículos que mencionan NVDA hoy» está rota antes de empezar: las agencias wire republican la misma noticia decenas de veces y GDELT las recoge todas. Un día con una sola noticia real —una nota de resultados de una agencia, por ejemplo— puede devolver 250 registros de los que apenas 90–100 son piezas distintas; el resto es la misma pieza con distinta cabecera y medio. Sin el dedupe por URL/título que ya lleva gdelt_artlist, el pipeline cuenta 250 y concluye «día informativo extraordinario» cuando ocurrió exactamente una cosa.
La contaminación es peor que ruido: es ruido correlacionado con la importancia de la noticia, porque las noticias grandes se republican más. La señal resultante no mide volumen informativo sino velocidad de republicación de las wires. El antídoto es barato —un set sobre URL o título normalizado— pero hay que aplicarlo antes de cualquier conteo, scoring de sentimiento o estadística de frecuencia. Y aun deduplicada, pesa la segunda advertencia del módulo: el alpha de una señal de sentimiento pública decae con su adopción (\(\alpha_t = \alpha_0 e^{-\lambda t}\), semivida de meses), así que el dedupe te da la señal limpia, no la señal eterna.
4.4 Arquitectura de pipelines point-in-time
4.4.1 La regla de oro de los datos: "texto al vector store, números a SQL"
Todo lo anterior converge en una decisión de diseño única, la que organiza la arquitectura de referencia del curso (insight estructural I5) —la regla de oro de los datos, hermana de la regla de oro del curso de §1.2.2, aplicada a la capa de almacenamiento—: el texto no estructurado va al vector store; los números van a bases relacionales/columnares y se consultan con tools deterministas. Los embeddings son recuperación semántica, no un almacén de cifras exactas: un LLM que "recuerda" un ingreso vía similitud vectorial puede recuperar el periodo equivocado o deformar la cifra, mientras que una query SQL sobre XBRL devuelve el valor con su filed y su accession number (Apify) . La partición concreta: al vector store van secciones de 10-K/10-Q (Item 1A, Item 7), transcripts y noticias full-text, con metadata {ticker, form, filing_date, section} para filtros pre-retrieval; a SQL/columnar van OHLCV, hechos XBRL, holdings 13F, transacciones Form 4 y estimados; a Redis, el estado caliente (Apify) . El stack se simplifica si el vector store es pgvector dentro del propio Postgres/TimescaleDB (Apify) .
En el transporte numérico, el patrón estándar es: WebSocket del vendor → productor Python → topics de Kafka particionados por símbolo (preserva el orden por activo) → consumidores → almacenes, usando el timestamp del exchange como event-time para que el jitter no reordene los cálculos; la replayability de Kafka permite regenerar features sin re-descargar del vendor (博客园) . En serving, TimescaleDB (Postgres) aporta hypertables y continuous aggregates que pre-calculan OHLCV unas 100 veces más rápido que vistas sobre ticks crudos, con compresión del 90–95 % (Apify) :
CREATE TABLE tick_data (time TIMESTAMPTZ NOT NULL, symbol TEXT NOT NULL,
bid NUMERIC(20,8) NOT NULL, ask NUMERIC(20,8) NOT NULL);
SELECT create_hypertable('tick_data', 'time');
CREATE MATERIALIZED VIEW tick_1m_view WITH (timescaledb.continuous,
timescaledb.materialized_only = false) AS
SELECT time_bucket('1 minute', time) AS time, symbol,
FIRST((bid+ask)/2, time) AS open, MAX((bid+ask)/2) AS high,
MIN((bid+ask)/2) AS low, LAST((bid+ask)/2, time) AS close
FROM tick_data GROUP BY time_bucket('1 minute', time), symbol;
SELECT add_retention_policy('tick_data', INTERVAL '30 days');
Para research y backtest, el patrón de facto es Parquet particionado (year=/month=/symbol=) consultado con DuckDB in-process —lectura columnar con predicate pushdown y coste marginal cero—, reservando TimescaleDB para serving (Entropy Method: Solving RL Without Gradients) . La pieza que cierra el bucle temporal es Feast, feature store con offline store (entrenamiento) y online store (serving) cuyo point-in-time join genera datasets con exactamente la semántica anti-look-ahead que un backtest exige: cada feature se une con el último valor disponible en el instante de la etiqueta, no con el último conocido hoy (Accuweather Api) .
En palabras llanas: por qué los números no van al vector store
Un embedding es un resumen matemático del significado de un texto, no una fotocopia de sus cifras. Si guardas «los ingresos fueron 394.300 millones» como vector, lo que recuperas después es texto parecido —quizá el trimestre equivocado, quizá la cifra de otra empresa del mismo sector— y el LLM lo reescribe con su fluidez habitual. Es el mecanismo de la alucinación numérica, ahora con infraestructura cara alrededor. En cambio, una query SQL sobre la tabla XBRL devuelve el valor exacto con su filed y su accession number: auditable, repetible y sin interpretación.
La partición del módulo resume en una frase lo que un desk tarda meses en aprender a base de incidentes: el texto va al vector store con metadata para filtrar, los números a SQL/columnar consultados con tools deterministas, y el estado caliente a Redis.
Nota la flecha intermedia del diagrama: el agente nunca «recuerda» cifras, las pide a una tool que ejecuta SQL. Por eso pgvector dentro del propio Postgres simplifica tanto el stack —una sola base de datos guarda las dos mitades de la regla de oro—.
4.4.2 Trampas de datos: look-ahead, survivorship y universos point-in-time
La regla de disponibilidad que define point-in-time (PIT) es simple de enunciar y costosa de implementar: un hecho \(f\) solo puede alimentar la decisión en el instante \(t\) de la simulación si su fecha de publicación efectiva es anterior o igual a \(t\):
Hay tres violaciones habituales, con antídotos distintos (orthogonal.info) . Primera, los restatements: usar el valor corregido de un fundamental antes de que la corrección fuera pública. El caso canónico es Plug Power: la pérdida diluida del año fiscal 2018 se reportó originalmente en $0{,}36 por acción y fue re-expresada a $0{,}39 en un filing del 14 de mayo de 2021; cualquier simulación de 2019 o 2020 que use $0{,}39 ha filtrado dos años de futuro (orthogonal.info) . La API XBRL de la SEC da filed por hecho, pero muestra la última versión de cada periodo —no preserva el valor pre-restatement—; para PIT estricto hacen falta Compustat Point-in-Time, el modo PIT de Bloomberg, Norgate, motores como QuantConnect LEAN (fundamentales "as of" la fecha de publicación) o una capa de versionado propia sobre accn + filed (orthogonal.info) .
Nota de riesgo. El look-ahead en fundamentales es la sobreestimación más silenciosa de los backtests con datos LLM: no deja excepciones en los logs, el pipeline corre limpio y el Sharpe sale inflado. El caso Plug Power ($0{,}36 → $0{,}39) parece inofensivo hasta que se multiplica por miles de hechos XBRL re-expresados cada año. Violación hermana: el reporting lag —unir el dato anual al cierre del periodo cuando el 10-K llega 25–60 días después—. La auditoría temporal correcta formula una pregunta por cada input: "en el instante exacto en que se disparó esta señal, ¿podía un operador real haber conocido este número?" (orthogonal.info) . Si responder exige mirar el calendario de filings, la respuesta es no.
La tercera violación es el survivorship bias: un universo construido con los tickers vivos de hoy ha eliminado a los quebrados, adquiridos y deslistados, y nunca ve los peores resultados. La magnitud no es menor: en un estudio de Morningstar, el 58 % de los fondos existentes en 1999 ya no existía en 2019 (Accuweather Api) . Y hay una limitación estructural del stack barato: APIs como yfinance o Alpha Vantage no sirven delistados, por lo que un backtest serio de larga historia requiere fuentes con delistings (Norgate, CRSP) y universos point-in-time que reconstruyan los constituyentes del S&P 500 de cada fecha, no los de hoy (Accuweather Api) . Complementos del checklist: desplazar toda señal una barra (lo calculado con la barra \(N\) no puede operar hasta la apertura de \(N+1\)), timestamps de exchange frente a recepción, detección de huecos por halts, validación de nulos en XBRL y dedupe de noticias (orthogonal.info) .
Con este módulo, el lector dispone de las fuentes (4.1–4.3) y de la arquitectura temporalmente honesta (4.4) que consumirán los agentes posteriores: el Módulo 5 (RAG) se construirá sobre la rama documental del diagrama, y los Módulos 7 y 8 sobre la rama numérica y sus joins PIT.
Ejemplo trabajado: la cronología Plug Power, paso a paso
El caso canónico de look-ahead por restatement merece verse como cronología, porque el error no está en ningún dato suelto sino en el orden en que se conocieron los hechos:
| Fecha | Evento | EPS diluido FY2018 público en ese instante |
|---|---|---|
| 31-dic-2018 | Cierre del año fiscal 2018 | (aún sin publicar) |
| mar-2019 | 10-K original (filed) |
−0,36 USD por acción |
| 01-ene-2020 | Instante de la decisión simulada | −0,36 USD (único valor conocido) |
| 14-may-2021 | Restatement en filing posterior (filed) |
−0,39 USD por acción |
| Hoy | Query ingenua a la API XBRL (última versión del periodo) | −0,39 USD ← la trampa |
La regla PIT del módulo aplicada a la tabla: en la fila de la decisión (01-ene-2020) solo cuenta lo que tiene filed anterior o igual a esa fecha, es decir −0,36 USD. Cualquier simulación de 2019 o 2020 que use −0,39 ha filtrado hasta dos años de futuro.
Recorrido: el 10-K original de PLUG (presentado en marzo de 2019) reportó la pérdida diluida de FY2018 en 0,36 USD por acción, y ese fue el único valor público durante más de dos años. El 14 de mayo de 2021 un filing posterior la re-expresó a 0,39 USD. La API XBRL de la SEC —que muestra la última versión de cada periodo— devuelve hoy 0,39 para FY2018; una query ingenua de «EPS de FY2018» lo inyecta en una simulación de 2019 o 2020 y el futuro queda filtrado sin una sola excepción en los logs. Por eso la nota de riesgo del módulo lo llama la sobreestimación más silenciosa: el pipeline corre limpio y el Sharpe sale inflado.
El antídoto es el patrón que el Ejercicio 2 pide construir: filtrar por filed anterior o igual a la fecha de decisión y quedarse con el último hecho disponible. Tres detalles lo hacen funcionar en producción: conservar accn + filed de cada hecho (son la clave de versionado), no sobrescribir jamás el valor original al cargar un restatement, y aplicar la misma disciplina al reporting lag —el 10-K llega 25–60 días después del cierre, así que «periodo terminado a 31 de diciembre» y «dato público» son fechas distintas—.
Ejercicios
-
Explorador EDGAR. Escriba un script que, dado un ticker, resuelva el CIK con
company_tickers.json, descarguesubmissionsy liste los últimos diez 10-K/10-Q con la URL del documento construida desdeaccessionNumberyprimaryDocument. Respete 10 req/s y añada backoff exponencial ante un 429. Extienda para medir el reporting lag observado: días entreperiodOfReportyfilingDatede los 10-K de cinco empresas. -
Tool XBRL point-in-time. Convierta
get_xbrl_conceptenget_concept_asof(ticker, concept, as_of_date), que filtre hechos confiled <= as_of_datey devuelva el último disponible. Verifique la trampa Plug Power: consulteEarningsPerShareDilutedde PLUG y demuestre que una query ingenua (último valor de FY2018) y la query PIT conas_of_date = 2020-01-01devuelven valores distintos. -
Diseño de pipeline. Dibuje (Mermaid o pseudocódigo) el pipeline de una estrategia que opera con noticias Benzinga y confirma con fundamentales EDGAR: asigne cada componente a Kafka, TimescaleDB, Parquet/DuckDB, Feast o vector store; justifique para cada dato si es "texto" o "número"; anote dónde un error introduciría look-ahead. Estime el coste mensual a julio de 2026 con la Tabla 4.1, incluyendo la tarifa non-display aplicable.
-
Análisis de licencias. Un PM propone alimentar un agente de research con (a) titulares de yfinance, (b) quotes de Massive plan Starter $29/mes y (c) transcripts obtenidos por scraping. Para cada fuente, identifique el conflicto de licencia o ToS, proponga la alternativa mínima conforme (con precio a julio de 2026) y redacte el párrafo de justificación para compliance.
-
Deduplicación y alpha decay. Con
gdelt_artlist, recolecte tres días de artículos sobre cinco tickers de semiconductores. Cuantifique la tasa de duplicados antes y después del dedupe y discuta cómo contamina una señal de "volumen de noticias". Estime la semivida bajo \(\alpha_t = \alpha_0 e^{-\lambda t}\) si el Sharpe ex-ante cae un 50 % en ocho meses.
Módulo 4 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
- SEC — EDGAR Application Programming Interfaces (oficial): la referencia que manda sobre cualquier tutorial: endpoints JSON, política de User-Agent, límite de 10 req/s y descargas bulk para backfills.
- GDELT — anuncio de la DOC 2.0 API (blog oficial del proyecto): los modos ArtList, TimelineVol y ToneChart explicados por quien los construyó, con los límites reales de la API gratuita.
- Feast — point-in-time joins (documentación oficial): la semántica anti-look-ahead de §4.4 ya implementada; léela antes de escribir un join temporal a mano.
- TimescaleDB — continuous aggregates (documentación oficial): cómo se materializan los OHLCV del listado SQL del módulo y qué garantiza la política de refresco.
- DuckDB — lectura de Parquet (documentación oficial): predicate pushdown y particionado hive, la mitad «backtest» del stack de research.
- Loukas et al. — EDGAR-CORPUS (arXiv:2109.14394): el corpus de NLP sobre filings que fundamenta buena parte del research documental sobre EDGAR; prepara el terreno del RAG del Módulo 5.
- LangChain — documentación de tools: el contrato exacto del decorador
@tool(docstring, argumentos, errores) que usaget_xbrl_concept. - Apache Kafka — documentación oficial: particionado por clave y retención, los dos mecanismos detrás del «topic por símbolo» y de la replayability del pipeline.
Comprueba lo aprendido
Autoevaluación con feedback inmediato. No se guarda ninguna puntuación: es solo para ti.