Dashboard de riesgo de acciones con Claude Code y RiskModels

Claude Code puede construir la interfaz en minutos. La pregunta difícil es si esa interfaz sabe algo real sobre riesgo de acciones.
Pídele a Claude Code que construya un dashboard de riesgo de acciones y normalmente producirá algo pulido: un campo para el ticker, un gráfico de volatilidad móvil, una matriz de correlación, quizá una beta frente al SPY.
La aplicación puede compilar. Los gráficos pueden verse profesionales. Pero el resultado sigue limitado por la información disponible para el agente.
Un agente de código es un constructor, no un modelo de riesgo.
Sin una fuente estructurada de conocimiento de dominio, puede calcular estadísticas conocidas a partir del histórico de precios. No puede determinar de forma fiable cuánto del riesgo de una posición viene del mercado, de su sector, de su subsector, o de la propia acción — ni qué ETF líquido cubre cada capa.
Esa es la distinción que este proyecto pone a prueba.
Conecté Claude Code al servidor MCP de RiskModels, le di un prompt deliberadamente incompleto, y le pedí que construyera un dashboard interactivo en torno a ERM3, el modelo jerárquico de riesgo de acciones de RiskModels.
Esto es lo que construyó Claude en unos cinco minutos
Claude no inventó un modelo de riesgo. Ensambló un frontend en torno a uno. En la instantánea en vivo usada para este artículo (datos a fecha de 2026-07-14), la vista comparativa ya muestra por qué esto importa:

CRM, MSFT y NVDA en la misma fecha de modelo. Una volatilidad total similar no revelaría que CRM y MSFT tienen mucho peso en subsector y residual mientras que NVDA carga mucha más cuota de mercado.
Esa pantalla es la recompensa. Todo lo de abajo es cómo se llegó ahí — y por qué el agente igualmente necesitó una API de dominio para acertar las respuestas.
Cómo se conectan las piezas
El bucle es corto: un prompt a Claude Code, herramientas MCP contra RiskModels, una llamada a ERM3, una interfaz en Streamlit.
Prompt → Claude Code → RiskModels MCP → /decompose → Dashboard
RiskModels expone ERM3 vía REST, Python, CLI, y MCP (https://riskmodels.app/api/mcp/sse). Se instala en local con npx -y riskmodels@latest install. El endpoint para este proyecto es POST /api/decompose: cuatro capas de varianza aditivas (market, sector, subsector, residual), cada una con er, hr, y hedge_etf, más un mapa hedge con signo. Las cuatro cuotas de ER suman ≈ 1. Residual no tiene ETF de cobertura — es varianza no explicada, no alfa.
El prompt — y el error que reveló la lección
Deliberadamente no le di a Claude una especificación de UI detallada. La idea era ver qué podía inferir una vez tuviera acceso a un esquema de riesgo real.
Build a Streamlit dashboard using the RiskModels decomposition API. Let the user compare several tickers, inspect the four ERM3 risk layers for one stock, see the ETF hedge notionals per $1 long, and visualize which risk remains after applying an L1, L2, or L3 hedge. Validate the API response and explain residual risk correctly.
Claude gestionó bien el andamiaje: layout en Streamlit, llamadas cacheadas, validación, vistas comparativas, operaciones de cobertura legibles.
Pero la primera versión cometió un error conceptual revelador: describió el riesgo residual como "alfa no capturada".
Esa frase suena plausible. También es incorrecta. El ER residual es una cuota de varianza sin signo y sin ninguna afirmación sobre rentabilidades futuras.
Un prompt corrector arregló la etiqueta. La lección se quedó: el agente es excelente construyendo software y flojo inventando significado financiero que no estaba codificado en las herramientas o instrucciones.
Qué responde el dashboard
1. ¿A qué está realmente expuesta la posición?
Para CRM en la misma instantánea:

Market 3,4%, sector 0,9%, subsector 52,4%, residual 43,3%. El subsector (IGV) domina; una beta de un solo factor frente al SPY se perdería eso.
Una beta convencional comprime la posición en una sola relación de mercado. ERM3 pregunta si la variación se asocia al mercado amplio, al sector, a un subsector más estrecho, o a la propia acción.
2. ¿Qué ETFs cubren esas capas?
Por cada $1 largo en CRM:
SPY +0.160
XLK -0.645
IGV +1.063

Nocionales de ETF con signo por $1 de acción en largo: positivo = largo en el ETF, negativo = corto en él.
Esos signos vienen de cómo se estima ERM3. El modelo ajusta primero mercado, luego sector, luego subsector como una cascada secuencial ortogonal: el hr de cada capa mide exposición incremental una vez se han eliminado las capas más amplias — no una beta OLS univariante sobre ese ETF por sí solo. El mapa hedge de /decompose invierte el hr de cada capa negociable (el negativo del hr, duplicados sumados), así que los números de arriba son dólares de ETF por $1 de acción en largo. Para CRM eso es SPY +0,160, XLK −0,645, IGV +1,063 — largo en SPY e IGV con una pata corta en XLK. Las betas independientes pueden no coincidir con esos signos porque XLK e IGV comparten exposición a mercado/tecnología que ya se ha aislado aguas arriba. Lee el mapa hedge; no reconstruyas la operación a partir de intuición univariante.
3. ¿Qué queda tras cada nivel de cobertura?
- Sin cobertura conserva las cuatro capas.
- L1 elimina mercado.
- L2 elimina mercado y sector.
- L3 elimina mercado, sector, y subsector.

Base sin cobertura (Hedge depth = None): las cuatro capas de CRM siguen presentes. Seleccionar L1 / L2 / L3 pone a cero mercado, luego sector, luego subsector — tras L3 solo queda residual en estas unidades de ER, no porque residual se haya convertido en el 100% de la varianza, sino porque las capas sistemáticas modeladas se pusieron a cero.
Esta es una vista de atribución, no una promesa de rendimiento de cobertura realizado.
4. ¿Por qué se comporta CRM distinto a MSFT?
Una vez existen los paneles, la pregunta interesante es interpretativa — y ahí es donde un agente de código anclado al modelo empieza a sonar como si entendiera el riesgo en lugar de simplemente graficarlo:
User:
Why is CRM behaving differently from MSFT?
Claude:
CRM's risk is primarily concentrated in the IGV subsector,
whereas MSFT still carries substantially more market exposure.
A market hedge removes relatively little CRM variance.
An IGV hedge removes far more.
Esa respuesta no es una intuición sacada de gráficos de precio. Es una lectura de las mismas capas estructuradas que renderiza el dashboard.
Tampoco tienes que confiar ciegamente en los gráficos del agente
Hay una segunda frontera de confianza que este proyecto puso de manifiesto. Las capturas de arriba son la interfaz en Streamlit que construyó Claude — valores por defecto de Plotly, decisiones de layout, y todo lo demás. Incluso con números correctos de /decompose, un gráfico dibujado por un agente sigue siendo la interpretación del agente sobre escala, orden, y énfasis.
RiskModels cierra esa brecha de la misma forma que cierra la brecha de datos: la plataforma también sirve sus propios paneles canónicos. La misma instantánea de CRM / MSFT / NVDA es direccionable, sin modificar, desde
GET /api/snapshot/stock/{ticker}/panels/{slug}?format=png
con los slugs l3_explained_risk_hbar, hedge_notionals_hbar, hedge_depth_retained, y watchlist_er_stacked (pasa tickers=CRM,MSFT,NVDA para el panel de watchlist). Estos son artefactos de un registro — código de renderizado versionado y mantenido junto al modelo — no gráficos de notebook. Un agente puede incrustar esos bytes en lugar de reinventar los gráficos, lo que significa que un dashboard de producción y los propios artefactos de investigación de la plataforma nunca pueden discrepar en silencio.
El código
La llamada principal es deliberadamente sencilla:
@st.cache_data(ttl=3600)
def get_decomposition(ticker: str) -> dict:
response = requests.post(
"https://riskmodels.app/api/decompose",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"ticker": ticker},
timeout=30,
)
response.raise_for_status()
payload = response.json()
validate_decomposition(payload)
return payload
La validación comprueba que las cuatro capas existen, que los ER son numéricos y suman cerca de 1,0, y que el objeto hedge tiene la forma esperada. Las apps generadas por IA no deberían asumir en silencio que cada payload está completo.
Las vistas por nivel de cobertura operan directamente sobre las capas aditivas — poniendo a cero mercado, luego sector, luego subsector — sin fingir que recalculan una futura matriz de covarianza. La app completa de Streamlit se publica junto con este artículo.
Por qué importa MCP
MCP deja que el agente descubra herramientas, inspeccione esquemas, las llame mientras trabaja, y revise la UI en torno a respuestas reales — en lugar de copiar nombres de campo de la documentación.
Eso es un bucle más fuerte que una integración REST normal. Con un cliente HTTP codificado a mano, el desarrollador todavía tiene que saber qué endpoints existen, qué significan sus esquemas, y cómo interpretar cada campo. Con MCP, Claude puede enumerar las operaciones disponibles, leer descripciones de capacidades estructuradas, invocar herramientas mientras construye el andamiaje de la app, e iterar contra respuestas tipadas — trabajando dentro de la superficie de herramientas de la plataforma, no solo pegando una URL en requests.post.
Las responsabilidades quedan separadas: Claude Code construye la interfaz; RiskModels aporta el modelo de dominio y los datos actuales; el desarrollador verifica la interpretación. El resultado no es experiencia financiera autónoma. Es una forma más rápida de ensamblar software en torno a una fuente de experiencia explícita e inspeccionable.
Hacia dónde puede ir esto
Los cuatro paneles de arriba son la puerta de entrada a una superficie más profunda. La misma plataforma los compone — más comparaciones de ADN de riesgo entre pares, cascadas de descomposición de rentabilidad, y trayectorias de fundamentales — en una página completa de análisis institucional:

La página institucional de una hoja para NVDA (en vivo; la instantánea mostrada aquí es de 2026-07-13; las cifras del dashboard de arriba son de 2026-07-14). Los paneles de este artículo son las piezas direccionables del mismo tipo de análisis.
Las construcciones más ricas se mantienen en la misma frontera: tablas de cartera ordenadas por cuota residual, nocionales de cobertura ponderados por holdings, alertas de deriva, descomposición de rentabilidad, explicaciones en lenguaje natural ancladas en ERM3. El paso importante no es añadir más gráficos. Es preservar qué genera el agente frente a lo que sabe el sistema de dominio.
Ideas clave
Los agentes de código generan software. No generan verdad financiera.
Un gráfico pulido construido a partir de una beta improvisada sigue siendo una beta improvisada. Conectar el agente a un modelo documentado cambia la calidad del resultado porque le da al software una estructura explícita que representar.
El dashboard siempre se iba a construir rápido. Eso es lo que se les da bien a los agentes de código.
La diferencia importante es que sus campos de mercado, sector, subsector, residual, y cobertura vienen de un modelo de riesgo de acciones real en lugar de cálculos con apariencia plausible inventados dentro de la aplicación.
A medida que los agentes de código se vuelven omnipresentes, la ventaja competitiva se desplaza de escribir software hacia poseer experiencia estructurada y legible por máquina. En finanzas cuantitativas, esa experiencia es el modelo.
El mismo patrón de agente-más-MCP se extiende de forma natural más allá de /decompose — y buena parte de esa superficie ya está en vivo: fundamentales en un momento dado con coste de capital derivado de las mismas betas (GET /api/fundamentals/{ticker}, con clientes MCP y SDK), instantáneas de fondos mutuos y de declarantes 13F, rankings por cohorte de estilo, y los paneles de investigación direccionables usados arriba. La descomposición es un primer proyecto limpio; la idea más grande es una plataforma de investigación cuantitativa nativa para IA donde los agentes de código son la interfaz de una experiencia de mercado estructurada, en lugar de los autores de esa experiencia.
Empieza
Instalación local en Claude Code / Cursor:
RISKMODELS_API_KEY=your_api_key_here npx -y riskmodels@latest install
SDK de Python:
python3 -m pip install "riskmodels-py>=0.3.4"