EmidLabs Backtest
Server Details
Run crypto trading strategy backtests through EmidLabs's Backtesting API.
- Status
- Healthy
- Last Tested
- Transport
- Streamable HTTP
- URL
Available Tools
9 toolsget_backtest_batch_resultsGet Backtest Batch ResultsARead-onlyIdempotentInspect
Fetches every asset's outcome from a submit_backtest_batch call, paginated. By default (waitForCompletion: true) polls internally until every item in the batch is done — a cheap check, not one that pages through everything — so one call returns the finished page. Each item has the same aggregate metrics and recency fields (recentTradeCount/recentAvgPnlR/recentOutcomes) get_backtest_result returns for a single backtest, plus assetPair/status/error, so the single-result and batch-result shapes never drift apart. totalCount/completedCount/failedCount/pendingCount come back on every page, not just the last, so you can tell the batch is done from a single pageSize=1 call.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | 1-based page number. Default 1. | |
| batchId | No | The batchId returned by submit_backtest_batch. | |
| pageSize | No | Items per page, 1-100. Default 20. | |
| pollTimeoutMs | No | Defaults to 300000 (5 minutes) — a batch's slowest item determines the total wait, so this is higher than get_backtest_result's default. | |
| backtestApiKey | No | Your EmidLabs backtest API key. Not needed if this connector was added with a static 'x-api-key' header. | |
| backtestBaseUrl | No | Defaults to the public production API. | |
| waitForCompletion | No | If true (default), polls internally until every item in the batch is done or pollTimeoutMs elapses. |
Output Schema
| Name | Required | Description |
|---|---|---|
| page | No | |
| items | No | |
| batchId | No | |
| pageSize | No | |
| totalCount | No | Total items in this batch, across every page — not just this one. |
| totalPages | No | |
| failedCount | No | How many items finished unsuccessfully (Failed, Cancelled, or Expired). |
| pendingCount | No | How many items are still Queued or Running. The whole batch is done once this reaches 0 — true on every page, not just the last. |
| completedCount | No | How many items finished successfully. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond readOnly/idempotent/non-destructive annotations, it discloses internal polling (waitForCompletion), that a call returns only the finished page, and that counts appear on every page. It also explains the response shape stays consistent with get_backtest_result, which is valuable behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four sentences, with purpose first, then behavior and edge-case tips; no filler. Despite length, every sentence adds non-redundant operational knowledge.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a paginated polling tool with 7 optional params and an output schema, the description covers the data shape, pagination counts, polling timeout semantics, and relation to sibling tools. Output schema handles return values, so nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3; the description adds meaningful semantics around waitForCompletion ('polls internally until every item... done', 'cheap check') and the pageSize=1 trick. It doesn't need to restate parameter properties because the schema already documents them.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Fetches every asset's outcome from a submit_backtest_batch call') and adds pagination. It is clearly distinguished from get_backtest_result (single-result) and submit_backtest_batch (submission).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the originating call (submit_backtest_batch) and contrasts with the single-backtest tool get_backtest_result, giving an agent enough context to choose between them. It gives concrete usage advice (waitForCompletion behavior, pageSize=1 completion check), though it doesn't explicitly state exclusion conditions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_backtest_resultGet Backtest ResultARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | The id returned by submit_backtest. | |
| pollTimeoutMs | No | Defaults to 120000 (2 minutes). | |
| backtestApiKey | No | Your EmidLabs backtest API key. Not needed if this connector was added with a static 'x-api-key' header. | |
| backtestBaseUrl | No | Defaults to the public production API. | |
| waitForCompletion | No | If true (default), polls internally until the backtest finishes or pollTimeoutMs elapses. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| result | No | |
| status | No | |
| runtimeMs | No | 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". |
| errorMessage | No | |
| recentAvgPnlR | No | 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. |
| unitsConsumed | No | 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". |
| recentOutcomes | No | "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. |
| candlesProcessed | No | 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. |
| recentTradeCount | No | 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". |
TDQS
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.
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.
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.
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.
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.
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.
get_backtest_tradesGet Backtest TradesARead-onlyIdempotentInspect
Fetches the closed-trade list for a completed backtest, paginated and sortable — the trade-by-trade detail get_backtest_result deliberately omits. Only closed trades ever appear; a position still open when the backtest's date range ends isn't represented here or anywhere else. Example: sortBy="exitTime", sortDirection="desc", pageSize=5 for the most recently closed trades.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | The id returned by submit_backtest. | |
| page | No | 1-based page number. Default 1. | |
| sortBy | No | One of: number, pnlR, pnlPct, entryTime, exitTime. Defaults to number (closing order). | |
| pageSize | No | Trades per page, 1-100. Default 20. | |
| sortDirection | No | "asc" or "desc". Defaults to asc. | |
| backtestApiKey | No | Your EmidLabs backtest API key. Not needed if this connector was added with a static 'x-api-key' header. | |
| backtestBaseUrl | No | Defaults to the public production API. |
Output Schema
| Name | Required | Description |
|---|---|---|
| page | No | |
| items | No | The trades on this page, in the requested sort order. |
| pageSize | No | |
| totalCount | No | Total closed trades across the whole backtest, not just this page. |
| totalPages | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and idempotentHint, so the bar is lower. The description adds valuable info: only closed trades ever appear, open positions are not represented anywhere. It does not mention pagination performance or error handling, but the open-position caveat is meaningful beyond annotations, so a 3 is fair.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences: first defines the tool and its key differentiator, second adds the critical behavioral caveat, third is a concrete example. Every sentence adds value with no filler. Front-loaded and efficiently structured.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has a rich output schema and 100% schema parameter coverage, so the description need not elaborate return format. It covers the essential nuance about closed trades. Slightly less than a 5 because it could mention what happens if the backtest ID is invalid or the backtest isn't completed, but the essentials are covered.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents all parameters. The description adds an example usage that shows the meaning of sortBy/sortDirection/pageSize, but does not explain each parameter beyond the schema. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clear verb+resource ('Fetches the closed-trade list for a completed backtest'), plus specifics: paginated, sortable, and deliberately omits trade-by-trade detail that get_backtest_result provides. This sharply distinguishes it from the sibling tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use: for trade-by-trade detail and when get_backtest_result omits it. Also provides a concrete example. It does not explicitly list alternatives like get_backtest_batch_results, but naming the primary alternative is sufficient.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_confirmation_sourceGet Confirmation SourceARead-onlyIdempotentInspect
Fetches a submitted confirmation source by id. By default (waitForCompletion: true) polls internally until it finishes, so one call returns one final answer. No trade-outcome fields here at all (no PnlR/WinRate/...) — a confirmation source never opens a position. Once Completed, its id can be used as a confirmationSources sourceId in submit_backtest; its raw signal timeline is available separately via get_confirmation_source_signals.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | The id returned by submit_confirmation_source. | |
| pollTimeoutMs | No | Defaults to 120000 (2 minutes). | |
| backtestApiKey | No | Your EmidLabs backtest API key. Not needed if this connector was added with a static 'x-api-key' header. | |
| backtestBaseUrl | No | Defaults to the public production API. | |
| waitForCompletion | No | If true (default), polls internally until the confirmation source finishes or pollTimeoutMs elapses. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| status | No | |
| assetPair | No | |
| runtimeMs | No | How long the analyser actually took to compute this confirmation source's signal timeline, in milliseconds. Null until Status is "Completed". |
| timeframe | No | |
| errorMessage | No | |
| unitsConsumed | No | The actual execution-unit cost, same pool/rate as a regular backtest — computing a confirmation source's signal timeline costs the same per candle as simulating trades, it just skips the trade simulation itself. |
| candlesProcessed | No | Number of candles the analyser processed. Null until Status is "Completed". This is raw volume, not the plan's billing unit — see UnitsConsumed for that. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/idempotent annotations, the description discloses the internal polling behavior, that one call returns one final answer, and that the tool never opens a position. This adds meaningful behavioral context beyond what annotations alone provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences with no filler; the first sentence front-loads the core action, and subsequent sentences pack high-value semantics about polling, outcome scope, and sibling routing. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema and fully documented parameters, the description supplies the missing conceptual context: polling semantics, lifecycle (Completed → sourceId), and the distinction from trade-outcome and signal-timeline tools. No critical behavior is left unexplained.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds extra meaning for the id parameter by explaining that a Completed id can be used as a confirmationSources sourceId in submit_backtest, and it reinforces the waitForCompletion default polling semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource ('Fetches a submitted confirmation source by id') and sharply distinguishes itself from get_confirmation_source_signals by noting the raw signal timeline is available separately. It also states that no trade-outcome fields appear, preventing confusion with backtest result siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It names the sibling get_confirmation_source_signals as the destination for raw signal timelines, and gives an explicit when-not through 'No trade-outcome fields here at all — a confirmation source never opens a position.' The lifecycle note that a Completed id can become a confirmationSources sourceId in submit_backtest gives actionable downstream context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_confirmation_source_signalsGet Confirmation Source SignalsARead-onlyIdempotentInspect
Fetches a completed confirmation source's raw signal timeline, paginated — the actual data a backtest's confirmationSources requirement is checked against. Can easily run into the thousands for a frequent condition over a long range (every candle-condition match is a row, not just closed trades), which is why this is paginated from the start. Debugging/inspection only — you do NOT need this tool to make confirmationSources work, and should not fetch these rows to reconstruct the gating yourself. To actually gate a backtest by this source, pass its id directly as sourceId in submit_backtest's own confirmationSources array; the backend applies the backward-only state check against this exact timeline automatically, including the higher-timeframe-to-lower-timeframe alignment. Reimplementing that alignment by hand from this raw data is unnecessary and easy to get wrong (e.g. failing to correctly persist a higher-timeframe state across every lower-timeframe candle until the next higher-timeframe close). Use this tool only to sanity-check a source's signal density or diagnose an unexpectedly low ConfirmedSignalsCount after the fact.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | The id returned by submit_confirmation_source. | |
| page | No | 1-based page number. Default 1. | |
| pageSize | No | Signals per page, 1-100. Default 20. | |
| backtestApiKey | No | Your EmidLabs backtest API key. Not needed if this connector was added with a static 'x-api-key' header. | |
| backtestBaseUrl | No | Defaults to the public production API. |
Output Schema
| Name | Required | Description |
|---|---|---|
| page | No | |
| items | No | The signals on this page, in candle order. |
| pageSize | No | |
| totalCount | No | Total signals across the whole confirmation source, not just this page — can easily be in the thousands for a frequent condition over a long range. |
| totalPages | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the tool readOnly and idempotent, and the description adds substantial non-obvious behavior: every candle-condition match is a row rather than only closed trades, timelines can reach thousands of rows, pagination is mandatory from the start, and the backend automatically applies backward-only state checks and higher-timeframe alignment. This is far beyond what annotations convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose and then provides highly relevant warnings. It is somewhat long and contains minor repetition around not reimplementing the alignment logic, but the details are valuable enough that the length is mostly justified.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity, the output schema presence, and the clear sibling context, this description is complete: it explains what the tool returns and why it is paginated, when to use it, when not to use it, and how to accomplish gating correctly instead. Nothing essential is missing for an agent to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds context about pagination and data scale but does not add parameter-specific semantics beyond what the schema already documents for id, page, pageSize, backtestApiKey, and backtestBaseUrl.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a precise verb and resource: 'Fetches a completed confirmation source's raw signal timeline, paginated.' It also clarifies the data's role ('the actual data a backtest's confirmationSources requirement is checked against'), which distinguishes it clearly from sibling tools like get_confirmation_source or submit_confirmation_source.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage guidance is explicit: 'Debugging/inspection only,' 'you do NOT need this tool to make confirmationSources work,' and direct alternatives are provided ('pass its id directly as sourceId in submit_backtest's own confirmationSources array'). It even names the precise diagnostic cases: sanity-check signal density or diagnose low ConfirmedSignalsCount.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_available_assetsList Available AssetsARead-onlyIdempotentInspect
Lists every asset pair with real historical data, each with its supported timeframes and the date range actually available. Optional to call — submit_backtest already returns a clear error (with the real available range) when an asset or date range doesn't have data, so this is for up-front exploration or for recovering from an "unknown asset" error, not a required step before every submit_backtest.
| Name | Required | Description | Default |
|---|---|---|---|
| backtestApiKey | No | Your EmidLabs backtest API key. Not needed if this connector was added with a static 'x-api-key' header. | |
| backtestBaseUrl | No | Defaults to the public production API. Override only for self-hosted/staging use. |
Output Schema
| Name | Required | Description |
|---|---|---|
| assets | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, which covers safety. The description adds useful context by noting the tool is optional and that submit_backtest errors provide the real range, and clarifies it lists only assets with real historical data. This goes beyond the annotations without contradicting them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, well-structured sentence that leads with the core function and then explains usage context and optionality. Every clause adds value; there is no redundancy or wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has an output schema, and the description explains purpose, scope, and usage trade-offs with a sibling. It is complete for a read-only list tool. Minor gaps like pagination or result size limits are not mentioned, but these are not essential given the output schema and annotations.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, with both parameters (backtestApiKey and backtestBaseUrl) already described in the schema. The description does not add parameter-specific semantics beyond what the schema provides, so the baseline score of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool lists asset pairs with real historical data, including supported timeframes and date ranges. It uses a specific verb ('Lists') and resource ('every asset pair with real historical data'), effectively distinguishing it from the sibling tools submit_backtest and get_backtest_result.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says the tool is optional and explains the alternative: submit_backtest already returns a clear error with the available range. It gives concrete scenarios for use (up-front exploration, recovering from an 'unknown asset' error) and states it is not required before every submit_backtest.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
submit_backtestSubmit BacktestAInspect
Submits a strategy for backtesting against historical OHLCV data. Returns immediately with an id and status — call get_backtest_result to fetch the outcome once it finishes. Testing the same strategy against many assets? Use submit_backtest_batch instead — one call per asset here adds up fast. Optionally accepts confirmationSources to only count a candidate Entry/Exit as a real trade once corroborated by a submit_confirmation_source result (multi-timeframe or cross-asset confirmation) — see the confirmationSources argument and submit_confirmation_source's own description.
| Name | Required | Description | Default |
|---|---|---|---|
| assetPair | No | e.g. "BTC-USDC". | |
| finalDate | No | ISO date string, e.g. "2025-06-01". | |
| initialDate | No | ISO date string, e.g. "2025-01-01". | |
| backtestApiKey | No | Your EmidLabs backtest API key (created in the Console). Not needed if this connector was added with a static 'x-api-key' header. | |
| backtestBaseUrl | No | Defaults to the public production API. Override only for self-hosted/staging use. | |
| confirmationSources | No | Optional. Each entry names a submit_confirmation_source result (same account only, must already be Completed) that every candidate Entry/Exit must be corroborated by before it's simulated as a trade — an unconfirmed candidate is dropped before trade simulation, never appears in get_backtest_trades or affects PnlR/WinRate/etc. See ConfirmedSignalsCount/UnconfirmedSignalsCount on get_backtest_result. A sourceId that doesn't exist, isn't Completed, or belongs to another account fails this submission immediately (unlike live, this is synchronous/batch — letting it through would produce a confusing zero-trade result with no explanation). | |
| strategySnapshotJson | No | The Strategy DSL object — every field below documents its own exact shape, this is just the execution model that ties them together. Entry fills at the close of the candle where decision.entry turns true (no lookahead). A position closes on the first of these to happen, checked in this order: stop-loss hit, take-profit hit, decision.exit turning true (a same-candle stop/take-profit always wins over exit). Multiple positions can be open at once by default — cap with configuration.maxOpenPositions. Results are measured in R-units (risk multiples); expectancyR (average R per trade) is the metric to optimize, not raw win rate or trade count. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| status | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations are all false and convey no safety profile, so the description carries the burden. It discloses asynchronous behavior ('Returns immediately with an id and status'), points to the polling pattern, and details confirmation-source validation semantics (unconfirmed candidates dropped, invalid sourceId fails submission immediately). This is meaningful behavioral context beyond the annotations, though it stops short of discussing rate limits or duplicate-submission effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a few focused sentences, each earning its place: core purpose, async result flow, batch alternative, and confirmationSources usage. It is front-loaded with the main action and remains scannable despite the somewhat long confirmation-sources sentence.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is complex with 7 parameters and a large strategy DSL schema, but the schema and output schema carry the detailed documentation. The description adds the orchestration context an agent needs: poll get_backtest_result, use the batch variant for many assets, and use confirmation sources for cross-validation. A minor gap is not flagging that strategySnapshotJson is effectively required despite being nullable in the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents every parameter in extensive detail. The tool description adds only the cross-tool pointer to submit_confirmation_source and a 'multi-timeframe or cross-asset confirmation' gloss; it doesn't add syntax or format details beyond what the schema provides. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Submits a strategy for backtesting against historical OHLCV data,' naming the action and resource precisely. It explicitly distinguishes itself from submit_backtest_batch and get_backtest_result, so an agent can tell them apart without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly says to use submit_backtest_batch instead when testing the same strategy against many assets, and directs the caller to get_backtest_result to fetch the outcome. It also explains the confirmationSources prerequisite via submit_confirmation_source, giving clear when-to-use and alternative guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
submit_backtest_batchSubmit Backtest BatchAInspect
Submits ONE strategy against MANY asset pairs in a single call — the same backtest you'd get from calling submit_backtest once per asset, without needing dozens of round trips. Returns immediately with a batchId (pass it to get_backtest_batch_results to fetch every asset's outcome, paginated) plus the per-asset id/status assigned right away. Best-effort: one bad asset pair (unknown, or its date range outside coverage) shows up with an error in that item only — every other asset in the batch is unaffected. Optionally accepts confirmationSources, applied identically to every asset in the batch — see submit_backtest's own confirmationSources argument for the full semantics.
| Name | Required | Description | Default |
|---|---|---|---|
| finalDate | No | ISO date string, e.g. "2025-06-01". | |
| assetPairs | No | e.g. ["BTC-USDC", "ETH-USDC", "SOL-USDC"]. Every asset gets the exact same strategySnapshotJson and date range. | |
| initialDate | No | ISO date string, e.g. "2025-01-01". | |
| backtestApiKey | No | Your EmidLabs backtest API key (created in the Console). Not needed if this connector was added with a static 'x-api-key' header. | |
| backtestBaseUrl | No | Defaults to the public production API. Override only for self-hosted/staging use. | |
| confirmationSources | No | Optional. A JSON-encoded STRING (not a native array/object — pass it exactly like a quoted string value), containing the same shape as submit_backtest's own confirmationSources: [{"sourceId":"<a submit_confirmation_source id>","signalType":"entry","validityWindow":{"count":1}}]. Applied identically to every asset pair in this batch (one shared gate, not one per asset). Passed as a raw JSON string rather than a native array because this tool already has one array parameter (assetPairs) — a second one crashes the MCP SDK's own parameter marshaller. A sourceId that doesn't exist, isn't Completed, or belongs to another account fails that item only (same best-effort semantics as an unknown asset pair), not the whole batch. | |
| strategySnapshotJson | No | Same Strategy DSL object submit_backtest takes — see that tool's description for the full shape. |
Output Schema
| Name | Required | Description |
|---|---|---|
| items | No | |
| batchId | No | Pass this to get_backtest_batch_results to fetch every item's status/result, paginated. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations are minimal (readOnlyHint=false, destructiveHint=false, idempotentHint=false), so the description carries the behavioral burden. It discloses immediate return behavior, per-asset id/status assignment, and best-effort error isolation for bad asset pairs. This adds meaningful context beyond the annotations, though it does not discuss broader failure modes like authentication errors or rate limits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences cover purpose, benefit, return behavior, error semantics, and cross-references, with no filler. The primary action and distinguishing batch behavior are front-loaded before the secondary details about best-effort handling and confirmationSources.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given an output schema exists and the input schema has 100% parameter coverage, the description is complete for invoking the tool correctly. It covers return values, the follow-up results tool, best-effort per-item errors, and the shared strategy/date-range semantics, while deferring the heavy DSL shape to submit_backtest appropriately.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The main description adds a useful pointer that strategySnapshotJson and confirmationSources share semantics with submit_backtest, but it does not add parameter meaning beyond what the input schema already thoroughly documents.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Submits ONE strategy against MANY asset pairs in a single call.' It clearly distinguishes itself from the sibling submit_backtest by emphasizing the batching benefit and the single-call semantics, so an agent can tell the two apart without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly frames the tool as the batched alternative to calling submit_backtest once per asset, and tells the agent to pass the returned batchId to get_backtest_batch_results. It gives clear context for when batch submission is appropriate, though it does not explicitly spell out when not to use it, such as when per-asset confirmationSources are needed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
submit_confirmation_sourceSubmit Confirmation SourceAInspect
Runs a strategy against historical data purely to produce a signal timeline used to confirm OTHER backtests — not a backtest itself. Walks the same candles and evaluates the same DSL as submit_backtest, but never simulates a position: no trade, no PnL, no WinRate/drawdown, none of that applies here, because this strategy is never meant to be traded on its own. Returns immediately with an id and status — call get_confirmation_source to check completion, then pass that id as a confirmationSources sourceId in submit_backtest (e.g. only count an XRP entry once a BTC-neutral confirmation source agrees). Costs the same capacity as a regular backtest of the same size — the compute is identical, it just skips trade simulation.
| Name | Required | Description | Default |
|---|---|---|---|
| assetPair | No | e.g. "BTC-USDC". | |
| finalDate | No | ISO date string, e.g. "2025-06-01". | |
| initialDate | No | ISO date string, e.g. "2025-01-01". | |
| backtestApiKey | No | Your EmidLabs backtest API key (created in the Console). Not needed if this connector was added with a static 'x-api-key' header. | |
| backtestBaseUrl | No | Defaults to the public production API. Override only for self-hosted/staging use. | |
| strategySnapshotJson | No | The Strategy DSL object — identical shape to submit_backtest's own. riskManagement is accepted but never used (no position is ever opened), so it's fine to omit. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| status | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses behavior well beyond the annotations: no trade, no PnL, no WinRate/drawdown, immediate return of id and status, and identical compute cost to a regular backtest despite skipping trade simulation. This gives the agent a clear mental model of side effects and cost. No contradiction with the annotations exists.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense but every sentence adds non-obvious value: the confirmation-only purpose, the no-trade-simulation caveat, the async workflow with get_confirmation_source, and the cost equivalence. It is front-loaded with the most important distinction and avoids filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with complex schema and an output schema, the description covers the full lifecycle: what it does, what it does not do, how to retrieve results, how to wire results into a subsequent backtest, and cost implications. An agent has enough context to invoke it correctly and understand the follow-up steps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already covers 100% of parameters with rich descriptions, including the strategy DSL structure, so the description does not need to enumerate parameters. The tool description adds useful cross-context that the DSL matches submit_backtest's, but parameter-level meaning is otherwise left to the schema, which is sufficient.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific, concrete statement: it 'runs a strategy against historical data purely to produce a signal timeline used to confirm OTHER backtests — not a backtest itself.' It clearly distinguishes this from submit_backtest by stating it never simulates a position, so an agent can understand exactly what this tool produces and how it differs from siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage guidance is explicit and actionable: call get_confirmation_source to check completion, then pass the returned id as a confirmationSources sourceId in submit_backtest. It also names the alternative submit_backtest and clarifies this tool is not for standalone trading, giving the agent both the workflow and the when-not-to-use signal.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
3 tool updates
- Changed
submit_backtest1 field changed- added
Input schema / properties / strategySnapshotJson / properties / configuration / properties / timezoneAdded value: +{ + "description": "IANA timezone id (e.g. \"America/Sao_Paulo\") used to localize the DSL's hour()/minute()/dayOfWeek()/isWeekend() functions, for time-of-day or weekday gating conditions. Omit/null defaults to \"America/Sao_Paulo\".", + "type": [ + "string", + "null" + ] +}
- Changed
submit_backtest_batch1 field changed- added
Input schema / properties / strategySnapshotJson / properties / configuration / properties / timezoneAdded value: +{ + "description": "IANA timezone id (e.g. \"America/Sao_Paulo\") used to localize the DSL's hour()/minute()/dayOfWeek()/isWeekend() functions, for time-of-day or weekday gating conditions. Omit/null defaults to \"America/Sao_Paulo\".", + "type": [ + "string", + "null" + ] +}
- Changed
submit_confirmation_source1 field changed- added
Input schema / properties / strategySnapshotJson / properties / configuration / properties / timezoneAdded value: +{ + "description": "IANA timezone id (e.g. \"America/Sao_Paulo\") used to localize the DSL's hour()/minute()/dayOfWeek()/isWeekend() functions, for time-of-day or weekday gating conditions. Omit/null defaults to \"America/Sao_Paulo\".", + "type": [ + "string", + "null" + ] +}
1 tool update
- Changed
submit_backtest_batch3 fields changed- changed
Input schema / properties / confirmationSources / descriptionPrevious value: -"Optional. Same shape as submit_backtest's own confirmationSources — applied identically to every asset pair in this batch (one shared confirmationSources gate, not one per asset). A sourceId that doesn't exist, isn't Completed, or belongs to another account fails that item only (same best-effort semantics as an unknown asset pair), not the whole batch."New value: +"Optional. A JSON-encoded STRING (not a native array/object — pass it exactly like a quoted string value), containing the same shape as submit_backtest's own confirmationSources: [{\"sourceId\":\"<a submit_confirmation_source id>\",\"signalType\":\"entry\",\"validityWindow\":{\"count\":1}}]. Applied identically to every asset pair in this batch (one shared gate, not one per asset). Passed as a raw JSON string rather than a native array because this tool already has one array parameter (assetPairs) — a second one crashes the MCP SDK's own parameter marshaller. A sourceId that doesn't exist, isn't Completed, or belongs to another account fails that item only (same best-effort semantics as an unknown asset pair), not the whole batch." - removed
Input schema / properties / confirmationSources / itemsRemoved value: -{ - "description": "One confirmation requirement: this backtest's own candidate Entry/Exit only counts as a trade once sourceId's own signal timeline is corroborated within validityWindow.", - "properties": { - "signalType": { - "description": "\"entry\" or \"exit\" — which of the source's signal types counts as confirming. Defaults to \"entry\" when omitted.", - "type": [ - "string", - "null" - ] - }, - "sourceId": { - "description": "The id returned by submit_confirmation_source (same account only) whose signal timeline this backtest's candidates must be corroborated by.", - "type": [ - "string", - "null" - ] - }, - "validityWindow": { - "description": "An OBJECT, not a bare number — e.g. { \"count\": 5 }. Defaults to { \"count\": 1 } when omitted.", - "properties": { - "count": { - "description": "Number of candles of the source's own timeframe. Defaults to 1 when omitted.", - "type": "integer" - } - }, - "type": [ - "object", - "null" - ] - } - }, - "required": [ - "sourceId" - ], - "type": [ - "object", - "null" - ] -} - changed
Input schema / properties / confirmationSources / typePrevious value: -[ - "array", - "null" -]New value: +[ + "string", + "null" +]
2 tool updates
- Changed
submit_backtest1 field changed- changed
Input schema / properties / confirmationSources / items / properties / validityWindow / descriptionPrevious value: -"How recent the source's own signal must be, expressed in candles of the SOURCE's own timeframe — not a fixed duration, so it scales automatically with whichever strategy is confirming."New value: +"An OBJECT, not a bare number — e.g. { \"count\": 5 }. Defaults to { \"count\": 1 } when omitted."
- Changed
submit_backtest_batch1 field changed- changed
Input schema / properties / confirmationSources / items / properties / validityWindow / descriptionPrevious value: -"How recent the source's own signal must be, expressed in candles of the SOURCE's own timeframe — not a fixed duration, so it scales automatically with whichever strategy is confirming."New value: +"An OBJECT, not a bare number — e.g. { \"count\": 5 }. Defaults to { \"count\": 1 } when omitted."
1 tool update
- Changed
submit_backtest_batch1 field changed- added
Input schema / properties / confirmationSourcesAdded value: +{ + "default": null, + "description": "Optional. Same shape as submit_backtest's own confirmationSources — applied identically to every asset pair in this batch (one shared confirmationSources gate, not one per asset). A sourceId that doesn't exist, isn't Completed, or belongs to another account fails that item only (same best-effort semantics as an unknown asset pair), not the whole batch.", + "items": { + "description": "One confirmation requirement: this backtest's own candidate Entry/Exit only counts as a trade once sourceId's own signal timeline is corroborated within validityWindow.", + "properties": { + "signalType": { + "description": "\"entry\" or \"exit\" — which of the source's signal types counts as confirming. Defaults to \"entry\" when omitted.", + "type": [ + "string", + "null" + ] + }, + "sourceId": { + "description": "The id returned by submit_confirmation_source (same account only) whose signal timeline this backtest's candidates must be corroborated by.", + "type": [ + "string", + "null" + ] + }, + "validityWindow": { + "description": "How recent the source's own signal must be, expressed in candles of the SOURCE's own timeframe — not a fixed duration, so it scales automatically with whichever strategy is confirming.", + "properties": { + "count": { + "description": "Number of candles of the source's own timeframe. Defaults to 1 when omitted.", + "type": "integer" + } + }, + "type": [ + "object", + "null" + ] + } + }, + "required": [ + "sourceId" + ], + "type": [ + "object", + "null" + ] + }, + "type": [ + "array", + "null" + ] +}
6 tool updates
- Changed
get_backtest_batch_results2 fields changed- added
Output schema / properties / items / items / properties / result / properties / confirmedSignalsCountAdded value: +{ + "description": "Only meaningful when the request declared confirmationSources — how many candidates cleared confirmation and became one of the Trades above.", + "type": "integer" +} - added
Output schema / properties / items / items / properties / result / properties / unconfirmedSignalsCountAdded 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" +}
- Changed
get_backtest_result2 fields changed- added
Output schema / properties / result / properties / confirmedSignalsCountAdded value: +{ + "description": "Only meaningful when the request declared confirmationSources — how many candidates cleared confirmation and became one of the Trades above.", + "type": "integer" +} - added
Output schema / properties / result / properties / unconfirmedSignalsCountAdded 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" +}
- Added
get_confirmation_source - Added
get_confirmation_source_signals - Changed
submit_backtest1 field changed- added
Input schema / properties / confirmationSourcesAdded value: +{ + "default": null, + "description": "Optional. Each entry names a submit_confirmation_source result (same account only, must already be Completed) that every candidate Entry/Exit must be corroborated by before it's simulated as a trade — an unconfirmed candidate is dropped before trade simulation, never appears in get_backtest_trades or affects PnlR/WinRate/etc. See ConfirmedSignalsCount/UnconfirmedSignalsCount on get_backtest_result. A sourceId that doesn't exist, isn't Completed, or belongs to another account fails this submission immediately (unlike live, this is synchronous/batch — letting it through would produce a confusing zero-trade result with no explanation).", + "items": { + "description": "One confirmation requirement: this backtest's own candidate Entry/Exit only counts as a trade once sourceId's own signal timeline is corroborated within validityWindow.", + "properties": { + "signalType": { + "description": "\"entry\" or \"exit\" — which of the source's signal types counts as confirming. Defaults to \"entry\" when omitted.", + "type": [ + "string", + "null" + ] + }, + "sourceId": { + "description": "The id returned by submit_confirmation_source (same account only) whose signal timeline this backtest's candidates must be corroborated by.", + "type": [ + "string", + "null" + ] + }, + "validityWindow": { + "description": "How recent the source's own signal must be, expressed in candles of the SOURCE's own timeframe — not a fixed duration, so it scales automatically with whichever strategy is confirming.", + "properties": { + "count": { + "description": "Number of candles of the source's own timeframe. Defaults to 1 when omitted.", + "type": "integer" + } + }, + "type": [ + "object", + "null" + ] + } + }, + "required": [ + "sourceId" + ], + "type": [ + "object", + "null" + ] + }, + "type": [ + "array", + "null" + ] +}
- Added
submit_confirmation_source
2 tool updates
- Changed
get_backtest_batch_results3 fields changed- added
Output schema / properties / items / items / properties / candlesProcessedAdded value: +{ + "description": "Number of candles the analyser processed for this item. Null until Status is \"Completed\". This is raw volume, not the plan's billing unit — see UnitsConsumed for that.", + "type": [ + "integer", + "null" + ] +} - changed
Output schema / properties / items / items / properties / unitsConsumed / descriptionPrevious value: -"Number of candles the analyser processed for this item. Null until Status is \"Completed\"."New value: +"The actual execution-unit cost of this item, 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\"." - changed
Output schema / properties / items / items / properties / unitsConsumed / typePrevious value: -[ - "integer", - "null" -]New value: +[ + "number", + "null" +]
- Changed
get_backtest_result3 fields changed- added
Output schema / properties / candlesProcessedAdded 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" + ] +} - changed
Output schema / properties / unitsConsumed / descriptionPrevious 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\"." - changed
Output schema / properties / unitsConsumed / typePrevious value: -[ - "integer", - "null" -]New value: +[ + "number", + "null" +]
2 tool updates
- Changed
submit_backtest1 field changed- changed
Input schema / properties / strategySnapshotJson / properties / inputs / descriptionPrevious value: -"Named computed values, one JSON-string expression each, evaluated once per candle. Raw fields: close, open, high, low, volume. Built-in functions (case-sensitive, lowercase — no others exist, e.g. avg()/SMA() uppercase/close[N] bracket indexing are NOT supported): ema(series,period), sma(series,period), rsi(series,period), atr(period), adx(period), adxPlusDi(period), adxMinusDi(period), crossUp(a,b), crossDown(a,b), highest(series,n), lowest(series,n), change(series), volumeSma(period), volumeSpike(multiplier), body(), range(), upperWick(), lowerWick(), abs(x), min(a,b), max(a,b). Candlestick patterns (all no-arg, boolean, read only closed-candle OHLC, same in backtest and live): single-candle hammer(), shootingStar(), doji(), bullishMarubozu(), bearishMarubozu(), spinningTop(), dragonflyDoji(), gravestoneDoji(), longLeggedDoji(); two-candle bullishEngulfing(), bearishEngulfing(), piercingLine(), darkCloudCover(), bullishHarami(), bearishHarami(), haramiCross(), tweezerTop(), tweezerBottom(); three-plus-candle morningStar(), eveningStar(), threeWhiteSoldiers(), threeBlackCrows(), threeInsideUp(), threeInsideDown(), threeOutsideUp(), threeOutsideDown(), risingThreeMethods(), fallingThreeMethods(). Caveat: hammer()/shootingStar() are shape-only, no prior-trend check (same shape is Hammer in a downtrend but Hanging Man in an uptrend, and vice versa for shootingStar/Inverted Hammer) — pair with a trend/momentum condition rather than using the shape alone. An input may only reference inputs defined above it (no forward/circular references). Example: {\"emaFast\":\"ema(close, 9)\",\"emaSlow\":\"ema(close, 21)\"}"New value: +"Named computed values, one JSON-string expression each, evaluated once per candle. Raw fields: close, open, high, low, volume. Built-in functions (case-sensitive, lowercase — no others exist, e.g. avg()/SMA() uppercase/close[N] bracket indexing are NOT supported): ema(series,period), sma(series,period), rsi(series,period), atr(period), adx(period), adxPlusDi(period), adxMinusDi(period), crossUp(a,b), crossDown(a,b), highest(series,n), lowest(series,n), change(series), shift(series,n) [look-back only, NaN before enough history], any(boolSeries,n), all(boolSeries,n), count(boolSeries,n) [over the n candles before the current one], swingHigh(series,confirmBars), swingLow(series,confirmBars) [confirmed N-bar swing point, true confirmBars candles AFTER the actual peak/trough — never at the peak itself, so it can't repaint between backtest and live], body(), range(), upperWick(), lowerWick(), isBullish(), isBearish(), abs(x), min(a,b), max(a,b). There is no volumeSma()/volumeSpike() — volume is a plain series like close/open/high/low, so use sma(volume,period) and volume > sma(volume,period) * multiplier instead. Candlestick patterns (all no-arg, boolean, read only closed-candle OHLC, same in backtest and live): single-candle hammer(), shootingStar(), doji(), bullishMarubozu(), bearishMarubozu(), spinningTop(), dragonflyDoji(), gravestoneDoji(), longLeggedDoji(); two-candle bullishEngulfing(), bearishEngulfing(), piercingLine(), darkCloudCover(), bullishHarami(), bearishHarami(), haramiCross(), tweezerTop(), tweezerBottom(); three-plus-candle morningStar(), eveningStar(), threeWhiteSoldiers(), threeBlackCrows(), threeInsideUp(), threeInsideDown(), threeOutsideUp(), threeOutsideDown(), risingThreeMethods(), fallingThreeMethods(). Caveat: hammer()/shootingStar() are shape-only, no prior-trend check (same shape is Hammer in a downtrend but Hanging Man in an uptrend, and vice versa for shootingStar/Inverted Hammer) — pair with a trend/momentum condition rather than using the shape alone. An input may only reference inputs defined above it (no forward/circular references). Example: {\"emaFast\":\"ema(close, 9)\",\"emaSlow\":\"ema(close, 21)\"}"
- Changed
submit_backtest_batch1 field changed- changed
Input schema / properties / strategySnapshotJson / properties / inputs / descriptionPrevious value: -"Named computed values, one JSON-string expression each, evaluated once per candle. Raw fields: close, open, high, low, volume. Built-in functions (case-sensitive, lowercase — no others exist, e.g. avg()/SMA() uppercase/close[N] bracket indexing are NOT supported): ema(series,period), sma(series,period), rsi(series,period), atr(period), adx(period), adxPlusDi(period), adxMinusDi(period), crossUp(a,b), crossDown(a,b), highest(series,n), lowest(series,n), change(series), volumeSma(period), volumeSpike(multiplier), body(), range(), upperWick(), lowerWick(), abs(x), min(a,b), max(a,b). Candlestick patterns (all no-arg, boolean, read only closed-candle OHLC, same in backtest and live): single-candle hammer(), shootingStar(), doji(), bullishMarubozu(), bearishMarubozu(), spinningTop(), dragonflyDoji(), gravestoneDoji(), longLeggedDoji(); two-candle bullishEngulfing(), bearishEngulfing(), piercingLine(), darkCloudCover(), bullishHarami(), bearishHarami(), haramiCross(), tweezerTop(), tweezerBottom(); three-plus-candle morningStar(), eveningStar(), threeWhiteSoldiers(), threeBlackCrows(), threeInsideUp(), threeInsideDown(), threeOutsideUp(), threeOutsideDown(), risingThreeMethods(), fallingThreeMethods(). Caveat: hammer()/shootingStar() are shape-only, no prior-trend check (same shape is Hammer in a downtrend but Hanging Man in an uptrend, and vice versa for shootingStar/Inverted Hammer) — pair with a trend/momentum condition rather than using the shape alone. An input may only reference inputs defined above it (no forward/circular references). Example: {\"emaFast\":\"ema(close, 9)\",\"emaSlow\":\"ema(close, 21)\"}"New value: +"Named computed values, one JSON-string expression each, evaluated once per candle. Raw fields: close, open, high, low, volume. Built-in functions (case-sensitive, lowercase — no others exist, e.g. avg()/SMA() uppercase/close[N] bracket indexing are NOT supported): ema(series,period), sma(series,period), rsi(series,period), atr(period), adx(period), adxPlusDi(period), adxMinusDi(period), crossUp(a,b), crossDown(a,b), highest(series,n), lowest(series,n), change(series), shift(series,n) [look-back only, NaN before enough history], any(boolSeries,n), all(boolSeries,n), count(boolSeries,n) [over the n candles before the current one], swingHigh(series,confirmBars), swingLow(series,confirmBars) [confirmed N-bar swing point, true confirmBars candles AFTER the actual peak/trough — never at the peak itself, so it can't repaint between backtest and live], body(), range(), upperWick(), lowerWick(), isBullish(), isBearish(), abs(x), min(a,b), max(a,b). There is no volumeSma()/volumeSpike() — volume is a plain series like close/open/high/low, so use sma(volume,period) and volume > sma(volume,period) * multiplier instead. Candlestick patterns (all no-arg, boolean, read only closed-candle OHLC, same in backtest and live): single-candle hammer(), shootingStar(), doji(), bullishMarubozu(), bearishMarubozu(), spinningTop(), dragonflyDoji(), gravestoneDoji(), longLeggedDoji(); two-candle bullishEngulfing(), bearishEngulfing(), piercingLine(), darkCloudCover(), bullishHarami(), bearishHarami(), haramiCross(), tweezerTop(), tweezerBottom(); three-plus-candle morningStar(), eveningStar(), threeWhiteSoldiers(), threeBlackCrows(), threeInsideUp(), threeInsideDown(), threeOutsideUp(), threeOutsideDown(), risingThreeMethods(), fallingThreeMethods(). Caveat: hammer()/shootingStar() are shape-only, no prior-trend check (same shape is Hammer in a downtrend but Hanging Man in an uptrend, and vice versa for shootingStar/Inverted Hammer) — pair with a trend/momentum condition rather than using the shape alone. An input may only reference inputs defined above it (no forward/circular references). Example: {\"emaFast\":\"ema(close, 9)\",\"emaSlow\":\"ema(close, 21)\"}"
2 tool updates
- Changed
submit_backtest1 field changed- changed
Input schema / properties / strategySnapshotJson / properties / inputs / descriptionPrevious value: -"Named computed values, one JSON-string expression each, evaluated once per candle. Raw fields: close, open, high, low, volume. Built-in functions (case-sensitive, lowercase — no others exist, e.g. avg()/SMA() uppercase/close[N] bracket indexing are NOT supported): ema(series,period), sma(series,period), rsi(series,period), atr(period), adx(period), adxPlusDi(period), adxMinusDi(period), crossUp(a,b), crossDown(a,b), highest(series,n), lowest(series,n), change(series), volumeSma(period), volumeSpike(multiplier), body(), range(), upperWick(), lowerWick(), abs(x), min(a,b), max(a,b). An input may only reference inputs defined above it (no forward/circular references). Example: {\"emaFast\":\"ema(close, 9)\",\"emaSlow\":\"ema(close, 21)\"}"New value: +"Named computed values, one JSON-string expression each, evaluated once per candle. Raw fields: close, open, high, low, volume. Built-in functions (case-sensitive, lowercase — no others exist, e.g. avg()/SMA() uppercase/close[N] bracket indexing are NOT supported): ema(series,period), sma(series,period), rsi(series,period), atr(period), adx(period), adxPlusDi(period), adxMinusDi(period), crossUp(a,b), crossDown(a,b), highest(series,n), lowest(series,n), change(series), volumeSma(period), volumeSpike(multiplier), body(), range(), upperWick(), lowerWick(), abs(x), min(a,b), max(a,b). Candlestick patterns (all no-arg, boolean, read only closed-candle OHLC, same in backtest and live): single-candle hammer(), shootingStar(), doji(), bullishMarubozu(), bearishMarubozu(), spinningTop(), dragonflyDoji(), gravestoneDoji(), longLeggedDoji(); two-candle bullishEngulfing(), bearishEngulfing(), piercingLine(), darkCloudCover(), bullishHarami(), bearishHarami(), haramiCross(), tweezerTop(), tweezerBottom(); three-plus-candle morningStar(), eveningStar(), threeWhiteSoldiers(), threeBlackCrows(), threeInsideUp(), threeInsideDown(), threeOutsideUp(), threeOutsideDown(), risingThreeMethods(), fallingThreeMethods(). Caveat: hammer()/shootingStar() are shape-only, no prior-trend check (same shape is Hammer in a downtrend but Hanging Man in an uptrend, and vice versa for shootingStar/Inverted Hammer) — pair with a trend/momentum condition rather than using the shape alone. An input may only reference inputs defined above it (no forward/circular references). Example: {\"emaFast\":\"ema(close, 9)\",\"emaSlow\":\"ema(close, 21)\"}"
- Changed
submit_backtest_batch1 field changed- changed
Input schema / properties / strategySnapshotJson / properties / inputs / descriptionPrevious value: -"Named computed values, one JSON-string expression each, evaluated once per candle. Raw fields: close, open, high, low, volume. Built-in functions (case-sensitive, lowercase — no others exist, e.g. avg()/SMA() uppercase/close[N] bracket indexing are NOT supported): ema(series,period), sma(series,period), rsi(series,period), atr(period), adx(period), adxPlusDi(period), adxMinusDi(period), crossUp(a,b), crossDown(a,b), highest(series,n), lowest(series,n), change(series), volumeSma(period), volumeSpike(multiplier), body(), range(), upperWick(), lowerWick(), abs(x), min(a,b), max(a,b). An input may only reference inputs defined above it (no forward/circular references). Example: {\"emaFast\":\"ema(close, 9)\",\"emaSlow\":\"ema(close, 21)\"}"New value: +"Named computed values, one JSON-string expression each, evaluated once per candle. Raw fields: close, open, high, low, volume. Built-in functions (case-sensitive, lowercase — no others exist, e.g. avg()/SMA() uppercase/close[N] bracket indexing are NOT supported): ema(series,period), sma(series,period), rsi(series,period), atr(period), adx(period), adxPlusDi(period), adxMinusDi(period), crossUp(a,b), crossDown(a,b), highest(series,n), lowest(series,n), change(series), volumeSma(period), volumeSpike(multiplier), body(), range(), upperWick(), lowerWick(), abs(x), min(a,b), max(a,b). Candlestick patterns (all no-arg, boolean, read only closed-candle OHLC, same in backtest and live): single-candle hammer(), shootingStar(), doji(), bullishMarubozu(), bearishMarubozu(), spinningTop(), dragonflyDoji(), gravestoneDoji(), longLeggedDoji(); two-candle bullishEngulfing(), bearishEngulfing(), piercingLine(), darkCloudCover(), bullishHarami(), bearishHarami(), haramiCross(), tweezerTop(), tweezerBottom(); three-plus-candle morningStar(), eveningStar(), threeWhiteSoldiers(), threeBlackCrows(), threeInsideUp(), threeInsideDown(), threeOutsideUp(), threeOutsideDown(), risingThreeMethods(), fallingThreeMethods(). Caveat: hammer()/shootingStar() are shape-only, no prior-trend check (same shape is Hammer in a downtrend but Hanging Man in an uptrend, and vice versa for shootingStar/Inverted Hammer) — pair with a trend/momentum condition rather than using the shape alone. An input may only reference inputs defined above it (no forward/circular references). Example: {\"emaFast\":\"ema(close, 9)\",\"emaSlow\":\"ema(close, 21)\"}"
3 tool updates
- Changed
get_backtest_batch_results6 fields changed- changed
Output schema / properties / items / items / properties / result / properties / bothHit / descriptionPrevious 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." - changed
Output schema / properties / items / items / properties / result / properties / conditionsDistributionPct / descriptionPrevious 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." - added
Output schema / properties / items / items / properties / result / properties / currentDrawdownRAdded 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" +} - added
Output schema / properties / items / items / properties / result / properties / maxDrawdownRAdded 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" +} - added
Output schema / properties / items / items / properties / result / properties / openPositionsAtEndAdded 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" +} - added
Output schema / properties / items / items / properties / result / properties / unrealizedPnlRAtEndAdded 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" +}
- Changed
get_backtest_result6 fields changed- changed
Output schema / properties / result / properties / bothHit / descriptionPrevious 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." - changed
Output schema / properties / result / properties / conditionsDistributionPct / descriptionPrevious 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." - added
Output schema / properties / result / properties / currentDrawdownRAdded 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" +} - added
Output schema / properties / result / properties / maxDrawdownRAdded 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" +} - added
Output schema / properties / result / properties / openPositionsAtEndAdded 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" +} - added
Output schema / properties / result / properties / unrealizedPnlRAtEndAdded 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" +}
- Changed
get_backtest_trades10 fields changed- added
Output schema / properties / items / items / properties / conditionsAtEntry / descriptionAdded value: +"Every named condition from strategySnapshotJson.conditions at entry time — true AND false, not just the ones that were true." - added
Output schema / properties / items / items / properties / entryExecutionCandleOpenTime / descriptionAdded value: +"Candle open time this trade's entry actually filled on. Currently always equal to EntrySignalCandleOpenTime — see that field's note." - added
Output schema / properties / items / items / properties / entryPrice / descriptionAdded value: +"Fill price at entry — always the entry candle's close." - added
Output schema / properties / items / items / properties / entrySignalCandleOpenTime / descriptionAdded value: +"Candle open time this trade's entry signal fired on. Currently always equal to EntryExecutionCandleOpenTime — reserved for a future delayed-fill model (e.g. signal on candle close, execution on next candle open), not yet implemented. Don't rely on these differing today." - added
Output schema / properties / items / items / properties / exitExecutionCandleOpenTime / descriptionAdded value: +"Candle open time this trade's exit actually filled on. Currently always equal to ExitSignalCandleOpenTime — see that field's note." - added
Output schema / properties / items / items / properties / exitPrice / descriptionAdded value: +"Fill price at exit — StopPrice, TakePrice, or the exit candle's close, depending on ExitReason." - added
Output schema / properties / items / items / properties / exitSignalCandleOpenTime / descriptionAdded value: +"Candle open time this trade's exit signal fired on. Currently always equal to ExitExecutionCandleOpenTime — same reserved-for-future-use note as the entry pair." - added
Output schema / properties / items / items / properties / holdingCandlesAdded value: +{ + "description": "Timeframe-agnostic candle count the position was held for (exit candle index minus entry candle index). Minimum possible value is 1, not 0 — a position opened on candle i can earliest close on candle i+1. Derive real elapsed time from EntryExecutionCandleOpenTime/ExitExecutionCandleOpenTime if needed.", + "type": "integer" +} - added
Output schema / properties / items / items / properties / scoreBreakdownAtEntry / descriptionAdded value: +"Weight contributed by each condition toward TotalScoreAtEntry — 0 for conditions that were false." - added
Output schema / properties / items / items / properties / totalScoreAtEntry / descriptionAdded value: +"Total score at entry — the value compared against the threshold in decision.entry."
5 tool updates
- Changed
get_backtest_batch_results1 field changed- added
Output schema / properties / items / items / properties / result / properties / totalFeeRAdded 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" +}
- Changed
get_backtest_result1 field changed- added
Output schema / properties / result / properties / totalFeeRAdded 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" +}
- Changed
get_backtest_trades4 fields changed- added
Output schema / properties / items / items / properties / feeRAdded value: +{ + "description": "R-units subtracted from this trade's PnlR by configuration.entryFeePct/exitFeePct (0 if neither was set). PnlR is already net of this — PnlR + FeeR recovers the pre-fee raw R. Not directly comparable across trades with different RiskDistance: this scales inversely with each trade's own stop distance.", + "type": "number" +} - added
Output schema / properties / items / items / properties / riskDistanceAdded value: +{ + "description": "Price distance between EntryPrice and StopPrice — the denominator PnlR/FeeR are expressed in units of.", + "type": "number" +} - added
Output schema / properties / items / items / properties / stopPriceAdded value: +{ + "description": "The stop-loss price this trade was risk-managed against.", + "type": "number" +} - added
Output schema / properties / items / items / properties / takePriceAdded value: +{ + "description": "The take-profit price this trade was risk-managed against.", + "type": "number" +}
- Changed
submit_backtest2 fields changed- added
Input schema / properties / strategySnapshotJson / properties / configuration / properties / entryFeePctAdded value: +{ + "description": "Simulated exchange fee on entry, as a percent (e.g. 0.1 = 0.1%). Omit/null = 0 (no fee, backward compatible). Subtracted from every trade's pnlR/pnlPct so results are net-of-fee by construction. 0-5 range. See the pnlR/expectancyR field descriptions on get_backtest_result for the R-vs-% caveat once a fee is set.", + "type": [ + "number", + "null" + ] +} - added
Input schema / properties / strategySnapshotJson / properties / configuration / properties / exitFeePctAdded value: +{ + "description": "Simulated exchange fee on exit, as a percent (e.g. 0.1 = 0.1%). Same semantics as EntryFeePct — real exchanges can charge different maker/taker rates per leg, so this is independent, not assumed equal.", + "type": [ + "number", + "null" + ] +}
- Changed
submit_backtest_batch2 fields changed- added
Input schema / properties / strategySnapshotJson / properties / configuration / properties / entryFeePctAdded value: +{ + "description": "Simulated exchange fee on entry, as a percent (e.g. 0.1 = 0.1%). Omit/null = 0 (no fee, backward compatible). Subtracted from every trade's pnlR/pnlPct so results are net-of-fee by construction. 0-5 range. See the pnlR/expectancyR field descriptions on get_backtest_result for the R-vs-% caveat once a fee is set.", + "type": [ + "number", + "null" + ] +} - added
Input schema / properties / strategySnapshotJson / properties / configuration / properties / exitFeePctAdded value: +{ + "description": "Simulated exchange fee on exit, as a percent (e.g. 0.1 = 0.1%). Same semantics as EntryFeePct — real exchanges can charge different maker/taker rates per leg, so this is independent, not assumed equal.", + "type": [ + "number", + "null" + ] +}
2 tool updates
- Changed
get_backtest_batch_results2 fields changed- changed
Output schema / properties / items / items / properties / result / properties / profitFactor / descriptionPrevious 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." - changed
Output schema / properties / items / items / properties / result / properties / profitFactor / typePrevious value: -"number"New value: +[ + "number", + "null" +]
- Changed
get_backtest_result2 fields changed- changed
Output schema / properties / result / properties / profitFactor / descriptionPrevious 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." - changed
Output schema / properties / result / properties / profitFactor / typePrevious value: -"number"New value: +[ + "number", + "null" +]
2 tool updates
- Changed
get_backtest_batch_results2 fields changed- added
Output schema / properties / items / items / properties / runtimeMsAdded value: +{ + "description": "How long the analyser actually took to run this item, in milliseconds — pure compute time. Null until Status is \"Completed\".", + "type": [ + "integer", + "null" + ] +} - added
Output schema / properties / items / items / properties / unitsConsumedAdded value: +{ + "description": "Number of candles the analyser processed for this item. Null until Status is \"Completed\".", + "type": [ + "integer", + "null" + ] +}
- Changed
get_backtest_result2 fields changed- added
Output schema / properties / runtimeMsAdded 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" + ] +} - added
Output schema / properties / unitsConsumedAdded value: +{ + "description": "Number of candles the analyser processed for this backtest. Null until Status is \"Completed\".", + "type": [ + "integer", + "null" + ] +}
3 tool updates
- Added
get_backtest_batch_results - Changed
get_backtest_result3 fields changed- added
Output schema / properties / recentAvgPnlRAdded 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" + ] +} - added
Output schema / properties / recentOutcomesAdded 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" + ] +} - added
Output schema / properties / recentTradeCountAdded 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" + ] +}
- Added
submit_backtest_batch
1 tool update
- Added
get_backtest_trades
2 tool updates
- Changed
get_backtest_result3 fields changed- added
Input schema / properties / id / defaultAdded value: +null - changed
Input schema / properties / id / typePrevious value: -"string"New value: +[ + "string", + "null" +] - removed
Input schema / requiredRemoved value: -[ - "id" -]
- Changed
submit_backtest18 fields changed- added
Input schema / properties / assetPair / defaultAdded value: +null - changed
Input schema / properties / assetPair / typePrevious value: -"string"New value: +[ + "string", + "null" +] - added
Input schema / properties / finalDate / defaultAdded value: +null - changed
Input schema / properties / finalDate / typePrevious value: -"string"New value: +[ + "string", + "null" +] - added
Input schema / properties / initialDate / defaultAdded value: +null - changed
Input schema / properties / initialDate / typePrevious value: -"string"New value: +[ + "string", + "null" +] - added
Input schema / properties / strategySnapshotJson / defaultAdded value: +null - changed
Input schema / properties / strategySnapshotJson / properties / conditions / additionalProperties / typePrevious value: -"string"New value: +[ + "string", + "null" +] - changed
Input schema / properties / strategySnapshotJson / properties / conditions / typePrevious value: -"object"New value: +[ + "object", + "null" +] - changed
Input schema / properties / strategySnapshotJson / properties / configuration / properties / timeframe / typePrevious value: -"string"New value: +[ + "string", + "null" +] - changed
Input schema / properties / strategySnapshotJson / properties / configuration / typePrevious value: -"object"New value: +[ + "object", + "null" +] - changed
Input schema / properties / strategySnapshotJson / properties / decision / properties / entry / typePrevious value: -"string"New value: +[ + "string", + "null" +] - changed
Input schema / properties / strategySnapshotJson / properties / decision / typePrevious value: -"object"New value: +[ + "object", + "null" +] - changed
Input schema / properties / strategySnapshotJson / properties / inputs / additionalProperties / typePrevious value: -"string"New value: +[ + "string", + "null" +] - changed
Input schema / properties / strategySnapshotJson / properties / inputs / typePrevious value: -"object"New value: +[ + "object", + "null" +] - changed
Input schema / properties / strategySnapshotJson / properties / score / typePrevious value: -"object"New value: +[ + "object", + "null" +] - changed
Input schema / properties / strategySnapshotJson / typePrevious value: -"object"New value: +[ + "object", + "null" +] - removed
Input schema / requiredRemoved value: -[ - "assetPair", - "initialDate", - "finalDate", - "strategySnapshotJson" -]
1 tool update
- Changed
submit_backtest1 field changed- changed
Input schema / properties / strategySnapshotJson / properties / configuration / properties / timeframe / descriptionPrevious value: -"One of \"15M\", \"30M\", \"1H\", \"2H\", \"4H\", \"1D\"."New value: +"One of \"5M\", \"15M\", \"30M\", \"1H\", \"2H\", \"4H\", \"1D\"."
Frequently Asked Questions
Claiming proves that you control a remote MCP connector. It does not move, proxy, or interrupt the server.
Open the connector listing, choose Claim ownership, and sign in to Glama.
Complete one verification method:
GitHub identity — fastest for official registry listings. For a namespace such as
io.github.alice/server, link the matching GitHub user, then choose Claim with GitHub. An organization namespace such asio.github.acme/serveralso needs that organization to have installed the Glama AI GitHub App and approved its permissions, because GitHub discloses organization membership only to apps it has installed. Use HTTP or DNS when it has not.HTTP challenge — works when you can deploy a public file. Generate a token, publish the exact JSON Glama shows at
/.well-known/glama.jsonon the same origin as the connector, then choose Check HTTP challenge.DNS challenge — works when you control DNS but cannot change the server. Generate a token, create the exact TXT record Glama shows, wait for it to propagate, then choose Check DNS challenge.
After verification, Glama sends a confirmation email and gives you access to listing details, thumbnails, health checks, and analytics. Keep the HTTP file or DNS record in place: Glama periodically checks it and ownership remains verified while the token is discoverable.
The HTTP ownership file has this structure:
{
"$schema": "https://glama.ai/mcp/schemas/connector.json",
"claim": "glama_claim_..."
}Claim tokens are opaque, stable, and bound to the signed-in Glama account. They contain no email address or other personal information. If Glama can no longer discover a verified HTTP or DNS token, it starts a seven-day grace period before removing claim-based access. Restore the same token during that period to keep ownership verified. Never publish an email address, Glama session token, GitHub token, or connector credential as ownership proof.
If verification fails, confirm that you copied the current token exactly. The HTTP file must be public, return valid JSON with a successful HTTP response, and stay on the connector's origin. DNS changes may need more time to propagate. A claim cannot transfer to a different origin or hostname: if the connector target changes, Glama starts the grace period and the new target must be claimed separately after the previous claim is released.
For a connector linked to the official MCP Registry, registry updates continue to replace its name, description, and URL by default. After claiming, open Manage connector and enable Use Glama listing details as the source of truth if edits made on Glama should be preserved. Categories and thumbnails are always managed on Glama; registry linkage and technical connection settings continue to sync.
Control your server's listing on Glama, including description and metadata
Access analytics and receive server usage reports
Get monitoring and health status updates for your server
Feature your server to boost visibility and reach more users
To improve your MCP server's ranking:
Claim ownership of the server listing
Complete the server profile with an accurate description and thumbnail
Provide a test profile so Glama can connect to and evaluate the server
Keep tool definitions clear and complete to earn a high Tool Definition Quality Score (TDQS)
Route real usage through the Glama Gateway; more recorded successful server uses also improve the ranking
For users:
Full audit trail – every tool call is logged with inputs and outputs for compliance and debugging
Granular tool control – enable or disable individual tools per connector to limit what your AI agents can do
Centralized credential management – store and rotate API keys and OAuth tokens in one place
Change alerts – get notified when a connector changes its schema, adds or removes tools, or updates tool definitions, so nothing breaks silently
For server owners:
Proven adoption – public usage metrics on your listing show real-world traction and build trust with prospective users
Tool-level analytics – see which tools are being used most, helping you prioritize development and documentation
Direct user feedback – users can report issues and suggest improvements through the listing, giving you a channel you would not have otherwise
The connector status is unhealthy when Glama is unable to successfully connect to the server. This can happen for several reasons:
The server is experiencing an outage
The URL of the server is wrong
Credentials required to access the server are missing or invalid
If you are the owner of this MCP connector and would like to make modifications to the listing, including providing test credentials for accessing the server, please contact support@glama.ai.
Discussions
No comments yet. Be the first to start the discussion!
Related MCP Connectors
Crypto backtesting & Bitcoin cycle analytics. Point-in-time, DSR-corrected, look-ahead-aware.
Crypto backtesting tools: real backtests with robustness verdicts, daily signals and market data.
Backtest strategies and analyze portfolios on any ticker: CAGR, drawdown, Sharpe, from real data.
Backtest trading strategies written in plain English, on real market data, with graded results.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceexposes a remote MCP endpoint so agents can: run strategy backtests by symbol/timeframe/date range, pass strategy inputs programmatically, receive structured backtest results (trades, win rate, profit, drawdown), keep long-running runs observable via progress notifications, support Binance Futures tickers only, enforce a maximum of 1440 candles per backtest, apply a rate limit of 3 backtests per5-

panther-mcpofficial
AlicenseAqualityDmaintenanceEnables AI assistants to backtest trading strategies described in plain English, providing access to market data, technical indicators, and comprehensive performance reports.131MIT- AlicenseNot gradedqualityBmaintenanceProvides tools to research crypto trading strategies via backtesting, walk-forward validation, and paper trading, with a deflated-Sharpe overfitting check. Enables natural-language-driven analysis and interpretation of strategy performance.3Apache 2.0
- AlicenseNot gradedqualityDmaintenanceEnables backtesting of limit-order strategies on Polymarket's BTC 5-minute markets using historical data, with tools to browse markets, get price series, and run simulations.MIT
Glama MCP Gateway
Add one secure layer between your agents and this server.
TDQS
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.
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.
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.
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.