Skip to main content
Glama
simoneb

ibkr-risk-mcp

by simoneb

stress_portfolio

Read-onlyIdempotent

Reprice your entire portfolio across market shocks to see the P&L curve and its trough, identifying the worst-case loss and the market move that triggers it.

Instructions

Reprice the whole portfolio — options, equities, futures — across underlying shocks and return the P&L curve and its trough.

The trough is the primary output: the worst point of the curve and the shock at which it sits. troughRefined interpolates between grid points for where the minimum actually falls, and is labelled as interpolated.

The model, returned with every result in assumptions:

  • only equity underlyings are on the axis by default (scope='equity'). FX, rates and anything else is excluded outright and listed under excluded with its market value. This is what Risk Navigator's Equity tab does, and it is what makes the two comparable — verified against a live account, where the engine and Risk Navigator agreed to 7 dollars on 29,000 at a 15% fall once the FX leg was off both. Off the equity axis the single shock is meaningless: the same account's CAD strangle was contributing -21,716 at -20% and -7,183 at +10%, dominating both tails.

  • all underlyings in scope are shocked by the same percentage at once, which is Risk Navigator's own default assumption. betas scales that shock per symbol and reaches every class that responds to one — an option is repriced at its own beta-scaled move, not at the index move. Use it to stand a foreign underlying down off an equity axis, and read the warning it produces: a beta of 0 takes a position off this curve, it does not measure that position's own risk.

  • options are repriced with Black-76 on the shocked forward using IB's implied volatility. Equity options are carried from spot using IB's pvDividend, so both kinds go through one pricer.

  • the volatility level is flat along the shock axis unless you say otherwise. Neither vol mode raises it: sticky_strike pins volatility to the strike, sticky_moneyness slides a strike along today's smile. Real volatility rises when an index falls, and a net short option book pays for that on top of the delta and gamma this curve already counts. vol_bump does not fill the gap — it is constant across shocks. vol_slope_down does: 1.0 adds one volatility point per 1% fall. It is your input, not a measurement, and it is applied as a parallel shift across every tenor.

  • P&L is model-price-now against model-price-shocked, so the curve is exactly zero at zero shock by construction. The gap between the local model and IB's own price is reported per position as modelVsMarket instead of being folded into the curve. Expect it to be small out of the money and a couple of percent in the money, where IB prices the early exercise that Black-76 has no room for — so the curve understates losses slightly once options go deep in the money.

  • bonds are held flat unless bond_rate_shift_bp is set; anything this server does not model is held flat and named in warnings.

  • breakdown='expiry' adds pnl_by_expiry to every point and troughByExpiry beside the trough — each expiry's own worst point and what it contributes at the portfolio's trough. On a book holding one root across many expiries those are the two different numbers behind "which short is the problem", and pnl_by_symbol can answer neither.

Check reconciled before quoting anything. At zero shock the portfolio is rebuilt from its positions and compared against NetLiquidation; a residual over 1% returns reconciled: false with the residual attached. A curve that does not reconcile is missing something, and the number it gives for the trough is missing it too.

Risk Navigator's own volatility shock model is not published. sticky_strike is the approximation that corresponds to its default curve, not a reproduction of it — expect the shape to match and the last few percent not to.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
betasNoPer-symbol share of the shock, e.g. {'AAPL': 1.2, 'EUR': 0.0}. Applies to options and futures as well as equities: the beta scales the move of that position's own underlying, and the option is then repriced there. Key it on the root ('ES'), the local symbol ('ESZ6 P5800') or the underlying ('ESZ6'); the most specific match wins. Use it to stand a foreign underlying down off an equity axis — but read the warning it produces: a beta of 0 removes a position from this curve, it does not measure its own risk.
scopeNoWhich underlyings are on the shock axis. 'equity' — the default — keeps only equity underlyings and excludes FX, rates and the rest outright, which is what TWS Risk Navigator's Equity tab does and what makes the curve comparable to it. Off the equity axis a single percentage shock is meaningless: a currency future moved 20% prices an exchange rate that has never traded there. 'all' shocks everything alike. Excluded positions are always listed under `excluded`, never dropped in silence.equity
shocksYesUnderlying moves as fractions: -0.10 is a 10% fall. A range like -0.30 to +0.30 in 0.01 steps is the usual ask.
vol_bumpNoAdded to every volatility, in points, flat along the shock axis: 0.05 is +5 points at every shock. For volatility that responds to the shock itself, use vol_slope_down.
vol_modeNosticky_strike keeps each strike's current volatility and is what Risk Navigator's default curve does. sticky_moneyness slides the smile with the forward.sticky_strike
breakdownNoWhich per-point P&L breakdowns to return. 'symbol' — the default and what this server has always returned — groups by root, which on an options book collapses every ES expiry under one 'ES' key. 'expiry' groups by the option's SETTLEMENT date instead ('ES 2026-10-30'), which is the breakdown that answers 'which expiry is holding the trough down, and which short do I buy back'. 'both' returns the two of them and 'none' neither. Positions with no expiry get a key naming their class ('ES (future)', 'AAPL (equity)') so the breakdown still sums to the point's total and can be checked against it. Responses are large: a book on nine expiries pays for the second dictionary at every one of twenty-six shocks, so ask for 'both' only when you want both, and 'none' when you only want the curve.symbol
fetch_skewNoLet sticky_moneyness pull neighbouring strikes from IB when the portfolio holds too few to define a smile. Costs extra market data requests.
risk_groupsNoOverride the risk group of a symbol, e.g. {'TLT': 'rates', 'GLD': 'metals'}. IB publishes no asset class for a bond or gold ETF quoted as a stock, so those are classified as equity unless named here. Groups: equity, fx, rates, metals, energy, other.
default_betaNo
vol_slope_upNoVolatility points removed per 1% RISE. Positive means volatility falls as the market rallies, which is the usual direction. Separate from vol_slope_down because the response is not symmetric.
valuation_dateNoValue the curve at this ISO date, e.g. '2026-09-30', instead of counting the days out by hand into date_offset_days. Mutually exclusive with it. No calendar magic: the date is the date, weekend or not, and time to expiry is ACT/365 throughout. The P&L is still measured FROM today at today's prices and volatilities, with the clock rolled forward — it is decay, not a forecast.
vol_slope_downNoVolatility points added per 1% FALL in the underlying: 1.0 means a -20% shock reprices at +20 points. Zero — the default — holds the volatility level flat, which prices the move in the underlying and not the move in volatility that comes with it. A net short option book loses real money on that term, so leaving this at zero is the optimistic half of the answer.
date_offset_daysNoRoll the valuation date forward this many days (time decay).
bond_rate_shift_bpNoParallel rate shift in basis points applied to bonds. Zero leaves them unchanged, which is the default.
bond_duration_yearsNoDuration assumed for bonds when a rate shift is applied. IB does not publish duration, so this is your input and the result is only as good as it.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Install Server

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare the tool read-only, idempotent, and non-destructive. The description goes far beyond that, disclosing model internals: Black-76 repricing, flat volatility assumptions, how troughRefined interpolates, how reconciled is computed, what happens to excluded and unmodeled positions, and the modelVsMarket gap. This is exemplary transparency for a complex analytical tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but front-loaded with the core purpose and primary output, then organized into clear behavioral bullets. Each sentence carries meaningful caveats, though some points (e.g., beta semantics, scope semantics) restate or extend schema text, adding a bit of redundancy. Still, it is dense and purposeful rather than padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity — 15 parameters, multiple model assumptions, a reconciliation check, and a detailed output shape — the description is remarkably complete. It explains not only what is returned but how to interpret troughRefined, reconciled, excluded, warnings, pnl_by_expiry, and modelVsMarket. It also warns about known limitations relative to Risk Navigator, which an agent needs before quoting results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is already high at 93%, so the baseline is 3. The description adds substantial meaning on top: betas scale the shock per symbol and remove positions at zero; scope='equity' matches Risk Navigator's Equity tab; vol_slope_down is a user input, not a measurement; breakdown='expiry' returns each expiry's trough contribution. Nearly every parameter gains operational context beyond its schema description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Reprice the whole portfolio — options, equities, futures — across underlying shocks and return the P&L curve and its trough.' This clearly distinguishes the tool's scope. However, it does not explicitly contrast itself with sibling tools like stress_curve or stress_whatif, so it stops short of full sibling differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives strong situational guidance: when to use equity scope, when betas are appropriate, when to set vol_slope_down, when breakdown='expiry' answers a different question, and when to trust the trough only if reconciled. It stops short of explicitly saying 'use this instead of stress_curve when...' or naming excluded conditions, so no direct alternative routing is provided.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/simoneb/ibkr-risk-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server