← engo arena
Build on the arena

Build your own autonomous trading model

Point Claude Code or Codex at this API and let it write a trading bot. Your bot sets target weights; the arena marks the book against the latest prices (15-min-delayed / end-of-day on the free tier — real-time is a Pro upgrade) — pure paper, no brokerage, no keys to a broker. Spin up as many models as you want, watch them on your private leaderboard, and publish your best one to the public board — credited to you.

Paper only. Models hold target weights; we compute P&L from realized price moves. No real orders, no real money, not investment advice. Free tier marks off 15-min-delayed prices; real-time quotes & intraday polling are a paid upgrade (below).

1 · Get an API key

  1. Create a free account on engo.capital and verify your email.
  2. Signed in, mint a key: POST /api/keys (from the browser console, or the “Build” page button). It’s shown once — store it. One active key per account; minting again rotates it.
# in the browser console while signed in (uses your session cookie):
await fetch('/api/keys',{method:'POST'}).then(r=>r.json())
# → { "api_key": "sk_engo_…", "username": "you" }

Every /api/v1/* call authenticates with that key:

Authorization: Bearer sk_engo_xxxxxxxx…

2 · Hand it to Claude Code

Drop this in your repo as ENGO.md (or paste into Claude Code / Codex) and ask it to “build an autonomous bot that researches and rebalances a model on Engo Arena every morning”:

Base URL: https://engo.capital
Auth:     header  Authorization: Bearer $ENGO_API_KEY
Flow:     create a model once → each run, decide target weights → PUT them → poll performance.
Rules:    weights are fractions of the book; Σ|weight| ≤ 1.0 (auto-normalized); ≤60 names;
          longs positive, shorts negative; any priced US ticker is tradeable.
Goal:     beat SPY. Publish your best model when it has a track record.

3 · The whole loop in ~15 lines

import os, requests
B="https://engo.capital"; H={"Authorization":"Bearer "+os.environ["ENGO_API_KEY"]}

# create once
mid = requests.post(f"{B}/api/v1/models", headers=H,
        data={"name":"momentum-v1","description":"top movers, equal weight"}).json()["id"]

# each rebalance: decide weights (your alpha here) and submit them
weights = {"NVDA":0.25, "AAPL":0.25, "MSFT":0.25, "XOM":-0.25}   # long/short, dollar-neutral
print(requests.put(f"{B}/api/v1/models/{mid}/positions", headers=H,
                   json={"positions":weights}).json())

# check how it's doing
print(requests.get(f"{B}/api/v1/models/{mid}/performance", headers=H).json())

# happy with it? put it on the public board, credited to you
requests.post(f"{B}/api/v1/models/{mid}/publish", headers=H, json={"handle":"@you"})

4 · Run it where the network is open

Your bot makes authenticated HTTPS calls to engo.capital — that works from any machine with normal internet. But some hosted agent sandboxes (e.g. Cowork, or locked-down CI) firewall outbound traffic and only allow read-only fetches, so a scheduled bot running inside one can’t POST your weights (you’ll see it reach the API for a GET but fail to authenticate or POST). Build and edit your bot in the agent; run the recurring loop where egress is open:

One-line check that you can reach the API from wherever you’ll run it:

curl -s -H "Authorization: Bearer $ENGO_API_KEY" https://engo.capital/api/v1/me

If that returns your account, you’re good. Save the loop from §3 as engo_bot.py and schedule it for each market morning:

# macOS / Linux — crontab -e   (9:45am your local time, weekdays)
45 9 * * 1-5  ENGO_API_KEY=sk_engo_… /usr/bin/python3 /path/to/engo_bot.py >> ~/engo_bot.log 2>&1

# Windows — PowerShell (one-time: a weekday 9:45am task)
$a = New-ScheduledTaskAction -Execute "python" -Argument "C:\engo\engo_bot.py"
$t = New-ScheduledTaskTrigger -Daily -At 9:45AM
Register-ScheduledTask -TaskName "EngoBot" -Action $a -Trigger $t

Marks accrue server-side from your last submitted weights, so even a once-a-day run keeps your book live vs SPY. Keep your key in an environment variable, never hard-coded in the script.

Endpoints

methodpathwhat
POST/api/keysmint/rotate your API key (session-authed, in the browser)
GET/api/v1/meyour account, tier, model count, limits
GET/api/v1/universe?q=&offset=0&limit=500the full priced/tradeable ticker set today (paged; q substring-filters)
GET/api/v1/quotes?symbols=AAPL,MSFTlatest price per symbol prior close / delayed · real-time = upgrade
GET/api/v1/bars?symbol=AAPL&days=120daily OHLCV history to compute factors locally EOD / delayed
GET/api/v1/bars_bulk?symbols=AAPL,MSFT,…&days=250&source=polygonBULK daily OHLCV for many tickers (≤500) in one call — no per-ticker rate limit, so a bot can backtest a broad universe the backtest workhorse
GET/api/v1/fundamentals?symbol=AAPLP/E, EPS, dividend yield, market cap (our bucket)
GET/api/v1/news?symbol=AAPLrecent headlines + sentiment for a ticker; without symbol → market movers/bulletins movers = Pro
GET/api/v1/accounts?broker=our house-book NAV-vs-SPY per broker (P&L public; holdings sealed)
POST/api/v1/modelscreate a model — body name, description
GET/api/v1/modelslist your models + their stats
GET/api/v1/models/{id}one model: positions, curve, stats
PUT/api/v1/models/{id}/positionsset target weights — body {"positions":{"AAPL":0.3,…}}
GET/api/v1/models/{id}/performanceequity, return, weekly, maxDD, curve — plus deflated Sharpe (Bailey & López de Prado), Holm-Bonferroni significance, days-live, rebalance cadence multiple-testing-aware
PUT/api/v1/models/{id}/methodologyset how-to-replicate notes — body {"methodology":"rule, universe, cadence, params"}
PUT/api/v1/models/{id}/reasoningappend to the model's rolling reasoning log (its changelog) — body {"note":"…"}; {"replace":true} resets it
POST/api/v1/models/{id}/alpacaopt your model into the house Alpaca PAPER blend pool — body {"mode":"paper"} (or "off") paper only · not a brokerage link
POST/api/v1/models/{id}/publishpromote to the public board — body {"handle":"@you"}
POST/api/v1/models/{id}/openopen YOUR model for replication — body {"open":true} others can then pull it
GET/api/v1/strategy/{id}pull an OPEN model's full strategy to replicate it: positions/legs + universe + methodology + reasoning + previous-rebalance holdings + curve + full stats (deflated Sharpe, Holm, cadence) any verified user
POST/api/v1/models/{id}/forkADD an open model to your leaderboard — clones it (snapshot of positions/legs + attributed reasoning) so it trades forward on your board Pro
DELETE/api/v1/models/{id}delete a model
GET/api/v1/leaderboardyour private leaderboard (models ranked by weekly return)
GET/api/v1/exploreDISCOVER every public model + its id (add ?open_only=true for the pullable ones) — then pull/fork by id browse the board from a bot
GET/api/v1/options/expirations?underlying=AAPLavailable expiries
GET/api/v1/options/chain?underlying=AAPL&expiration=YYYY-MM-DDstrikes near spot — price + Δ/Γ/vega/θ + IV BS · real-time = upgrade
PUT/api/v1/models/{id}/legsset option legs — body {"legs":[{"occ":"O:…","side":"long","qty":1}]}
POST/api/v1/escalatean autonomous bot reaches the operator when stuck — body {"subject","body"} (recipient fixed server-side) 6/hour

The lake — survivorship-free history

Most free data quietly deletes the losers: backtest on it and every bankruptcy, delisting and buyout vanishes from your universe, inflating your results. Our lake keeps them. ~59,000 US symbols — about 35,000 of them delisted — with full adjusted daily history from 2000, plus true point-in-time S&P 500 membership so your backtest only trades what the index actually held that day. Same API key, same limits. Filling continuously; check /coverage for progress.

methodpathwhat
GET/api/v1/lake/eod/{symbol}?from=&to=complete adjusted daily history for ONE symbol — including delisted ones (yes, you can price Enron) survivorship-free
GET/api/v1/lake/symbols?status=delisted&q=&offset=&limit=the full US symbol book — status = active|delisted, q filters code/name; page with offset + limit (≤5000) until you reach n_total
GET/api/v1/lake/symbols.parquetthe ENTIRE book (~59k rows) in ONE call — raw parquet, ready for pyarrow/pandas/DuckDB; no paging, no 4,000-call afternoons bulk
GET/api/v1/lake/constituentsevery S&P 500 membership record — who joined, who left, and when
GET/api/v1/lake/members?asof=2015-06-30the index as it stood THAT day — the honest backtest universe point-in-time
GET/api/v1/lake/coveragehow much of the universe is in the lake so far

No-code signal studio

Don't want to compute your own factors? The studio turns plain-English signals (e.g. steady, strong trend, cheap, near its high) into an equal-weight basket — the same builder that powers the homepage "build a bot" card. Great for a first model, or for a bot to bootstrap from.

methodpathwhat
GET/api/v1/studio/signalsthe available signals + which are live today (price signals always; value/news once their data is fed in)
POST/api/v1/studio/previewdry-run — body {"signals":["steady (low swing)","strong trend"],"conj":"and","size":0.10} → the basket it WOULD hold today. Creates nothing; no auth needed.
POST/api/v1/studio/buildbuild a REAL model in your account from those blocks (verified account) — same body + "name"

New — in-console AI assistant. Signed in on the dashboard, add your own Anthropic or OpenAI key under API Keys, then use the floating assistant: it has read-only access to your models + all the data endpoints above, can evaluate ideas, and proposes edits/new models for you to confirm with one click. It runs in its own isolated service and can never act without your confirmation.

Replicate an open strategy

Any model an owner has marked open (incl. the autopilot's ★ @engo_autopilot models) can be inspected and copied by any verified user. On the board, click the model to see its holdings + reasoning; to mirror it from a bot:

# 0. discover what's on the board (every public model + its id; open_only = the copyable ones)
GET /api/v1/explore?open_only=true   →  {models:[{id, name, contributor, open, return_pct, …}, …]}
# 1. pull an open model's FULL strategy (your Bearer key)
GET /api/v1/strategy/<model_id>     →  {positions:{TICKER:weight,…}, legs, universe, methodology, reasoning:[…], curve, stats, kind}
# 2a. one-click clone it onto your own board (Pro) — it then trades forward independently
POST /api/v1/models/<model_id>/fork
# 2b. …or mirror it by hand into a fresh model
POST /api/v1/models  name=my-copy
PUT  /api/v1/models/<your_id>/positions   {"positions": <their positions map>}

You get the weights and the reasoning, not a black box — re-run it forward on your own paper book and compare. Want your own model to be copyable? Open it: POST /api/v1/models/{id}/open {"open":true} (or the share toggle on your dashboard). Private by default; opening shares the strategy with registered users only.

Options

Create a model with kind=options, browse a chain to get OCC contract symbols, then set legs. A model holds legs and we mark P&L = Σ side·qty·(mark−entry)·100. Pro models now mark off real-time Schwab option prices (0DTE included), refreshed through the session; the free tier marks off delayed per-contract prices, and any contract a delayed feed can't price (newly-listed / same-day) falls back to a Black-Scholes theoretical with intraday time value — so legs are never stuck flat. Multi-leg = your spread (the API marks all legs; defined-risk is how you build it). Greeks/IV come from Black-Scholes anchored to an ATM mark; full real-time greeks are a Pro upgrade.

# a defined-risk call vertical on AAPL
mid = requests.post(f"{B}/api/v1/models", headers=H, data={"name":"aapl-vert","kind":"options"}).json()["id"]
ch  = requests.get(f"{B}/api/v1/options/chain?underlying=AAPL&expiration=2026-07-17", headers=H).json()
rows = {r["strike"]: r for r in ch["rows"]}
long_k, short_k = sorted(rows)[len(rows)//2], sorted(rows)[len(rows)//2+2]
requests.put(f"{B}/api/v1/models/{mid}/legs", headers=H, json={"legs":[
    {"occ": rows[long_k]["call"]["occ"],  "side":"long",  "qty":1},
    {"occ": rows[short_k]["call"]["occ"], "side":"short", "qty":1}]})   # → net debit = your max loss
print(requests.get(f"{B}/api/v1/models/{mid}", headers=H).json())   # equity, pnl, marked legs

How marking works

What each number means (and how to recompute it)

Every displayed stat is recomputable from served data — these are the exact conventions (also machine-readable as conventions in GET /api/public):

fielddefinition
return_pct / retcurrent equity vs the fixed $100k start — the all-in number, every cost included; recompute as acct/100000 − 1. Curves recorded before 2026-07 could start after inception (flat days weren't marked), so curve[-1]/curve[0]−1 may differ on older rows; new curves start at $100k on creation day and record flat days, so the two agree going forward.
weekly_pct / wrettrailing ~7 calendar days: latest equity vs the last curve value strictly before (last curve date − 7d); since-inception when the curve is younger. Anchored to the curve's own last date (not the server clock), so it reproduces from the served curve at any hour. Same convention as the house rows.
curveone [date, equity] point per UTC day at the latest marks (Polygon daily close, 15-min delayed in-session; Schwab real-time on Pro); the same-day point refreshes intraday; capped at the last 400 points; flat days recorded (from 2026-07).
max_dd / calmar / expectancy / win_ratepure functions of the served curve — recompute directly.
dsr · p_adj · significantnightly family-wide deflated Sharpe (Bailey & López de Prado) + Holm-Bonferroni over the whole model family (may lag a day). The serve-time fdsr/holm_sig on /api/public recompute over every curve in that payload — the family IS the board you're holding.
live row (ret)operator-defined: dollar profit vs total contributions (deposit ledger), on the initial stake — deposits are capital, never gains. The time-weighted return is served alongside in live_status. Not recomputable from the public curve alone, and labeled as such.

Publish & get credited

Call /publish and your model joins the public leaderboard in the COMMUNITY tier with a ★ by @your-handle credit. P&L is public; you keep your edge (only you see your full position history via your key).

Upgrade — real-time soon

Questions / early access: tom@engo.capital. Paper-trading research, not investment advice.