Create Backtest Job
Submit a new backtest job. Returns the freshly created job object with status queued; the backtest runs asynchronously.
Endpoint
POST /v1/backtest/jobs
Weight: 20
Authentication: Required (signed)
Request body
| Name | Type | Mandatory | Description |
|---|---|---|---|
template_id | string | Yes | Identifier of the strategy template (e.g. tpl_grid). See the Strategies overview for the catalog. |
params | object | Yes | Template-specific parameters. Schema is opaque to the backtest service and validated by the template. |
symbols | array<string> | Yes | Uppercase exchange-style symbols (e.g. ["BTCUSDT"]). Multi-symbol backtests are supported by templates that opt-in. |
timeframe | enum | Yes | Bar interval. One of 1m, 5m, 15m, 1h, 4h, 1d. |
start | string (ISO 8601 UTC) | Yes | Inclusive lower bound of the simulation window. |
end | string (ISO 8601 UTC) | Yes | Inclusive upper bound. Must be > start; total span ≤ 5 years. |
capital | string (decimal) | Yes | Starting account equity in quote currency. Quoted to preserve precision. |
leverage | integer | No | Maximum leverage applied to positions. Default 1. |
fee_model | enum | No | One of none, fixed_bps, tiered_maker_taker, match_exchange. Default fixed_bps. See Overview → Fee model. |
fee_bps | string (decimal) | No | Per-fill fee in basis points. Only honored when fee_model = "fixed_bps". Default "5". |
strategy_id | string | No | If set, the corresponding strategy's stored config is loaded as a base; any of the fields above that are also passed in the request override the strategy's values. Useful for re-running an existing strategy over a custom window. |
Response
{
"id": "bt_3c91ef",
"status": "queued",
"config": {
"template_id": "tpl_grid",
"params": {
"grid_levels": 8,
"upper_price": "72000",
"lower_price": "60000"
},
"symbols": ["BTCUSDT"],
"timeframe": "1h",
"start": "2025-01-01T00:00:00Z",
"end": "2025-12-31T23:59:59Z",
"capital": "10000.00",
"leverage": 1,
"fee_model": "fixed_bps",
"fee_bps": "5"
},
"submitted_at": "2026-04-29T10:15:00Z",
"started_at": null,
"finished_at": null,
"progress": 0,
"result": null,
"error": null
}
Response fields
| Field | Type | Description |
|---|---|---|
id | string | Job identifier of the form bt_<6-8 hex>. |
status | enum | One of queued, running, done, failed, cancelled. New jobs return queued. |
config | object | Echoes the resolved configuration the backtest will run with. If strategy_id was supplied, this reflects the merged config. |
submitted_at | string (ISO 8601) | Server-side acceptance timestamp. |
started_at | string (ISO 8601) | null | Set when the job leaves the queue. null while queued. |
finished_at | string (ISO 8601) | null | Set when the job reaches a terminal state. |
progress | number | Fractional progress in [0, 1]. 0 for newly queued jobs. |
result | object | null | null until status is done; see Get Result. |
error | object | null | null unless status is failed; contains { "code", "message" }. |
Errors
| HTTP | Code | Cause |
|---|---|---|
| 400 | INVALID_PARAMETER | Missing field, unknown template_id, invalid date range (e.g. end <= start, span > 5 years, end in the future), unsupported timeframe, or non-numeric capital. |
| 409 | INVALID_STATE | strategy_id references a deleted or otherwise unusable strategy. |
| 429 | RATE_LIMITED | The user already has 5 jobs in queued or running state. Wait for one to finish or cancel one first. |
See Errors for shared error semantics.
Example
curl -X POST https://api.pipai.example/v1/backtest/jobs \
-H "X-PipAI-API-Key: $API_KEY" \
-H "X-PipAI-Timestamp: $TS" \
-H "X-PipAI-Signature: $SIG" \
-H "Content-Type: application/json" \
-d '{
"template_id": "tpl_grid",
"params": {
"grid_levels": 8,
"upper_price": "72000",
"lower_price": "60000"
},
"symbols": ["BTCUSDT"],
"timeframe": "1h",
"start": "2025-01-01T00:00:00Z",
"end": "2025-12-31T23:59:59Z",
"capital": "10000.00",
"leverage": 1,
"fee_model": "fixed_bps",
"fee_bps": "5"
}'