Skip to main content
Glama

Get Backtest Result

get_backtest_result
Read-onlyIdempotent

Fetches a submitted backtest by id. By default (waitForCompletion: true) polls internally until it finishes, so one call returns one final answer — no need to poll from the caller's side. Only aggregate metrics are returned here, no trade-by-trade detail — call get_backtest_trades for that (paginated, sortable). Fetching many results from the same submit_backtest_batch call? Use get_backtest_batch_results instead.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
idNoThe id returned by submit_backtest.
pollTimeoutMsNoDefaults to 120000 (2 minutes).
backtestApiKeyNoYour EmidLabs backtest API key. Not needed if this connector was added with a static 'x-api-key' header.
backtestBaseUrlNoDefaults to the public production API.
waitForCompletionNoIf true (default), polls internally until the backtest finishes or pollTimeoutMs elapses.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
idNo
resultNo
statusNo
runtimeMsNoHow long the analyser actually took to run this backtest, in milliseconds — pure compute time, not counting queue/messaging latency. Null until Status is "Completed".
errorMessageNo
recentAvgPnlRNoAverage pnlR of the most recent RecentTradeCount closed trades. This is the recency signal for a rolling ranking — weighted alongside expectancyR, not a replacement for it.
unitsConsumedNoThe actual execution-unit cost of this backtest, matching what's debited from the account's plan balance (CandlesProcessed normalized by the account's candles-per-unit rate). Null until Status is "Completed".
recentOutcomesNo"Win"/"Loss" per recent trade, chronological — oldest first, so the LAST element is the most recent trade. Lets a caller see whether recent trades were genuinely a streak (e.g. all "Loss") versus alternating, which RecentAvgPnlR alone can't distinguish.
candlesProcessedNoNumber of candles the analyser processed for this backtest. Null until Status is "Completed". This is raw volume, not the plan's billing unit — see UnitsConsumed for that.
recentTradeCountNoNumber of trades the recency fields below are based on (up to 5, fewer if the backtest has fewer trades). Null until Status is "Completed".

Schema Changelog

Changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. Changed2 schema fields changed
    • addedOutput schema / properties / result / properties / confirmedSignalsCount
      Added value: +{
      +  "description": "Only meaningful when the request declared confirmationSources — how many candidates cleared confirmation and became one of the Trades above.",
      +  "type": "integer"
      +}
    • addedOutput schema / properties / result / properties / unconfirmedSignalsCount
      Added value: +{
      +  "description": "Only meaningful when the request declared confirmationSources — how many candidates were dropped before trade simulation because they weren't corroborated. ConfirmedSignalsCount + UnconfirmedSignalsCount is the total candidate count, same as what a backtest without confirmationSources would have produced.",
      +  "type": "integer"
      +}
  2. Changed3 schema fields changed
    • addedOutput schema / properties / candlesProcessed
      Added value: +{
      +  "description": "Number of candles the analyser processed for this backtest. Null until Status is \"Completed\". This is raw volume, not the plan's billing unit — see UnitsConsumed for that.",
      +  "type": [
      +    "integer",
      +    "null"
      +  ]
      +}
    • changedOutput schema / properties / unitsConsumed / description
      Previous value: -"Number of candles the analyser processed for this backtest. Null until Status is \"Completed\"."New value: +"The actual execution-unit cost of this backtest, matching what's debited from the account's plan balance (CandlesProcessed normalized by the account's candles-per-unit rate). Null until Status is \"Completed\"."
    • changedOutput schema / properties / unitsConsumed / type
      Previous value: -[
      -  "integer",
      -  "null"
      -]New value: +[
      +  "number",
      +  "null"
      +]
  3. Changed6 schema fields changed
    • changedOutput schema / properties / result / properties / bothHit / description
      Previous value: -"Trades where both stop-loss and take-profit were hit on the same candle (resolved as stop-loss)."New value: +"Trades where both stop-loss and take-profit were hit on the same candle (resolved as stop-loss). A high BothHit relative to Trades means many trades' outcome was decided by the engine's stop-wins-ties precedence rule rather than real intracandle price path data — treat results with more skepticism the higher this ratio is."
    • changedOutput schema / properties / result / properties / conditionsDistributionPct / description
      Previous value: -"For each condition name (see strategySnapshotJson.conditions): fraction of candles where it was true."New value: +"For each possible count of simultaneously-true conditions (0, 1, 2...N): fraction of all candles where exactly that many were true at once. A strategy-tuning diagnostic (how selective is the entry setup), not a performance metric."
    • addedOutput schema / properties / result / properties / currentDrawdownR
      Added value: +{
      +  "description": "How far below its own peak the equity curve sits at the end of the backtest window, in R-units. 0 if the backtest ends at a new high. Includes any still-open position's unrealized PnL (see UnrealizedPnlRAtEnd) — a slump caused by an open, underwater position at window end shows up here.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / result / properties / maxDrawdownR
      Added value: +{
      +  "description": "Worst peak-to-trough dip across closed trades, in R-units. 0 if equity never fell below its running high-water mark. Historical/all-time — see CurrentDrawdownR for where the equity curve sits right now.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / result / properties / openPositionsAtEnd
      Added value: +{
      +  "description": "Number of positions still open (never hit stop/take/exit-signal) when the backtest's date range ended. 0 in the common case. Check this before trusting CurrentDrawdownR/UnrealizedPnlRAtEnd at face value.",
      +  "type": "integer"
      +}
    • addedOutput schema / properties / result / properties / unrealizedPnlRAtEnd
      Added value: +{
      +  "description": "Sum of unrealized PnL, in R-units, across all positions still open at window end — marked to market against the last available candle's close. 0 when OpenPositionsAtEnd is 0. Does NOT include exit fee (the position hasn't closed, so none has been paid) — a slight overestimate of true current drawdown when a position is open. This value feeds ONLY CurrentDrawdownR/MaxDrawdownR — it is never included in PnlR/ExpectancyR/Trades/Wins/Losses or any other metric describing closed, realized trades.",
      +  "type": "number"
      +}
  4. Changed1 schema field changed
    • addedOutput schema / properties / result / properties / totalFeeR
      Added value: +{
      +  "description": "Total R subtracted across all trades by configuration.entryFeePct/exitFeePct (0 if neither was set on the request). expectancyR/pnlR above are already net of this — TotalFeeR is just how much fees cost, for diagnostics. Caveat: a trade's fee-in-R cost scales inversely with that trade's own stop distance, so once fees are applied, expectancyR is only a fair comparison WITHIN one archetype's own stop convention — use pnlPct-based metrics (see get_backtest_trades) for comparisons across strategies/timeframes with different typical stop widths.",
      +  "type": "number"
      +}
  5. Changed2 schema fields changed
    • changedOutput schema / properties / result / properties / profitFactor / description
      Previous value: -"grossProfitR / abs(grossLossR). Greater than 1 means profitable."New value: +"grossProfitR / abs(grossLossR). Greater than 1 means profitable. Null when there are no losing trades — the ratio is undefined (division by zero), not infinite."
    • changedOutput schema / properties / result / properties / profitFactor / type
      Previous value: -"number"New value: +[
      +  "number",
      +  "null"
      +]
  6. Changed2 schema fields changed
    • addedOutput schema / properties / runtimeMs
      Added value: +{
      +  "description": "How long the analyser actually took to run this backtest, in milliseconds — pure compute time, not counting queue/messaging latency. Null until Status is \"Completed\".",
      +  "type": [
      +    "integer",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / unitsConsumed
      Added value: +{
      +  "description": "Number of candles the analyser processed for this backtest. Null until Status is \"Completed\".",
      +  "type": [
      +    "integer",
      +    "null"
      +  ]
      +}
  7. Changed3 schema fields changed
    • addedOutput schema / properties / recentAvgPnlR
      Added value: +{
      +  "description": "Average pnlR of the most recent RecentTradeCount closed trades. This is the recency signal for a rolling ranking — weighted alongside expectancyR, not a replacement for it.",
      +  "type": [
      +    "number",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / recentOutcomes
      Added value: +{
      +  "description": "\"Win\"/\"Loss\" per recent trade, chronological — oldest first, so the LAST element is the most recent trade. Lets a caller see whether recent trades were genuinely a streak (e.g. all \"Loss\") versus alternating, which RecentAvgPnlR alone can't distinguish.",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": [
      +    "array",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / recentTradeCount
      Added value: +{
      +  "description": "Number of trades the recency fields below are based on (up to 5, fewer if the backtest has fewer trades). Null until Status is \"Completed\".",
      +  "type": [
      +    "integer",
      +    "null"
      +  ]
      +}
  8. Changed3 schema fields changed
    • addedInput schema / properties / id / default
      Added value: +null
    • changedInput schema / properties / id / type
      Previous value: -"string"New value: +[
      +  "string",
      +  "null"
      +]
    • removedInput schema / required
      Removed value: -[
      -  "id"
      -]
  9. Changed13 schema fields changed
    • addedOutput schema / properties / result / properties / avgLossR / description
      Added value: +"Average R on losing trades (-1.0 with the default riskManagement; varies if the strategy overrides riskManagement.stopLoss)."
    • addedOutput schema / properties / result / properties / avgWinR / description
      Added value: +"Average R on winning trades."
    • addedOutput schema / properties / result / properties / bothHit / description
      Added value: +"Trades where both stop-loss and take-profit were hit on the same candle (resolved as stop-loss)."
    • addedOutput schema / properties / result / properties / conditionsDistributionPct / description
      Added value: +"For each condition name (see strategySnapshotJson.conditions): fraction of candles where it was true."
    • addedOutput schema / properties / result / properties / direction / description
      Added value: +"\"long\" or \"short\" — the direction the whole backtest traded."
    • addedOutput schema / properties / result / properties / expectancyR / description
      Added value: +"Average expected R per trade — (winRate * avgWinR) + (lossRate * avgLossR). This is the metric to optimize a strategy on, not raw winRate or trade count: a low win rate with a high avgWinR/avgLossR ratio can still have a strongly positive expectancyR."
    • addedOutput schema / properties / result / properties / grossLossR / description
      Added value: +"Sum of all losing trades, in R-units (negative)."
    • addedOutput schema / properties / result / properties / grossProfitR / description
      Added value: +"Sum of all winning trades, in R-units."
    • addedOutput schema / properties / result / properties / pnlR / description
      Added value: +"Net profit/loss in R-units (risk multiples) — sum of every trade's PnL. This is the headline result."
    • addedOutput schema / properties / result / properties / profitFactor / description
      Added value: +"grossProfitR / abs(grossLossR). Greater than 1 means profitable."
    • addedOutput schema / properties / result / properties / scoreDistributionPct / description
      Added value: +"For each possible total score value: fraction of candles that summed to it."
    • addedOutput schema / properties / result / properties / trades / description
      Added value: +"Total number of closed trades."
    • addedOutput schema / properties / result / properties / winRate / description
      Added value: +"wins / trades. Range 0–1."
  10. Changed4 schema fields changed
    • addedInput schema / properties / backtestApiKey / default
      Added value: +null
    • changedInput schema / properties / backtestApiKey / description
      Previous value: -"Your EmidLabs backtest API key."New value: +"Your EmidLabs backtest API key. Not needed if this connector was added with a static 'x-api-key' header."
    • changedInput schema / properties / backtestApiKey / type
      Previous value: -"string"New value: +[
      +  "string",
      +  "null"
      +]
    • changedInput schema / required
      Previous value: -[
      -  "backtestApiKey",
      -  "id"
      -]New value: +[
      +  "id"
      +]
  11. First observed

TDQS

A4.7/5.0
Behavior5/5

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

Discloses important behavior beyond annotations: internal polling with waitForCompletion, the single-final-answer contract, and the limitation to aggregate metrics only. These details meaningfully shape an agent's expectations about latency and output scope, complementing the readOnlyHint and idempotentHint annotations.

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

Conciseness5/5

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

Three sentences with no filler. The core purpose is front-loaded, followed by the most important behavioral nuance, then targeted sibling routing. Every sentence earns its place.

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 moderate complexity, a complete input schema, an output schema, and strong annotations, the description covers all essential context: what it does, how polling behaves, what is omitted from results, and which sibling tools handle those omissions. Nothing critical is missing.

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

Parameters3/5

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

Schema description coverage is 100%, so the description adds limited new parameter-level meaning. It does reinforce the id and waitForCompletion semantics, but most parameter explanation is already supplied by the schema, so no significant compensation is needed or provided.

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

Purpose5/5

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

States a specific action ('Fetches a submitted backtest by id') on a clear resource. It also explicitly distinguishes itself from get_backtest_trades and get_backtest_batch_results by naming what the tool does not return and which sibling covers that need.

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

Usage Guidelines5/5

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

Provides explicit guidance on when to use this tool versus alternatives: use get_backtest_trades for trade-by-trade detail and get_backtest_batch_results when fetching many results from a batch. It also clarifies that the caller does not need to poll because the tool polls internally by default.

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

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

TDQS

A4.5/5.0
Disambiguation5/5

Each tool maps to a distinct resource and action: submitting/fetching backtests, fetching batch results, fetching trades, submitting/fetching confirmation sources, fetching signals, and listing available assets. The singular vs. batch result tools are explicitly cross-referenced and serve different call patterns, so an agent shouldn't confuse them.

Naming Consistency5/5

All tool names follow a consistent snake_case verb_noun pattern: submit_*, get_*, and list_*. Resource names are clear and predictable, such as backtest, backtest_batch, backtest_trades, confirmation_source, and confirmation_source_signals. The list_/get_ verb variation is conventional and not confusing.

Tool Count5/5

Nine tools is well-scoped for this domain, covering single and batch backtests, result and trade retrieval, asset discovery, and the confirmation-source workflow. Each tool has a distinct role, and none feel like filler or duplication.

Completeness5/5

The tool set covers the full backtesting lifecycle: submit single/batch, fetch aggregate results, fetch trade detail, list available assets, and submit/fetch confirmation sources plus their signals. The confirmation-source workflow integrates cleanly with submit_backtest, and there are no dead ends or obvious missing operations.

Resources