Documentation

Getting Started

Get your API key, make your first request, and receive your first backtest result in minutes.

Prerequisites

To use the EmidLabs Backtesting API you need:

  • An EmidLabs account — create one at the Console.
  • An API key generated from the Console.
  • Any HTTP client — curl, fetch, Python requests, or any language SDK.

#Authentication

All API requests must include your API key in the x-api-key header. There are no other authentication methods.

Authentication header
x-api-key: em_YOUR_API_KEY
Never expose your API key in client-side code, public repositories, or logs. Always use server-side code or environment variables to make API calls.

Generating an API key

1

Open the Console

Navigate to console.emidlabs.com and sign in to your account.
2

Go to API Keys

In the Console sidebar, select "API Keys" to access key management.
3

Create a key

Click "Generate New Key". Give it a descriptive name. The key is shown once — copy and store it securely.
4

Set an expiry (optional)

You can set an expiry date for the key for better security hygiene.

#Your First Backtest

A backtest is submitted as a POST request. The body includes the asset pair, date range, and a strategy definition as a nested JSON object.

Step 1 — Define the strategy

The strategy is a JSON object that describes what the engine should look for. Here is a simple EMA crossover with RSI confirmation:

strategy.json
{
  "configuration": {
    "timeframe": "1H"
  },
  "inputs": {
    "emaFast": "ema(close, 9)",
    "emaSlow": "ema(close, 21)",
    "rsiValue": "rsi(close, 14)"
  },
  "conditions": {
    "trendUp": "emaFast > emaSlow",
    "rsiHealthy": "rsiValue > 40 AND rsiValue < 65"
  },
  "score": {
    "trendUp": 20,
    "rsiHealthy": 30
  },
  "decision": {
    "entry": "score >= 40"
  }
}

Step 2 — Submit the request

The strategy is nested directly under the strategySnapshotJson field of the request body.

Submit backtest
curl -X POST \
  "https://backtest.emidlabs.com/api/public/v1/backtest" \
  -H "Content-Type: application/json" \
  -H "x-api-key: em_YOUR_API_KEY" \
  -d '{
  "assetPair": "BTC-USDC",
  "initialDate": "2023-01-01",
  "finalDate": "2023-12-31",
  "strategySnapshotJson": {
    "configuration": { "timeframe": "1H" },
    "inputs": { "emaFast": "ema(close, 9)", "emaSlow": "ema(close, 21)", "rsiValue": "rsi(close, 14)" },
    "conditions": { "trendUp": "emaFast > emaSlow", "rsiHealthy": "rsiValue > 40 AND rsiValue < 65" },
    "score": { "trendUp": 20, "rsiHealthy": 30 },
    "decision": { "entry": "score >= 40" }
  }
}'
The API returns immediately with a backtest ID and status: "Running". Execution typically completes within 200–500ms for most date ranges.

Step 3 — Fetch the results

Use the returned id to fetch results via a GET request. Add includeTrades=true to receive individual trade details.

Fetch results
curl -X GET \
  "https://backtest.emidlabs.com/api/public/v1/backtest/YOUR_BACKTEST_ID?includeTrades=true" \
  -H "x-api-key: em_YOUR_API_KEY"

#Reading Results

When status is Completed, theresult object contains all performance metrics.

Key metrics

tradesTotal number of trades executed.
winRatePercentage of winning trades (0–1).
expectancyRAverage expected R per trade. Positive is profitable.
pnlRTotal profit/loss in R-units across all trades.
profitFactorGross profit divided by gross loss. >1 is profitable.
maxDrawdownPctLargest peak-to-trough drawdown as a percentage.
conditionsDistributionPctHow often each condition was true per candle.
scoreDistributionPctDistribution of total score values across all candles.

R-units explained

All profit/loss values are in R-units, not currency amounts. By default, 1R = 1% of your position (the default stop-loss distance) — configurable per strategy viariskManagement. A result of +10R means the strategy would have returned 10× the risked amount per trade, in aggregate.

This makes results comparable across strategies and assets regardless of position size, and forces focus on the statistical edge rather than dollar amounts.