Backtesting API

Full reference for the Backtesting API — endpoints, request schema, response schema, metrics, and error codes.

Overview

The Backtesting API exposes two endpoints. You submit a strategy execution request and then poll for the result using the returned backtest ID.

Base URL: https://api.emidlabs.com/api/public/v1

All requests require the x-api-key header with a valid API key. Keys are generated in the Console.

#POST /backtest — Submit

POST/backtest

Submit a new backtest for execution.

The body must be application/json. The strategy is embedded as a serialized JSON string inside strategySnapshotJson.

Request body

FieldTypeRequiredDescription
strategySnapshotJsonstringYesStrategy object serialized as a JSON string.
assetPairstringYesTrading pair. E.g. "BTC-USDC", "ETH-USDT".
initialDatestringYesStart date in ISO format: YYYY-MM-DD.
finalDatestringYesEnd date in ISO format: YYYY-MM-DD.

Supported asset pairs

Asset pairs correspond to pairs available on Coinbase. Current examples:

BTC-USDCETH-USDCETH-USDTSOL-USDCBTC-USDT

The full list of supported pairs matches the assets available in the Console. Date ranges must fall within the available historical data for the selected asset.

Submit response

FieldTypeDescription
idstring (UUID)Unique identifier for the backtest.
statusstring"Running" immediately after submission.
assetPairstringThe asset pair used.
initialDatestringStart date of the backtest period.
finalDatestringEnd date of the backtest period.
createdAtUtcstringTimestamp of creation in UTC.
canViewResultbooleanWhether the result is accessible (depends on credits).

#GET /backtest/:id — Fetch Results

GET/backtest/{id}

Fetch the status and results of a submitted backtest.

Query parameters

ParameterTypeDefaultDescription
includeTradesbooleanfalseWhen true, includes the full tradesDetail array in result.
💡
Omit includeTrades or set it to false when you only need aggregate metrics. The trade list can be large for long date ranges, so only request it when you need per-trade analysis.

Response fields

FieldTypeDescription
idstringUUID of the backtest.
statusstring"Running", "Completed", or "Failed".
strategySnapshotJsonstringThe strategy used, serialized.
assetPairstringAsset pair.
initialDate / finalDatestringDate range.
createdAtUtcstringCreation timestamp (UTC).
errorMessagestring | nullError details if status is "Failed".
canViewResultbooleanWhether the result is accessible.
logsJsonstring | nullExecution logs serialized as JSON string.
resultobject | nullFull performance metrics when Completed.

#Metrics Reference

When status is Completed, the result object contains:

Profitability metrics

FieldTypeDescription
pnlRnumberNet profit/loss in R-units. Sum of all trade PnLs.
grossProfitRnumberSum of all winning trades in R-units.
grossLossRnumberSum of all losing trades in R-units (negative).
profitFactornumbergrossProfitR / abs(grossLossR). >1 is profitable.
expectancyRnumberAverage expected R per trade. (winRate × avgWinR) + (lossRate × avgLossR).
avgWinRnumberAverage R on winning trades.
avgLossRnumberAverage R on losing trades (always -1.0 with fixed model).

Trade statistics

FieldTypeDescription
tradesnumberTotal number of trades executed.
winsnumberNumber of winning trades.
lossesnumberNumber of losing trades.
winRatenumberwins / trades. Range: 0–1.
bothHitnumberTrades where both SL and TP were hit in the same candle (resolved as SL).

Diagnostics

FieldTypeDescription
conditionsDistributionPctobjectFor each condition: fraction of candles where it was true.
scoreDistributionPctobjectFor each possible score value: fraction of candles with that score.
💡
The conditionsDistributionPct and scoreDistributionPct fields are key for strategy quality analysis. A condition that is almost always true adds no discriminating power. Use these to diagnose and refine your strategy structure.

Trade detail fields (with includeTrades=true)

FieldTypeDescription
numbernumberSequential trade number.
entryPricenumberPrice at which the trade was entered.
exitPricenumberPrice at which the trade was closed.
pnlRnumber+3.0 for a win, -1.0 for a loss (fixed model).
pnlPctnumberPercentage gain/loss on the trade.
totalScoreAtEntrynumberTotal score that triggered the entry.
conditionsAtEntryobjectWhich conditions were true at entry.
scoreBreakdownAtEntryobjectScore contributed by each condition at entry.

#Error Codes

StatusCodeDescription
400invalid_payloadThe request body is malformed or missing required fields.
400invalid_strategyThe strategySnapshotJson is invalid or references undefined variables.
400invalid_date_rangeThe date range is outside available historical data for the asset.
400unsupported_assetThe assetPair is not supported.
401unauthorizedMissing or invalid API key.
402insufficient_creditsNot enough credits to execute this backtest.
429rate_limitedToo many requests. Back off and retry.
500execution_failedServer-side execution error. Check errorMessage field.

When an error occurs at the execution level (after submission), the backtest status is set to Failed and the errorMessage field contains a description of what went wrong.