Backtesting API

The Backtesting API runs historical strategy testing with performance metrics and trade-by-trade analysis.

Endpoints

MethodEndpointDescription
POST/api/v1/backtestsRun a new backtest
POST/api/v1/backtests/bulkRun backtests for multiple strategies
GET/api/v1/backtests/{id}Retrieve a historical backtest result
GET/api/v1/backtests/{id}/tradesRetrieve a run’s trade history
POST/api/v1/backtests/{id}/archiveArchive a run (hide from the default view)
POST/api/v1/backtests/{id}/unarchiveUnarchive a run (restore to the default view)
Backtests are never deleted. A backtest is an immutable historical record; there is no delete endpoint. To remove a run from your default history view, use POST /api/v1/backtests/{id}/archive (reversible via unarchive). See Archive a backtest.
Path. /api/v1/backtests is the canonical path (mirroring the async /api/v2/backtests/). The older /api/v1/backtesting/backtest* paths still work as a deprecated alias and dispatch to the identical handlers, but new integrations should use /api/v1/backtests.

Run a Backtest

POST /api/v1/backtests Runs a synchronous backtest and returns metrics and trade history. Loads market data from CoinAPI for the specified asset and date range.
One backtest at a time. The engine processes a single synchronous backtest per worker. If another backtest is already running, this endpoint returns 503 Service Unavailable with a Retry-After header instead of blocking until the gateway times out (504). Honor Retry-After and retry, run requests sequentially, or use the bulk endpoint to evaluate many strategies in one request. See the Running a Backtest guide.

Date Range Modes

ModeParametersBehavior
Explicit Rangestart_date + end_dateExact date window
From Date to Nowstart_date onlyStart date to current time
Lookback from Endend_date + lookback_monthsN months back from end date
Recent Historylookback_months onlyN months from current time

Example: Historical Lookback

curl -X POST https://api.mangrovedeveloper.ai/api/v1/backtests \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "asset": "ETH",
    "interval": "1h",
    "lookback_months": 12,
    "initial_balance": 10000.0,
    "min_balance_threshold": 0.1,
    "min_trade_amount": 25.0,
    "max_open_positions": 5,
    "max_trades_per_day": 50,
    "max_risk_per_trade": 0.01,
    "max_units_per_trade": 100.0,
    "max_trade_amount": 10000.0,
    "volatility_window": 24,
    "target_volatility": 0.02,
    "volatility_mode": "stddev",
    "enable_volatility_adjustment": false,
    "cooldown_config": {
      "1h": {"short_loss_limit": 4, "long_loss_limit": 6, "short_window_bars": 48, "long_window_bars": 144}
    },
    "strategy_json": "{\"name\": \"ETH Strategy\", \"asset\": \"ETH\", \"entry\": [{\"name\": \"macd_bullish_cross\", \"timeframe\": \"1h\", \"signal_type\": \"TRIGGER\", \"params\": {\"window_fast\": 12, \"window_slow\": 26, \"window_sign\": 9}}, {\"name\": \"is_above_sma\", \"timeframe\": \"1h\", \"params\": {\"window\": 50}, \"signal_type\": \"FILTER\"}], \"exit\": []}"
  }'

Response

{
  "success": true,
  "metrics": {
    "sharpe_ratio": 1.23,
    "sortino_ratio": 1.10,
    "calmar_ratio": 0.80,
    "irr_annualized": 0.25,
    "max_drawdown": 0.15,
    "max_drawdown_duration": 42,
    "win_rate": 0.55
  },
  "execution_time_seconds": 3.21,
  "trade_count": 12
}

Required Parameters

ParameterTypeDescription
assetstringAsset symbol (e.g., “BTC”, “ETH”). Optional when strategy_id is supplied (defaults from the saved strategy).
intervalstringTime interval (“1h”, “4h”, “1d”)
initial_balancenumberStarting account balance
strategy_jsonstringStringified JSON strategy configuration. Provide this or strategy_id.

Strategy Source: strategy_json or strategy_id

Provide exactly one of:
  • strategy_json (string) — the stringified strategy configuration shown below.
  • strategy_id (string) — the UUID of a strategy you already created. The API loads its definition and defaults asset and execution_config from the saved strategy when you omit them.
Sending both returns 400; an unknown or inaccessible strategy_id returns 404. The same strategy_id option is accepted by the async endpoint POST /api/v2/backtests/.
{
  "strategy_id": "550e8400-e29b-41d4-a716-446655440000",
  "interval": "1h",
  "lookback_months": 12,
  "initial_balance": 10000.0
}

Strategy JSON Format

Entry rules require exactly 1 TRIGGER + 1 FILTER signal:
{
  "name": "Strategy Name",
  "asset": "BTC",
  "entry": [
    {"name": "signal_name", "timeframe": "1h", "signal_type": "TRIGGER", "params": {}},
    {"name": "signal_name", "timeframe": "1h", "signal_type": "FILTER", "params": {}}
  ],
  "exit": []
}
Do NOT include atr_period or atr_multiplier in strategy_json. These belong in execution_config and are injected at runtime.

Retrieve Backtest Result

GET /api/v1/backtests/{backtest_id} Retrieves a previously executed backtest including full trade history.
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.mangrovedeveloper.ai/api/v1/backtests/550e8400-e29b-41d4-a716-446655440000"

Archive a Backtest

Backtests are immutable and cannot be deleted. Archiving a run hides it from your default history view; it remains stored and can be restored at any time. POST /api/v1/backtests/{backtest_id}/archive POST /api/v1/backtests/{backtest_id}/unarchive
# Archive (hide from the default view)
curl -X POST -H "Authorization: Bearer $TOKEN" \
  "https://api.mangrovedeveloper.ai/api/v1/backtests/550e8400-e29b-41d4-a716-446655440000/archive"

# Unarchive (restore)
curl -X POST -H "Authorization: Bearer $TOKEN" \
  "https://api.mangrovedeveloper.ai/api/v1/backtests/550e8400-e29b-41d4-a716-446655440000/unarchive"
{ "success": true, "backtest_id": "550e8400-e29b-41d4-a716-446655440000", "archived": true }
Archiving only affects a backtest you own; an unknown or inaccessible id returns 404.

Listing archived runs

Your backtest history (GET /api/v1/users/me/backtests) excludes archived runs by default. Pass include_archived=true to include them; each item carries an archived boolean and an archived_at timestamp (null when active).
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.mangrovedeveloper.ai/api/v1/users/me/backtests?include_archived=true"

Bulk Backtest

POST /api/v1/backtests/bulk Evaluates multiple strategies over a shared date range. Market data is fetched once per unique (asset, timeframe) pair. Provide either strategy_ids (UUIDs from database) or strategy_configs (inline strategy objects).
curl -X POST https://api.mangrovedeveloper.ai/api/v1/backtests/bulk \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "strategy_ids": ["id-1", "id-2", "id-3"],
    "start_date": "2024-01-01",
    "end_date": "2024-12-31",
    "initial_balance": 10000.0,
    "min_balance_threshold": 0.1,
    "min_trade_amount": 25.0,
    "max_open_positions": 5,
    "max_trades_per_day": 50,
    "max_risk_per_trade": 0.01,
    "max_units_per_trade": 100.0,
    "max_trade_amount": 10000.0,
    "volatility_window": 24,
    "target_volatility": 0.02,
    "volatility_mode": "stddev",
    "enable_volatility_adjustment": false,
    "cooldown_config": {
      "1h": {"short_loss_limit": 4, "long_loss_limit": 6, "short_window_bars": 48, "long_window_bars": 144}
    }
  }'
Individual strategy failures are captured per-result without aborting the batch. The data_fetches field shows how many unique API calls were made.

Cooldown Parameters

Pass cooldown_config as a top-level key in the backtest request body to control loss-streak limits and cooldown durations. The engine selects the entry keyed to the interval value of the request.
"cooldown_config": {
  "5m":  {"short_loss_limit": 4, "long_loss_limit": 6, "short_window_bars": 180, "long_window_bars": 480},
  "15m": {"short_loss_limit": 4, "long_loss_limit": 6, "short_window_bars": 120, "long_window_bars": 320},
  "1h":  {"short_loss_limit": 4, "long_loss_limit": 6, "short_window_bars": 48,  "long_window_bars": 144},
  "1d":  {"short_loss_limit": 4, "long_loss_limit": 6, "short_window_bars": 20,  "long_window_bars": 60}
}
KeyDescription
short_loss_limitLosses in short_window_bars that trip the short-tier cooldown
long_loss_limitLosses in long_window_bars that trip the long-tier cooldown
short_window_barsRolling lookback AND cooldown duration (bars) for the short tier
long_window_barsRolling lookback AND cooldown duration (bars) for the long tier
Max hold time is controlled by execution_config.max_hold_bars, not by cooldown_config.
Deprecated parameters: cooldown_bars, daily_momentum_limit, and weekly_momentum_limit are deprecated flat keys, kept for backward compatibility. They are optional — omit them and they default from trading_defaults.json (24, 3, 3). You no longer need to supply them to call the backtest endpoints, so the examples above leave them out. Continue migrating any explicit cooldown tuning to cooldown_config before the next major version.
See the Risk Management guide for full cooldown tuning details.