Arctick/ API docs

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.

Base URL
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

Request a Pro or Team key →

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

FieldTypeRequiredDescription
dslstringyesStrategy in Arctick DSL (see DSL grammar)
lookback_daysintnoLimit backtest to last N days. Default: all available (~730d)
starting_equityfloatnoPosition 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

HTTPcodeMeaning
400missing_dslThe dsl field is empty or absent
400parse_errorDSL didn't parse (see parse_error in body)
401missing_authNo Authorization header
401invalid_keyKey not recognized or revoked
402quota_exceededMonthly quota reached · upgrade tier
429rate_limitPer-window rate limit hit. retry_after in body
500engine_errorBacktest 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
import requests

resp = requests.post(
    "https://arctick.xyz/api/v1/backtest",
    headers={"Authorization": "Bearer hf_free_demo_kqx7gp2pz4"},
    json={
        "dsl": "LONG WHEN RSI(14) < 30\nTAKE_PROFIT 2%\nSTOP_LOSS 1%",
        "lookback_days": 365,
    },
)
data = resp.json()
print(data["verdict"], data["gates"]["quality"]["data"]["sharpe"])
const resp = await fetch("https://arctick.xyz/api/v1/backtest", {
  method: "POST",
  headers: {
    "Authorization": "Bearer hf_free_demo_kqx7gp2pz4",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    dsl: "LONG WHEN RSI(14) < 30\nTAKE_PROFIT 2%\nSTOP_LOSS 1%",
    lookback_days: 365,
  }),
});
const data = await resp.json();
console.log(data.verdict, data.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

TierPriceCalls / monthRate 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.