IBKR Portfolio Builder

Investigación de carteras de arriba hacia abajo para Interactive Brokers con un catálogo tipificado de 468 filtros de IBKR etiquetados por intención de estrategia. Solo lectura.

Documentación

ibkr-portfolio-builder-mcp

Un servidor MCP remoto para la construcción de carteras de arriba hacia abajo con Interactive Brokers. Diseñado para usarse como conector personalizado de Claude.ai, MCP de Claude Code, o cualquier cliente HTTP MCP.

La mayoría de los servidores ibkr-mcp exponen primitivas de búsqueda individuales — get_quote, get_position, place_order. Este expone el flujo de trabajo de investigación: un catálogo tipado de 468 screener en 16 categorías etiquetadas por intención de estrategia (valor / crecimiento / ingresos / momentum / calidad / eventos / …), instrumentos aplicables por escaneo, enlaces de pares inversos y acceso a noticias/cuenta en vivo — para que un LLM pueda hacer una construcción de carteras real de arriba hacia abajo (elegir sectores / estrategias → ejecutar escaneos → contrastar con noticias → reducir a candidatos) en lugar de buscar tickers de abajo hacia arriba.

Por qué existe esto

Lo construí porque los servidores IBKR-MCP existentes en la comunidad tratan a IBKR como una fuente de datos de "buscar un ticker". Eso refleja cómo funcionan la mayoría de las interfaces de los brókeres minoristas, pero no es así como se hace una buena construcción de carteras.

Un buen flujo de trabajo de arriba hacia abajo se ve así:

  1. Tesis macro ("las tasas están por caer, los pagadores de dividendos deberían revalorizarse") →
  2. Intención de estrategia ("muéstrame screener de ingresos con sesgo de calidad en grandes capitalizaciones de EE. UU.") →
  3. Composición del screener (ejecutar screener de rendimiento de dividendos + ROE + baja deuda; intersectar) →
  4. Contexto de eventos/noticias ("¿alguno de estos tiene ganancias en las próximas dos semanas? ¿alguna acción negativa de analistas?") →
  5. Conjunto de candidatos reducido ("cinco tickers, clasificados por mis criterios, listos para un análisis más profundo").

Para hacer eso con un LLM, el servidor MCP necesita exponer el vocabulario de investigación, no solo la API cruda. Esa es la brecha que este servidor llena:

  • Un catálogo de escaneos tipado — 468 códigos de escaneo de IBKR en 16 categorías (Fundamentals, Price Movement, Dividends, Options & Volatility, Events & Earnings, 52/26/13 Week High-Low, ESG, Bonds, …) autoetiquetados con 28 etiquetas de intención de estrategia (value, growth, quality, income, momentum_up, momentum_down, analyst, technical, gap, volatility, events, leverage, efficiency, risk_adjusted, …). El LLM pregunta "¿qué escaneos de valor existen para acciones de EE. UU.?" y obtiene una respuesta limpia y filtrable en lugar de intentar adivinar códigos de escaneo a partir de datos de entrenamiento.
  • Enlaces de pares inversos — cada par HIGH_X ↔ LOW_X y X_ASC ↔ X_DESC está precalculado, para que el LLM pueda invertir la polaridad ("¿cuál es lo opuesto de LOW_PE_RATIO?") sin adivinar.
  • Mapa de instrumentos por escaneo — el catálogo sabe qué escaneo aplica a STK, ETF, OPT, BOND, etc. El LLM deja de enviar escaneos de Refinitiv a instrumentos de bonos y obtener resultados vacíos.
  • Catálogo de filtros — mapa tipado separado de los filtros numéricos (priceAbove, peRatioBelow, divYieldAbove, growthRateAbove, avgVolumeAbove, marketCapAbove, …) agrupados por categoría, con notas de aplicabilidad por instrumento.
  • Noticias + screener en una sola superficie de herramientas — mismo conector, misma autenticación, misma conversación. El LLM puede intersectar un resultado de escaneo con titulares recientes o ganancias próximas sin cambiar de contexto.
  • Dos modos de autenticación — OAuth 2.1 completo (DCR + PKCE + well-knowns) para conectores personalizados de Claude.ai, más un token bearer estático para todo lo demás. Mismo servidor, mismas herramientas.

Sigue siendo un servidor temprano. La API de IBKR tiene muchas restricciones sobre lo que una cuenta de papel puede ver realmente (notablemente el derecho a noticias históricas). Pero el catálogo y la forma del flujo de trabajo están listos para producción, y son la pieza clave para un bucle de investigación impulsado por LLM.

Datos rápidos

  • Transporte: HTTP Streamable en /mcp.
  • Autenticación: OAuth 2.1 (PKCE + Registro de Cliente Dinámico RFC 7591) Y/O token bearer estático. Seleccionable mediante AUTH_MODE.
  • Persistencia: solo en memoria hoy (las sesiones / clientes DCR / tokens OAuth se reinician al reiniciar el contenedor). Redis está en la hoja de ruta — ver más abajo.
  • Conexión IBKR: ib-gateway (ghcr.io/gnzsnz/ib-gateway:stable) se ejecuta como un servicio hermano en este compose; cuenta de papel en modo API de solo lectura por defecto.
  • Construido sobre: FastMCP + ib_async.

Herramientas

Paridad con el MCP oficial de IBKR para las 9 herramientas de solo lectura (omitiendo las dos herramientas de escritura/instrucciones de órdenes — ver hoja de ruta), más las 5 herramientas de screener/noticias/catálogo que son la razón de existir de este servidor.

HerramientaQué hace
ib_account_summaryNetLiquidation / BuyingPower / TotalCashValue / AvailableFunds / UnrealizedPnL para la cuenta de papel o en vivo conectada.
ib_positionsPosiciones abiertas en cuentas administradas, con cantidad / costo promedio / mark-to-market / PnL no realizado.
ib_open_ordersÓrdenes actualmente en curso con estado, cantidad completada / restante, precio de llenado promedio.
ib_tradesLlenados ejecutados recientes (ventana de days_back, IBKR limita el historial a ~7 días).
ib_price_snapshotBid / ask / último / alto / bajo / volumen actual para una acción de EE. UU. Muestra claramente los mensajes de restricción de datos de mercado de IBKR.
ib_price_historyBarras OHLCV para cualquier duración / tamaño de barra (1 day, 1 hour, 5 mins, ...). Siempre funciona independientemente de la suscripción de datos de mercado.
ib_search_contractsBúsqueda difusa en la base de datos de contratos de IBKR por nombre / ticker parcial.
ib_contract_detailsMetadatos completos del contrato — long_name, industry, category, subcategory, horario de negociación, bolsas válidas. El gancho para el screening top-down consciente del sector.
ib_scan_catalogEl catálogo de escaneos tipado. Filtrar por category, strategy, instrument, texto libre query; opcionalmente devolver la lista completa de categorías + estrategias disponibles mediante list_meta=true.
ib_filter_catalogCódigos de parámetros de filtro agrupados por categoría (price, volume, market_cap, fundamentals, technical, options), con una nota de aplicabilidad por instrumento.
ib_screener_codesBúsqueda de subcadenas sobre los códigos scan-parameters.xml crudos (legado / respaldo). Útil para códigos de proveedores más nuevos aún no incluidos en el catálogo curado.
ib_screenerEjecutar un escaneo de IBKR — pasar scan_code, instrument, location, filtros opcionales de precio / volumen. Devuelve rango + ticker + bolsa.
ib_news_providersListar los proveedores de noticias suscritos de IBKR (Briefing.com, Dow Jones, etc.).
ib_news_for_symbolObtener titulares para una acción de EE. UU. en todos los proveedores suscritos. Solo titulares; muestra un campo notice claro cuando la cuenta carece del derecho a noticias históricas.
ib_news_articleObtener el cuerpo de un solo artículo por provider_code + article_id. ⚠️ puede incurrir en una tarifa por artículo (Dow Jones en particular).

Nota sobre la colocación de órdenes. El MCP oficial de IBKR también expone Create Order Instruction y Delete Order Instruction. Este servidor intencionalmente no lo hace — ejecuta ib-gateway en modo READ_ONLY_API=yes para que ni siquiera una llamada de herramienta mal enrutada pueda colocar una orden. La ejecución de órdenes pertenece a un servicio separado con su propia puerta de aprobación. Ver la hoja de ruta para una posible herramienta de instrucciones "solo por etapas" que escribiría en un almacén local sin tocar nunca IBKR.

Autenticación

AUTH_MODE selecciona qué mecanismos acepta el servidor. El valor predeterminado es both.

ModoQué se aceptaEnv requerido
oauthSolo tokens emitidos por OAuth. Requerido para conectores personalizados de Claude.ai.LOGIN_PASSWORD
bearerSolo un Authorization: Bearer <token> estático. Omite el flujo de OAuth — mejor para clientes CLI, Claude Code, tus propios scripts.STATIC_BEARER_TOKEN
both (predeterminado)Ya sea tokens OAuth o el token bearer estático.Al menos uno de LOGIN_PASSWORD o STATIC_BEARER_TOKEN.

Los endpoints de OAuth (/authorize, /token, /register, /.well-known/*, /login) siempre están registrados. En modo bearer son inertes — nada en tu README necesita apuntar a ellos.

Generando secretos

uv run --no-project python -c "import secrets; print(secrets.token_urlsafe(48))"   # bearer token
uv run --no-project python -c "import secrets; print(secrets.token_urlsafe(48))"   # session secret

Usando el token bearer estático

curl -X POST https://YOUR.DOMAIN/mcp \
  -H "Authorization: Bearer $STATIC_BEARER_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Conectándose desde Claude.ai (OAuth)

Configuración → Conectores → Agregar conector personalizado → URL: https://YOUR.DOMAIN/mcp → deja el ID de cliente / secreto de OAuth en blanco (Claude.ai usa DCR). Cuando Claude.ai abra el flujo de OAuth, se te pedirá LOGIN_PASSWORD.

Ejecución

cp .env.example .env
# edit .env: set TWS_USERID / TWS_PASSWORD (paper account), LOGIN_PASSWORD, STATIC_BEARER_TOKEN, PUBLIC_BASE_URL
docker compose up -d

Por defecto esto extrae la imagen multiarquitectura publicada del Registro de Contenedores de GitHub: ghcr.io/adwiteeymauriya/ibkr-portfolio-builder-mcp:latest. Para construir localmente en su lugar (por ejemplo, al iterar sobre el código fuente), ejecuta docker compose build ibkr-mcp primero.

ib-gateway tarda ~60–90 s en completar el inicio de sesión de IBKR después del primer arranque. Sigue los registros con docker logs -f ibkr-mcp-gateway.

Para uso solo local (clientes con token bearer, sin Claude.ai) esto es suficiente — http://localhost:8000/mcp ya está sirviendo. Los conectores personalizados de Claude.ai requieren una URL HTTPS en internet público, por lo que se necesita un proxy inverso con TLS al frente.

Poniendo TLS al frente para Claude.ai

Elige una. Ambas terminan con un https://your-host/mcp funcional y un certificado válido.

Opción 1 — Cloudflare Tunnel (sin IP pública, sin reenvío de puertos). Mejor si el servidor se ejecuta en una red doméstica o en una VM detrás de NAT. Cloudflare te da un nombre de host y TLS gratis; el demonio del túnel se conecta desde el servidor al borde de Cloudflare.

# One-time: install cloudflared, then
cloudflared tunnel login
cloudflared tunnel create ibkr-mcp
cloudflared tunnel route dns ibkr-mcp ibkr-mcp.your-domain.com

~/.cloudflared/config.yml:

tunnel: ibkr-mcp
credentials-file: /home/you/.cloudflared/<TUNNEL_ID>.json
ingress:
  - hostname: ibkr-mcp.your-domain.com
    service: http://localhost:8000
  - service: http_status:404

Ejecuta con cloudflared tunnel run ibkr-mcp (o instala como una unidad systemd mediante cloudflared service install). Luego establece PUBLIC_BASE_URL=https://ibkr-mcp.your-domain.com en .env y docker compose restart ibkr-mcp.

Opción 2 — Proxy inverso Caddy con Let's Encrypt. Mejor si el servidor tiene una IP pública y los puertos 80/443 abiertos. Caddy obtiene los certificados automáticamente.

Caddyfile:

ibkr-mcp.your-domain.com {
    reverse_proxy localhost:8000
}

Ejecuta con caddy run (o instala como un servicio del sistema: sudo caddy start + una unidad systemd). El mismo cambio de .env que arriba.

En ambos casos, PUBLIC_BASE_URL debe coincidir exactamente con la URL que le das a Claude.ai — Claude.ai valida el emisor de OAuth contra ella.

Ejemplos de prompts para LLM (flujo de trabajo de arriba hacia abajo)

1. Discovery:
   "List the strategies and categories available in ib_scan_catalog."

2. Strategy intent:
   "Find me value scans for US stocks. Show me their inverse codes too."

3. Composition:
   "Run LOW_PE_RATIO on STK.US.MAJOR with priceAbove $20 and avgVolumeAbove
    1,000,000, top 30. Cross-reference with HIGH_RETURN_ON_EQUITY top 30.
    Show me overlap."

4. Event context:
   "For the overlap list, check ib_news_for_symbol for any negative
    headlines in the last 7 days, and Events & Earnings scans for
    upcoming earnings within 14 days."

5. Narrow:
   "Rank the survivors by liquidity and tell me which two you'd dig
    into next."

Hoja de ruta

ÁreaElemento
AutenticaciónSesiones respaldadas por Redis, clientes DCR, tokens OAuth
AutenticaciónÁmbitos por token (read-only, read-news, screener-only, ...)
InstrumentosOpciones (cadenas, griegas, cálculo de IV/precio)
InstrumentosFuturos (ContFuture, combos mediante Bag)
InstrumentosBonos (búsqueda + cotización)
InstrumentosForex + cripto
BolsasEnrutamientos de acciones no estadounidenses (UE, HK, JP, AU)
Bolsasib_account_summary consciente de la moneda
InvestigaciónFundamentos de Reuters (reqFundamentalDataAsync)
InvestigaciónBarras de streaming en tiempo real + tick por tick
InvestigaciónLibro de órdenes de Nivel 2
InvestigaciónFlujos de PnL diarios (pnlAsync, pnlSingleAsync)
InvestigaciónSubcuentas de asesor (reqFamilyCodesAsync)
InvestigaciónCatálogo → Memgraph para consultas de múltiples saltos
Investigaciónib_news_search más amplio
Riesgoib_what_if_order (vista previa de margen, sin ejecución)
RiesgoHerramientas de instrucciones por etapas locales (sin escritura en IBKR)

Los problemas abiertos / PRs son bienvenidos en cualquiera de estos.

Estructura

.
├── Dockerfile
├── docker-compose.yml             # connector + ib-gateway, internal IBKR network
├── pyproject.toml                 # uv-managed: fastmcp, itsdangerous, uvicorn, ib_async
├── uv.lock
├── .env.example
├── LICENSE                        # MIT
├── scan-parameters.xml            # IBKR's authoritative scan params (raw XML)
├── scanner_reference.json         # IBKR-categorized scanner reference
├── scanner_params.json            # Flat dump of scan codes + filters
├── scripts/
│   └── build_catalog.py           # Regenerates src/connector/data/* from the three source files above
└── src/
    └── connector/
        ├── settings.py            # env-driven config (incl. AUTH_MODE)
        ├── auth.py                # LoginGatedOAuthProvider + static bearer override + /login
        ├── ibkr.py                # ib_async connection helper (connect-per-call)
        ├── screener.py            # raw scan-parameters.xml substring search (fallback tool)
        ├── catalog.py             # typed scan + filter catalog loaders + filtering
        ├── tools.py               # 15 MCP tools wired into FastMCP
        ├── server.py              # FastMCP + Starlette wiring + uvicorn entry
        └── data/
            ├── scan_catalog.json  # generated
            └── filter_catalog.json # generated

Licencia

MIT.

Agradecimientos

Aviso legal

Este software se comunica con tu cuenta de Interactive Brokers. Por defecto se ejecuta contra una cuenta de papel en modo API de solo lectura — no se pueden colocar órdenes incluso si una herramienta lo intenta. Si cambias a una cuenta en vivo, lo haces bajo tu propio riesgo. Ninguna salida de las herramientas constituye asesoramiento de inversión; el etiquetado de estrategias es un ayudante de vocabulario, no un motor de recomendaciones.