API documentation
v1 · production · sub-2s per backtest · 5 statistical gates returned with every call.
Overview
Arctick exposes its 5-gate backtest engine as a JSON HTTP API. POST a strategy in our DSL, get a deterministic verdict back in 1–3 seconds.
The engine is the same one running the public playground at arctick.xyz. Same gates, same data, same code path · just programmatic.
https://arctick.xyz/api/v1
Authentication
Every request requires a Bearer token in the Authorization header.
Authorization: Bearer hf_pro_xxxxxxxxxxxxxxxx
For zero-setup testing, use the public demo key (Free-tier limits apply):
Authorization: Bearer hf_free_demo_kqx7gp2pz4
POST /backtest
Run a single backtest of one DSL strategy on BTC 1h Hyperliquid data, returns all 5 gates.
POST https://arctick.xyz/api/v1/backtest
Request body
| Field | Type | Required | Description |
|---|---|---|---|
dsl | string | yes | Strategy in Arctick DSL (see DSL grammar) |
lookback_days | int | no | Limit backtest to last N days. Default: all available (~730d) |
starting_equity | float | no | Position size in USD. Default: 1000 |
Example
{
"dsl": "LONG WHEN RSI(14) < 30\nTAKE_PROFIT 2%\nSTOP_LOSS 1%",
"lookback_days": 365,
"starting_equity": 1000
}
Response schema
Returns the full 5-gate verdict plus a _billing object with your current usage.
{
"verdict": "PASS", // or "FAIL"
"strategy_label": "Custom strategy (DSL)",
"elapsed_sec": 1.62,
"n_trials": 27, // auto-generated DSR/PBO trial count
"data_range": { "start": ..., "end": ..., "n_bars": 17521, "days": 730 },
"gates": {
"quality": { "passes": true, "data": { "sharpe": ..., "sortino": ..., "calmar": ..., "max_dd_pct": ..., "max_dd_usd": ..., "total_return_pct": ..., "pnl_usd": ..., "win_rate": ..., "n_trades": ..., "ev_per_trade_pct": ..., "starting_equity": ... }},
"dsr": { "passes": ..., "data": { "sr_obs": ..., "e_max_sr": ..., "dsr_prob": ..., "passes_95": ... }},
"pbo": { "passes": ..., "data": { "pbo": ..., "n_splits": ..., "median_omega": ... }},
"wfa": { "passes": ..., "data": { "pct_positive": ..., "mean_oos_sharpe": ..., "n_windows": ... }, "windows_preview": [...] },
"leak_audit": { "passes": ..., "data": { "headline_sharpe": ..., "shifted_sharpe": ..., "ratio": ... }}
},
"equity": { "x": [...], "y": [...] }, // equity curve, ≤400 pts
"_billing": { "tier": "pro", "calls_this_month": 12, "monthly_cap": 5000 }
}
Error codes
| HTTP | code | Meaning |
|---|---|---|
| 400 | missing_dsl | The dsl field is empty or absent |
| 400 | parse_error | DSL didn't parse (see parse_error in body) |
| 401 | missing_auth | No Authorization header |
| 401 | invalid_key | Key not recognized or revoked |
| 402 | quota_exceeded | Monthly quota reached · upgrade tier |
| 429 | rate_limit | Per-window rate limit hit. retry_after in body |
| 500 | engine_error | Backtest engine failed (rare, report it) |
Code examples
curl -X POST https://arctick.xyz/api/v1/backtest \ -H "Authorization: Bearer hf_free_demo_kqx7gp2pz4" \ -H "Content-Type: application/json" \ -d '{ "dsl": "LONG WHEN RSI(14) < 30\nTAKE_PROFIT 2%\nSTOP_LOSS 1%", "lookback_days": 365 }' | jq .verdict,.gates.quality.data.sharpe
DSL grammar (quick reference)
Each rule on its own line. At least one LONG or SHORT required.
// Rules LONG WHEN <condition> SHORT WHEN <condition> EXIT WHEN <condition> TAKE_PROFIT 2% STOP_LOSS 1% // Indicators SMA(n) EMA(n) RSI(n) ATR(n) VOL_SMA(n) BB_UPPER(n, k) BB_LOWER(n, k) VWAP(n) VWAP_UPPER(n, k) VWAP_LOWER(n, k) MACD(fast, slow, signal) CVD(n) FUNDING_RATE(n) OPEN_INTEREST(n) // Columns close open high low volume // Operators < > <= >= crosses_above(a, b) crosses_below(a, b) // Arithmetic + - * / // e.g. close - SMA(50) > 0 // Logic AND OR
Full grammar + worked examples in the playground.
Rate limits & quotas by tier
| Tier | Price | Calls / month | Rate limit |
|---|---|---|---|
Free |
$0 | 50 | 5 / 3600s |
Pro |
$49 / mo | 5,000 | 60 / 60s |
Team |
$499 / mo | 50,000 | 600 / 60s |
Enterprise |
custom | unlimited | negotiated |
When a rate-limit response (HTTP 429) is returned, the body includes retry_after in seconds. Standard backoff: wait, then retry.