# Backtest360 (remote · mcp.backtest360.com)

MCP server exposing the Backtest360 engine API as tools for AI agents.

- Trust score: 75/100 (medium)
- Change this week: +10
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-08-03

## Components

- remote · `mcp.backtest360.com`: 75/100 (this document), [markdown](https://verifymcp.io/servers/com-backtest360-backtest360/mcp.md), [page](https://verifymcp.io/servers/com-backtest360-backtest360/mcp)
- pypi · `backtest360-mcp`: 36/100, [markdown](https://verifymcp.io/servers/com-backtest360-backtest360/backtest360-mcp.md), [page](https://verifymcp.io/servers/com-backtest360-backtest360/backtest360-mcp)

## Channel facts

- Endpoint: `https://mcp.backtest360.com/mcp`
- Transports: `streamable-http`
- Auth: `required`
- Version: `0.5.0`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically against the live server, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-08-03.

- **Endpoint Security**: 89/100
  - The endpoint's TLS certificate is valid, in date, and uses a strong key.
  - Authorisation is enforced on tool calls, but the challenge carries no valid RFC 9728 metadata, so a client cannot discover where to get a token.
  - HTTPS is enforced; there's no plaintext access path.
  - The HSTS (Strict-Transport-Security) header is present.
  - DNSSEC check failed: this domain isn't protected by DNSSEC.
- **Transport & Reachability**: 100/100
  - Verified streamable-http transport via a live MCP handshake.
- **Schema Quality & AI Usability**: 64/100
  - 67% of prompts and resources have a non-trivial description (not blank, and not just the item's name).
  - AI-judged instruction clarity (good).
  - Context-footprint check failed: tool/resource definitions use about 3972 tokens (~189/item across 21 items; 20 tools + 1 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 27/100
  - Stability observed for 8 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 71/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 0% of tool parameters carry a description.
  - Structured output schemas are declared (90% of tools); any adoption earns full credit.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

## Install

### Claude

```bash
claude mcp add --transport http com-backtest360-backtest360 https://mcp.backtest360.com/mcp
```

### Codex

```toml
[mcp_servers.com-backtest360-backtest360]
url = "https://mcp.backtest360.com/mcp"
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "com-backtest360-backtest360": {
      "type": "remote",
      "url": "https://mcp.backtest360.com/mcp",
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add com-backtest360-backtest360 --url https://mcp.backtest360.com/mcp --transport streamable-http
```

### Hermes

```yaml
mcp_servers:
  com-backtest360-backtest360:
    url: "https://mcp.backtest360.com/mcp"
```

### Other

```json
{
  "mcpServers": {
    "com-backtest360-backtest360": {
      "type": "http",
      "url": "https://mcp.backtest360.com/mcp"
    }
  }
}
```

The mcpServers block is a cross-client convention. Remote transports vary, so check your client's docs.

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-08-03 (score 75, +1)

No change was recorded against any check on this day. Stability & Change Management went from 23 to 27. That category is still filling its 30-day observation window: 7 days of observed history at the previous scan, 8 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-08-01 (score 74, +1)

No change was recorded against any check on this day. Stability & Change Management went from 17 to 20. That category is still filling its 30-day observation window: 5 days of observed history at the previous scan, 6 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-07-31 (score 73, +6)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-30 (score 67, +1)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-29 (score 66, +1)

No change was recorded against any check on this day. Stability & Change Management went from 7 to 10. That category is still filling its 30-day observation window: 2 days of observed history at the previous scan, 3 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-07-27 (score 65, +1)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-26 (score 64)

First indexed and scored.

## MCP tools (20)

### `get_me` (~155 tokens)

The configured API key's permissions, limits, and current usage.

        Cheap. Call early in a session — before planning work — to learn what
        this key can do instead of discovering limits through failed calls.

        Returns:
            ``scopes``: the permission scopes the key carries. ``limits``:
            requests per minute and per day, max concurrent requests, and the
            per-run bar cap (null when uncapped). ``usage``: current
            consumption against those limits, with reset countdowns in
            seconds. ``capabilities``: feature flags such as server-side data
            fetch and the full metric set. A small fixed-shape record,
            returned as the engine sent it.

### `engine_info` (~49 tokens)

Engine version, API contract number, and health.

        Free (not quota-counted). Call once at the start of a session
        to confirm the engine is reachable and which contract it serves.

### `get_catalog` (~210 tokens)

Fetch one engine reference catalog.

        Catalogs (cheap, cacheable per session):
        - 'operators' — comparison operators for condition expressions
        - 'execution-modes' — entry/exit anchors and fill algorithms, with the
          validity matrix by market type
        - 'stop-types' — stop-loss types, re-entry modes, and their parameters
        - 'sizing-methods' — position-sizing methods and their parameters
        - 'bar-frequencies' — supported bar frequencies and the signal x
          execution validity matrix (which combinations are allowed)
        - 'sections' — the full metric catalog: every statistic's stable id,
          display label, section, and description
        - 'sampling-modes' — Monte-Carlo resampling modes, each with its
          status and parameters

        Fetch the relevant catalog BEFORE building a strategy or config; build
        only from values it lists — never guess parameter names or frequencies.

Input parameters:

- `catalog` (string, required)

### `list_indicators` (~265 tokens)

List indicators, or fetch one indicator's full schema.

        Cheap, cacheable per session.

        With no arguments: a compact catalog — ``{"indicators": [...],
        "count": N}`` — where each entry carries id, name, category, kind,
        and value_dtype (no description, to keep the discovery scan small). Use
        it to discover what exists. Pass name='rsi' (id or name,
        case-insensitive) to get that single indicator's complete entry
        including its description and params_schema — do this before adding an
        indicator to a strategy so its parameters are exactly right.
        Pass compact=False for full entries for everything (large; the MCP
        server may cap it and set ``truncated_by_mcp`` — prefer compact or
        name=).

        Wire optimization: the compact discovery path asks the engine to omit
        per-entry descriptions (``descriptions=false``) since they are stripped
        locally anyway; the name= and compact=False paths request them. This is
        a pure saving — if the engine ignores the param it returns full entries
        and the local compact strip still yields a lean result.

Input parameters:

- `compact` (boolean)
- `name`

### `list_templates` (~226 tokens)

List predesigned strategy templates, or fetch one in full.

        Cheap, cacheable per session. The engine returns the templates
        available to the calling key.

        With no arguments: a compact catalog — ``{"templates": [...],
        "count": N}`` — where each entry carries id, origin, name, and
        description. Use it to discover what exists. Pass name='sma-cross'
        (id or name, case-insensitive) to get that single template's complete
        entry: its strategy logic (``condition_tree`` + ``indicators``, the
        same shape validate_strategy and run_backtest accept) plus parameter
        metadata — ``defaults`` (starting parameter values), ``requires``,
        and ``locked_params`` (parameters that must keep their template
        values). Pass compact=False for complete entries for everything
        (large; the MCP server may cap it and set ``truncated_by_mcp`` —
        prefer compact or name=).

Input parameters:

- `compact` (boolean)
- `name`

### `get_strategy_schema` (~44 tokens)

JSON Schema for the strategy document (condition_tree + indicators).

        Fetch this before composing a strategy by hand; the
        validate_strategy tool checks against the same rules.

### `validate_strategy` (~218 tokens)

Validate a strategy document without running a backtest.

        A cheap quota separate from backtest runs,
        so validate freely and ALWAYS before run_backtest.

        Args:
            strategy: The strategy document — name, indicators[], and
                condition_tree (see get_strategy_schema for the exact shape).
            injected_indicators: Names of custom time-series columns the
                caller will supply via data_inputs at run time, so conditions
                referencing them validate.

        Returns:
            On success: {"valid": true, "warmup_bars": ..., referenced
            indicators/columns}. On failure: {"valid": false, "errors": [...]}
            where each error carries a machine code, the location in the
            document, a message, and context (e.g. the list of valid column
            names). A failed validation is a NORMAL result, not an error —
            read the errors, fix the document, and validate again before
            running.

Input parameters:

- `injected_indicators`
- `strategy` (object, required)

### `run_backtest` (~642 tokens)

Run a historical backtest against the engine.

        Quota-counted and compute-bound. Validate the
        strategy first (validate_strategy is far cheaper). On a 504 compute
        timeout, do NOT retry the same request — reduce the date range, use a
        coarser frequency, or simplify the strategy. On 429/503, wait for the
        advertised Retry-After before retrying.

        Args:
            data_source: Either inline OHLCV ({"ohlcv": {dates, open, high,
                low, close, volume?}} as parallel arrays, ISO-8601 dates) or a
                server-side fetch ({"symbol", "start", "end", "frequency"} —
                requires a paid plan).
            strategy: Strategy document (indicators[] + condition_tree).
                Mutually exclusive with signals.
            signals: Precomputed signal series ({"dates": [...], "values":
                [-1|0|1, ...]}). Mutually exclusive with strategy.
            execution: Execution/cost/risk/sizing settings. Use values from
                get_catalog('execution-modes'/'stop-types'/'sizing-methods');
                omit for engine defaults.
            benchmark: Optional benchmark data source (same shape as
                data_source) — when given, the result also carries
                benchmark-relative metrics (beta, alpha, information ratio,
                tracking error, up/down capture) and bar-alignment info.
            data_inputs: Optional custom time-series the strategy references
                (name -> {dates, values}).
            response_detail: 'summary' (default — headline metrics, smallest),
                'stats' (every metric), 'full' (plus trades and series
                downsampled to a fixed, server-controlled number of points).
            include: Optional add-on blocks at any detail level: 'trades',
                'equity_curve', 'monthly_returns', 'yearly_returns',
                'signal_diagnostics' (which per-bar entry/exit conditions
                fired,…

Input parameters:

- `benchmark`
- `data_inputs`
- `data_source` (object, required)
- `execution`
- `include`
- `response_detail` (string)
- `signals`
- `strategy`
- `trades_limit` (integer)

### `get_latest_signal` (~100 tokens)

Evaluate the strategy on the most recent bar only — no P&L, no stats.

        Returns the latest signal (-1/0/1), which
        condition slots fired, and the bar timestamp. Use for "what would this
        strategy do right now" questions; use run_backtest for performance.

Input parameters:

- `data_inputs`
- `data_source` (object, required)
- `execution`
- `strategy` (object, required)

### `compare_backtests` (~335 tokens)

Run several strategies on the same data and compare side by side.

        One quota-counted call, but compute scales with the number of
        strategies. If the wall-clock compute budget is exceeded, the call
        fails with a tool error (504) instead of returning partial results —
        narrow the request (fewer strategies, shorter date range, coarser
        frequency) and retry.

        Args:
            data_source: Shared data source (same shape as run_backtest).
            strategies: List of {"label": str, "strategy": {...},
                "execution": {...}?} entries. Labels need not be unique or
                id-safe — they are echoed back verbatim in the result.
            include_benchmark: Add a buy-and-hold benchmark to the comparison.
            response_detail: Shaping level applied to each strategy's result.
            trades_limit: Max trades per strategy when detail is 'full'.

        Returns:
            {"strategies": [{"label", "result"}, ...], "equity_curves": {...},
            "alignment"?}, each result shaped at the requested detail. When a
            benchmark is included, non-benchmark entries also carry
            "relative" (beta, alpha, information ratio, etc.). A 400/422
            rejection returns {"accepted": false, "error": ...};
            capacity/timeout/permission failures raise a tool error.

Input parameters:

- `data_source` (object, required)
- `include_benchmark` (boolean)
- `response_detail` (string)
- `strategies` (array, required)
- `trades_limit` (integer)

### `export_backtest` (~246 tokens)

Export a multi-strategy comparison as an Excel workbook.

        Quota-counted; needs a key whose plan includes full-metrics export
        (a 403 means the configured key's plan does not — do not retry).
        Returns the workbook base64-encoded — decode and write it to a
        ``.xlsx`` file.

        Args:
            data_source: Shared data source (same shape as run_backtest).
            strategies: Same shape as compare_backtests' ``strategies``.
            include_benchmark: Add a buy-and-hold benchmark to the export.

        Returns:
            {"filename", "content_type", "size_bytes", "content_base64"}. A
            400/422 rejection returns {"accepted": false, "error": ...};
            capacity/timeout/permission failures raise a tool error. If the
            encoded workbook would exceed the output size limit, raises a
            tool error — narrow the request (shorter date range, fewer
            strategies, coarser frequency) and retry.

Input parameters:

- `data_source` (object, required)
- `include_benchmark` (boolean)
- `strategies` (array, required)

### `compute_stats` (~277 tokens)

Compute the engine's performance metrics from a returns series.

        Use when the returns came from somewhere
        other than run_backtest (an external system, a portfolio) — backtest
        results already include these statistics.

        Args:
            returns: Per-bar log returns as {"dates": [...], "values": [...]}
                parallel arrays (ISO-8601 dates).
            trading_days_per_year: Required annualization factor — 252 for a
                daily equities calendar, 365 for 24/7 crypto. Must match the bar
                calendar of the returns series; a wrong value silently
                mis-annualizes Sharpe, volatility, and CAGR.
            benchmark_returns: Optional benchmark series, same shape — adds
                alpha/beta/capture metrics.
            trades: Optional trade records (entry_date, exit_date, direction,
                return_net, ...) — adds trade-level metrics.
            risk_free_rate: Annual risk-free rate as a decimal.

        Returns:
            {"stats": {...}} — the metric set the API key's plan allows.
            See get_catalog('sections') for every metric's id and description.

Input parameters:

- `benchmark_returns`
- `returns` (object, required)
- `risk_free_rate` (number)
- `trades`
- `trading_days_per_year` (integer, required)

### `search_tickers` (~89 tokens)

Search available assets by ticker or name (relevance-ranked).

        Use to resolve a user's asset mention ("bitcoin",
        "S&P") to the exact ticker before requesting a server-side data fetch.
        asset_class filters to 'stocks', 'crypto', 'forex', or 'indices'.

Input parameters:

- `asset_class`
- `limit` (integer)
- `query` (string, required)

### `list_tickers` (~80 tokens)

List available tickers, optionally filtered by asset class.

        The full universe is very large, so the MCP server
        caps the returned list and marks it ``truncated_by_mcp`` — pass
        asset_class to narrow it, or use search_tickers to resolve a specific
        asset by name.

Input parameters:

- `asset_class`

### `get_data_range` (~78 tokens)

Available date range and estimated bar count for a symbol/frequency.

        Available on paid plans. Call before a server-side fetch so the
        requested start/end stay inside what the provider can deliver and the
        bar count stays inside the key's per-run limit.

Input parameters:

- `frequency` (string, required)
- `symbol` (string, required)

### `get_ticker_info` (~141 tokens)

Identity and data coverage for one symbol, in a single call.

        Metadata only — no market data, so no paid plan is needed. Returns the
        asset's identity (name, asset class, exchange, currency, and whether it
        is still active) together with a coverage summary for the given
        frequency: the available date range and an estimated bar count. Use it
        to confirm a symbol resolves and that the history you need exists before
        requesting a quote or a price fetch. For the precise per-frequency range
        use get_data_range.

Input parameters:

- `frequency` (string)
- `symbol` (string, required)

### `get_quote` (~118 tokens)

Latest available price for a symbol.

        Requires a paid plan (managed market data). Returns the most recent
        *available* bar for the given frequency — the end-of-day close for
        daily, the last completed bar otherwise — as open/high/low/close/volume
        plus an ``as_of`` timestamp for that bar. This is a last-known price,
        not a live tick; read ``as_of`` to judge how stale it is.

Input parameters:

- `frequency` (string)
- `symbol` (string, required)

### `get_price_history` (~221 tokens)

OHLCV price history for a symbol over a date range.

        Requires a paid plan (managed market data). ``start`` is required
        (``YYYY-MM-DD``); ``end`` defaults to today. Returns a summary (symbol,
        resolved date range, total bar count, price range, gap flags),
        market-hours detection, and the OHLCV arrays. A long history is
        downsampled by the MCP server to a bounded number of points — first and
        last bar always kept, every column thinned on the same dates — with
        ``downsampled_from_bars`` and ``points_returned`` recorded on the
        ``ohlcv`` block; the untouched ``summary.total_bars`` still reports the
        true bar count. The window is bounded by the plan's per-request bar cap
        — call get_data_range first to size a request.

Input parameters:

- `end`
- `frequency` (string)
- `start` (string, required)
- `symbol` (string, required)

### `list_macro_series` (~126 tokens)

List the available macroeconomic series (the catalog).

        Free — no special plan. Returns the set of macro series you can fetch
        with get_macro_series, each with its stable ``id`` (the value
        get_macro_series takes), title, category, native reporting frequency,
        and units, plus the list of categories. Optionally filter to one
        ``category`` (e.g. rates, yield_curve, inflation, employment, recession,
        growth). Call this first to find the ``id`` for the series you want.

Input parameters:

- `category`

### `get_macro_series` (~232 tokens)

Observations for one macroeconomic series over an optional date range.

        Free — no special plan. ``series`` is an ``id`` from list_macro_series
        (e.g. treasury_10y, cpi, unemployment_rate); arbitrary external ids are
        not accepted. ``start``/``end`` are ``YYYY-MM-DD``, inclusive, both
        optional (full history when omitted). Returns the value series at its
        native reporting frequency, with the series descriptor and an ``as_of``
        date. A long history is downsampled by the MCP server to a bounded
        number of points (first and last kept), marked with
        ``downsampled_from_bars`` and ``points_returned`` on the
        ``observations`` block.

        Note: values are the latest revised figures stamped by reference period,
        not point-in-time as-first-reported data — do not treat them as the
        values that were known at a past date.

Input parameters:

- `end`
- `series` (string, required)
- `start`

## Diagnostics

Captured diagnostic sections: TLS, DNSSEC, Authorisation, Transports. The full working is on the page: https://verifymcp.io/servers/com-backtest360-backtest360/mcp#diagnostics

## Score history

- 2026-08-03: 75
- 2026-08-02: 74
- 2026-08-01: 74
- 2026-07-31: 73
- 2026-07-30: 67
- 2026-07-29: 66
- 2026-07-28: 65
- 2026-07-27: 65
- 2026-07-26: 64

## Links

- Remote endpoint: https://mcp.backtest360.com/mcp
- Authorisation metadata: https://mcp.backtest360.com/.well-known/oauth-protected-resource/mcp
- Repository: https://github.com/Backtest360/backtest360-mcp
- Changelog RSS feed: https://verifymcp.io/servers/com-backtest360-backtest360/mcp/changelog.xml
- Changelog JSON feed: https://verifymcp.io/servers/com-backtest360-backtest360/mcp/changelog.json
- HTML version of this page: https://verifymcp.io/servers/com-backtest360-backtest360/mcp
