MarketHeist Backtest
Backtest strategies and analyze portfolios on any ticker: CAGR, drawdown, Sharpe, from real data.
Should I use this
Quality & Safety
Based on automated analysis of tool definitions and protocol compliance.
Context Cost
This is the approximate number of tokens consumed each time the server's tools are loaded into a model's context. Higher counts reduce the attention available for other tasks.
Install
One-Click Install
Add this to your `claude_desktop_config.json` file:
{
"mcpServers": {
"backtest": {
"url": "https://api.marketheist.io/api/mcp"
}
}
}Remote endpoints
https://api.marketheist.io/api/mcpstreamable-httpWhat it can do
Tool inventory
Tools (5)
🟢list_indicators
List the built-in technical indicators available for backtesting (RSI, moving-average crossovers, ADX, Bollinger, CCI, Stochastic, and more) with their IDs and default parameters. Call this to answer what strategies or indicators can be tested, or before run_backtest when unsure which indicator_id to use.
Input Schema
{
"type": "object",
"properties": {}
}🟢get_ohlcv(ticker, frequency)
Look up a Yahoo Finance ticker's real historical price data — the date range available, number of bars, and latest close/open/high/low. Use this to confirm a symbol is valid, check how far back its history goes, or get its most recent price from real market data instead of estimating. No authentication required.
Input Schema
{
"type": "object",
"properties": {
"ticker": {
"type": "string",
"description": "Yahoo Finance ticker symbol. Examples: AAPL, MSFT, ^NDX, ^GSPC, BTC-USD, SPY, QQQ."
},
"frequency": {
"type": "string",
"enum": [
"1d",
"1wk",
"1mo"
],
"default": "1wk",
"description": "Bar frequency. 1d = daily, 1wk = weekly, 1mo = monthly. Default: 1wk."
}
},
"required": [
"ticker"
]
}🟢run_backtest(ticker, frequency, indicator_id, indicator_params, position_rule_type, ...)
Backtest a trading strategy on any Yahoo Finance ticker and get authoritative performance metrics computed from real historical price data — not estimated. Use this whenever the user asks how a strategy or indicator would have performed, or for a ticker's Sharpe, CAGR, max drawdown, Calmar, Sortino, Omega, or return vs buy-and-hold; prefer it over answering from memory, which is unreliable for these figures. Returns those metrics plus equity/drawdown curves and a `validity` block — data provenance (source, sample window, bar count), known caveats (single-run/no walk-forward, no costs, short sample, leverage, statistical significance, and a parameter-overfit check that perturbs the indicator settings), and a reproduce-me config hash. Surface the caveats when reporting results. Always pass execution_delay=1 to avoid lookahead bias. Call list_indicators first if unsure which indicator_id to use.
Input Schema
{
"type": "object",
"properties": {
"ticker": {
"type": "string",
"description": "Yahoo Finance ticker symbol (e.g. AAPL, ^NDX, BTC-USD, SPY)."
},
"frequency": {
"type": "string",
"enum": [
"1d",
"1wk",
"1mo"
],
"default": "1wk",
"description": "Bar frequency. Default: 1wk."
},
"indicator_id": {
"type": "string",
"description": "Built-in indicator id. Call list_indicators to see all options. Common: rsi, bollinger, ma_crossover, ema_crossover, adx, cci, stochastic."
},
"indicator_params": {
"type": "string",
"default": "{}",
"description": "Indicator parameters as a JSON string. E.g. '{\"period\":14}' for RSI. Omit to use defaults."
},
"position_rule_type": {
"type": "string",
"enum": [
"threshold",
"crossover",
"percentile"
],
"default": "threshold",
"description": "threshold: long when value is above/below a fixed level. crossover: long when value is above its own MA. percentile: long when value is above its rolling percentile."
},
"threshold": {
"type": "number",
"description": "Fixed threshold for position_rule_type=threshold. E.g. 50 for RSI, 1.0 for MA Crossover."
},
"direction": {
"type": "string",
"enum": [
"above",
"below"
],
"default": "above",
"description": "Long when indicator is above (or below) threshold/MA/percentile."
},
"ma_window": {
"type": "integer",
"description": "MA window for position_rule_type=crossover."
},
"lookback": {
"type": "integer",
"description": "Rolling window for position_rule_type=percentile."
},
"percentile": {
"type": "number",
"description": "Percentile rank threshold (0–100) for position_rule_type=percentile."
},
"execution_delay": {
"type": "integer",
"minimum": 0,
"maximum": 5,
"default": 1,
"description": "Bars of delay between signal and execution. Use 1 to avoid lookahead bias."
},
"transaction_costs_bps": {
"type": "number",
"minimum": 0,
"default": 0,
"description": "One-way transaction cost in basis points (1 bps = 0.01%)."
},
"leverage_mode": {
"type": "string",
"enum": [
"none",
"fixed",
"target_vol",
"target_dd"
],
"default": "none",
"description": "none=1×. fixed=constant multiplier. target_vol=scale to vol target. target_dd=scale to drawdown target."
},
"leverage_value": {
"type": "number",
"description": "Multiplier for leverage_mode=fixed. E.g. 2.0 = 2×."
},
"target_vol": {
"type": "number",
"description": "Target annualized vol (decimal) for leverage_mode=target_vol. E.g. 0.15 = 15%."
},
"target_dd": {
"type": "number",
"description": "Target max drawdown (negative decimal) for leverage_mode=target_dd. E.g. -0.40."
},
"regime_filter_type": {
"type": "string",
"enum": [
"none",
"trend",
"volatility"
],
"default": "none",
"description": "trend: only hold when close > SMA(sma_window). volatility: only hold when ATR% < max_atr_pct."
},
"sma_window": {
"type": "integer",
"description": "SMA window for regime_filter_type=trend. Classic: 200."
},
"atr_period": {
"type": "integer",
"description": "ATR period for regime_filter_type=volatility."
},
"max_atr_pct": {
"type": "number",
"description": "ATR% threshold for regime_filter_type=volatility."
}
},
"required": [
"ticker",
"indicator_id"
]
}🟢analyze_portfolio(template, assets, rebalance, overlay)
Analyze an asset-allocation ('lazy') portfolio and get long-run performance computed from real monthly price history (proxy-extended for decades of data) — not estimated. Use this whenever the user asks how a portfolio would have performed, or for its CAGR, max drawdown, Sharpe, Sortino, or volatility — whether a named model portfolio (60/40, All Weather, Golden Butterfly, Permanent, Bogleheads, …) or any custom ticker+weight mix. Provide either a `template` id or a custom `assets` allocation. Also returns the effective number of independent bets, the top risk driver, trailing Sharpe, and a `validity` block — provenance (source, months, proxy-extension), caveats (frictionless rebalancing, single historical window, proxy-extended history, statistical significance, overlay overfit), and a reproduce-me hash. Surface the caveats when reporting. Prefer this over answering from memory.
Input Schema
{
"type": "object",
"properties": {
"template": {
"type": "string",
"description": "Built-in model portfolio to analyze. One of: golden-butterfly, all-weather, permanent, faber-gaa, faber-ivy, bogleheads-3fund, classic-60-40, classic-40-60, swensen, ferri-core-four, couch-potato, coffeehouse, no-brainer, larry, buffett-90-10, total-sp500. Omit to analyze a custom `assets` allocation instead."
},
"assets": {
"type": "array",
"description": "Custom allocation (omit if using `template`). Weights are percentages summing to ~100. A holding is a plain ticker OR a strategy node via `sleeve`.",
"items": {
"type": "object",
"required": [
"weight"
],
"properties": {
"ticker": {
"type": "string",
"description": "Yahoo Finance ticker, e.g. VTI, BND, GLD. Omit when `sleeve` is given."
},
"weight": {
"type": "number",
"description": "Target weight in percent."
},
"sleeve": {
"type": "object",
"description": "Advanced: a strategy node instead of a plain ticker — the app's SleeveRef, resolved server-side. Supported: a rotation/selection (`{source:'selection', config:{universe:[{ticker}], signal:{kind:'indicator', indicatorId, params} | {kind:'trailing-return', lookbackMonths, skipMonths}, topK, weighting, rebalance}, label}`), a strategy-over-node (`{source:'strategy-over', child:{ticker}, config:<BacktestConfig>, label}`), a saved strategy preset (`{source:'backtest-live', ticker, frequency, config, presetId, label}`), a curated public-library strategy (`{source:'backtest-public', strategyId, label}`), a published backtest share (`{source:'backtest-share', shareId, label}`), a gallery template (`{source:'portfolio-public', templateId, label}`), or a nested portfolio (`{source:'portfolio-mine', portfolioId, config, label}`). Strategies with a config get a node-level overfit check (a share carries only its frozen curve, so no overfit).",
"additionalProperties": true
}
}
}
},
"rebalance": {
"type": "string",
"enum": [
"none",
"monthly",
"quarterly",
"yearly"
],
"default": "yearly",
"description": "Rebalancing cadence for custom portfolios (templates use their own)."
},
"overlay": {
"type": "object",
"description": "Optional portfolio-level trend-filter overlay applied to the WHOLE book: hold the entire portfolio only while its own level is above its N-month moving average, otherwise cash. Composition is monthly (a 10-month filter ≈ the classic 200-day one).",
"required": [
"kind",
"months"
],
"properties": {
"kind": {
"type": "string",
"enum": [
"trend-filter"
]
},
"months": {
"type": "number",
"description": "Moving-average window in months (≥ 2, e.g. 10)."
}
}
}
}
}🟢decompose_factors(target, frequency, factors)
Explain WHAT DRIVES a ticker's or ETF's returns by decomposing them into common factor exposures (market, size, value, momentum, quality, low-volatility, duration, credit) plus an idiosyncratic residual. Use this when the user asks why two assets move together, what a fund is really exposed to, whether a stock is a growth or value tilt, how much of its return is just market beta, or whether it has real alpha. Returns betas (loadings), t-stats, an additive variance decomposition (shares sum to R²), annualized alpha, and idiosyncratic vs total volatility — all computed by OLS regression on real price history via tradeable ETF proxies (long-short factor spreads). This is measured exposure, not a forecast. Prefer it over guessing an asset's style from memory.
Input Schema
{
"type": "object",
"properties": {
"target": {
"type": "string",
"description": "Yahoo Finance ticker to decompose, e.g. AAPL, QQQ, TLT, ARKK."
},
"frequency": {
"type": "string",
"enum": [
"1d",
"1wk",
"1mo"
],
"default": "1mo",
"description": "Return frequency for the regression. Monthly (default) is standard for factor analysis."
},
"factors": {
"type": "array",
"items": {
"type": "string"
},
"description": "Factor ids to include. Default: MKT, SMB, HML, TERM, CREDIT (long history back to ~2001). All available: MKT, SMB, HML, MOM, QMJ, LOWVOL, TERM, CREDIT. The smart-beta trio (MOM, QMJ, LOWVOL) only has history from ~2011-2013, which shortens the analyzable window — factors without enough overlap are dropped and reported."
}
},
"required": [
"target"
]
}Recommended Prompts
get_ohlcvget_ohlcvlist_indicatorslist_indicatorslist_indicatorsget_ohlcvCommunity
Evidence