Getting started
Run backtests programmatically with the Open Backtest API.
The Open Backtest API lets you fetch market candles, create backtest
sessions, push trades and read computed statistics — everything you see in
the app, scriptable. Sessions created through the API show up in your
workspace like any other, tagged api/sdk.
Authentication
The API is part of the Pro plan. Create a key in
Settings → API in the app — the full key (obk_…) is shown exactly
once. Pass it on every request in the x-api-key header:
curl https://api.openbacktest.fefe-du-973.fr/api/v1/me \
-H "x-api-key: obk_your_key_here"Base URL for this deployment: https://api.openbacktest.fefe-du-973.fr/api/v1. It is resolved from the
deployment environment, so local and production documentation stay aligned.
Errors and rate limits
Every non-2xx response uses one envelope:
{ "error": { "code": "NOT_FOUND", "message": "Session not found" } }Codes: UNAUTHORIZED, PRO_REQUIRED, RATE_LIMITED, NOT_FOUND,
UNKNOWN_SYMBOL, SESSION_NOT_ACTIVE, VALIDATION_ERROR,
MARKET_DATA_UNAVAILABLE, INTERNAL.
Keys are limited to 1000 requests/hour (HTTP 429 with a Retry-After
header beyond that). Candle requests draw from an additional per-user
budget shared with the app — one upstream quota per account.
A complete run in curl
BASE=https://api.openbacktest.fefe-du-973.fr/api/v1
KEY=obk_your_key_here
# 1. Who am I?
curl -s $BASE/me -H "x-api-key: $KEY"
# 2. Create a project
PROJECT=$(curl -s -X POST $BASE/projects -H "x-api-key: $KEY" \
-H "Content-Type: application/json" \
-d '{"name":"My strategy","symbol":"BTCUSDT","timeframe":"1h"}')
PROJECT_ID=$(echo "$PROJECT" | jq -r .project.id)
# 3. Open a session (fees in percent per side)
SESSION_PAYLOAD=$(jq -nc \
--arg projectId "$PROJECT_ID" \
--arg name "Run 1" \
'{projectId:$projectId,name:$name,initialBalance:10000,
feesConfig:{entryFee:0.1,exitFee:0.1,type:"percent"}}')
SESSION=$(curl -s -X POST $BASE/sessions -H "x-api-key: $KEY" \
-H "Content-Type: application/json" \
-d "$SESSION_PAYLOAD")
SID=$(echo $SESSION | jq -r .session.id)
# 4. Push closed trades (batches of up to 500)
curl -s -X POST $BASE/sessions/$SID/trades -H "x-api-key: $KEY" \
-H "Content-Type: application/json" \
-d '{"trades":[{"clientId":"strategy-run-42-trade-1",
"side":"long","qty":0.1,"entryPrice":60000,
"entryTime":1751000000000,"exitPrice":61000,"exitTime":1751003600000}]}'
# 5. Finish and read the stats
curl -s -X POST $BASE/sessions/$SID/finish -H "x-api-key: $KEY" | jq .statsAll dates are millisecond epochs. Trades are ingested closed (entry + exit in one record) — metrics (fees, P&L, R-multiple) are computed server-side and frozen at ingest.
Prefer Python? The SDK wraps this whole lifecycle in a few lines, with candles as pandas DataFrames.