Your First Backtest (CLI)
Run a backtest end-to-end from the terminal in under 10 minutes — install, authenticate, create, validate, upload, run, fetch results.
Your First Backtest (CLI)
End-to-end walkthrough using only the terminal. Every step shows the actual JSON output and pipes the relevant ID into the next command. By the end you'll have a strategy on the platform, a running backtest, and metrics back in your shell.
See the finished thing first: Verified Keel backtest of a funding-carry strategy — Sharpe 2.17, +79.6% return, -9.7% max drawdown.
Prerequisites
- Python 3.11+
- A free Keel account (sign up)
jqfor piping JSON between commands (optional but recommended)
1. Install
pipx install keel-trade # or: uv tool install keel-trade
keel --version
# keel, version 0.4.02. Authenticate
keel auth loginThis opens your default browser, runs OAuth 2.1 + PKCE against
app.usekeel.io, and captures the redirect on a temporary local
listener. Tokens go to ~/.keel/config.yaml; refresh fires
transparently every hour.
For CI / SSH / Codespaces / WSL where CLI and browser aren't on the same machine:
keel auth login --key <token>
# Get a token at https://app.usekeel.io/settings?tab=api-keysVerify:
keel auth whoami
# {"principal_id": "...", "org_id": "...", "plan": "..."}3. Create a Strategy from a Template
keel strategy new my_carry --template carry
# Wrote ~/.keel/strategies/my_carry/strategy.pyOpen ~/.keel/strategies/my_carry/strategy.py — that's the Keel DSL. It's a funding-carry pipeline: load price + funding, negate the funding sign so the forecast points to the receiving side, vol-standardize, scale, cap, normalize to weights.
4. Validate Locally (No API Call)
keel strategy validate ~/.keel/strategies/my_carry/strategy.pyYou'll see "valid": true plus the type flow at each step. Validation runs entirely in-process — no auth needed.
To assess whether the pipeline is ready to backtest:
keel strategy stage ~/.keel/strategies/my_carry/strategy.py
# {"stage": "sized", "backtest_ready": true, ...}5. Resolve the Universe
The template ships with resolved=[] — the platform doesn't know which symbols to trade yet. Pick the top 30 by volume:
keel universe set ~/.keel/strategies/my_carry/strategy.py \
--mode top_volume --top-n 30(keel universe resolve --mode top_volume --top-n 30 shows you the symbol list without writing it back if you want to preview first.)
6. Upload to the Platform, Capture the ID
STRATEGY_ID=$(keel strategy create ~/.keel/strategies/my_carry/strategy.py \
--format json | jq -r '.strategy_id')
echo "$STRATEGY_ID"
# str_01HX...--format json is forced here so jq can parse it. In agent mode (Claude Code, Cursor, etc.) JSON is already the default.
7. Start a Backtest
BT_ID=$(keel backtest run "$STRATEGY_ID" \
--start-date 2025-06-01 --end-date 2026-02-01 \
--format json | jq -r '.backtest_id')
echo "$BT_ID"
# bt_01HX...8. Poll Until It's Done
keel backtest status "$BT_ID"
# {"status": "RUNNING", ...} # check again in a minute
# {"status": "SUCCEEDED", ...} # readyOr loop:
until [ "$(keel backtest status "$BT_ID" --format json | jq -r .status)" = "SUCCEEDED" ]; do
sleep 15
done9. Read the Results
keel backtest results "$BT_ID" --format json | jq '.metrics'
# {
# "sharpe_ratio": 1.42,
# "total_return_pct": 31.5,
# "max_drawdown_pct": -8.1,
# "win_rate_pct": 53.2,
# "total_trades": 412
# }That's the same shape you see on the app's backtest page. To open the rich view, head to app.usekeel.io and find my_carry in your strategies list.
What's Next?
- Iterate: edit
~/.keel/strategies/my_carry/strategy.py, then re-run from step 4. To push edits back to the platform:keel strategy checkout "$STRATEGY_ID"thenkeel strategy push -m "Tweak vol target". - Deploy live: see the CLI reference for
keel live deploy. Requires an authorized Hyperliquid account (keel accounts list). - Agent setup: wire the CLI + MCP server into Claude Code, Cursor, or your own agent via the agent setup guide.