LAB API
Run your ideas from a script instead of the terminal. Same conveyor,
same credits — a labk_ token stands in for your account.
The API is the exact machinery behind the LAB tab: you describe an idea, backtest it,
optimize it, and read the honest verdict — over HTTP. Base URL https://gex.live; every
body and response is JSON.
Authentication
Create a token on your account page (the LAB & API section). It is shown once; store it like a password. Send it as a Bearer token on every request:
Authorization: Bearer labk_your_token_here
A token is your account for LAB: jobs run over it spend your credit balance, whether they came from the browser or a script. It is scoped to LAB only — it cannot open the paid live stream — so a leaked token cannot cost you a subscription. Revoke it any time from the account page. No CSRF token or cookie is needed for Bearer requests.
Credits
- Developing an idea is free —
/api/lab/chatspends nothing, but it requires a positive balance (each message is an LLM call on our side). - Each job costs one credit — a backtest or an optimize pass. A failed job refunds its credit automatically.
- Out of credits →
402 {"error":"no credits","buy":"lab"}. Buy more on the LAB page.
The conveyor
An idea is not tested with a single call — it is walked down a conveyor, and
each step is a separate /api/lab/run that must come in order:
chat ─▶ BACKTEST ─▶ QUANT OPTIMIZE ─▶ ADD TO DESK (free) 1 credit 1 credit free rule tested ready desk
Backtest, then optimize — not one or the other. The backtest checks the rule as
you wrote it against an honest baseline. The optimize ("quant") then varies
every filter and shows whether any variant does better out of sample. You run the backtest
first (it moves the idea rule → tested); only a tested idea can
be optimized (tested → ready); only a ready idea can go to the
desk. Calling a step out of order is refused.
One idea occupies the conveyor at a time. A run against a second idea
while one is mid-test returns 409 {"holder":"i_..."} — finish it (to the desk)
or drop the first.
Quickstart (Python)
Describe the idea, then walk it: backtest → optimize → desk.
import os, requests
TOKEN = os.environ["GEX_LAB_TOKEN"] # labk_...
H = {"Authorization": f"Bearer {TOKEN}"}
BASE = "https://gex.live"
def show(result):
for leg in result["legs"]:
v = leg["verdict"]
print(" ", leg["title"], "->", "PASS" if v["interesting"] else "fail")
# 1. chat (free): describe the idea; LAB compiles it into a rule.
r = requests.post(f"{BASE}/api/lab/chat", headers=H, json={
"message": "fade a +3 sigma stretch above vwap when a 5-point candle "
"prints on top-decile volume; 15 minute horizon",
}).json()
if r["kind"] != "spec":
raise SystemExit(f"not compilable yet: {r['say']}") # LAB asked a question
idea = r["idea"]["id"]
print("compiled:", r["idea"]["name"])
# 2. BACKTEST (1 credit): the rule as written, against its honest baseline.
bt = requests.post(f"{BASE}/api/lab/run", headers=H,
json={"id": idea, "kind": "backtest"}).json()
print("backtest:"); show(bt["result"])
# 3. QUANT OPTIMIZE (1 credit): vary every filter. Do this AFTER the backtest.
qo = requests.post(f"{BASE}/api/lab/run", headers=H,
json={"id": idea, "kind": "quant"}).json()
print("optimize:", qo["result"]["variants_tried"], "variants tried")
# 4. ADD TO DESK (free): park the tested idea; frees the conveyor for the next one.
requests.post(f"{BASE}/api/lab/idea", headers=H,
json={"id": idea, "action": "desk"})Endpoints
POST /api/lab/chat
Compile a plain-words idea into a rule, or amend an existing one. Free, needs a positive balance.
{ "message": "fade a +3 sigma stretch ...", "id": "i_xxx (optional, to amend)" }
Returns one of:
{ "kind": "spec", "idea": { "id": "i_...", "name": "...", "spec": {...} }, "say": "..." }
{ "kind": "chat", "say": "which threshold do you mean?" } // needs clarifying
{ "kind": "error", "say": "...", "errors": [ ... ] } // could not compile
Any chat on an idea resets it to the start of the conveyor (a re-test is owed).
POST /api/lab/run
Run the idea's current conveyor step. Spends one credit; refunded on failure.
kind is not a menu — it is the step you are performing, and it must match the
idea's stage:
{ "id": "i_...", "kind": "backtest" } // stage rule -> tested (do this FIRST)
{ "id": "i_...", "kind": "quant" } // stage tested -> ready (then this)
{ "idea": { ... }, "result": { ...engine output... }, "state": { ...balance, ideas... } }
The result is the engine's verdict — per leg: an era table
(all / this year / holdout), each with the full rule vs its core-only
baseline, and a verdict (interesting is true only
when the rule clears cost out-of-sample AND beats its baseline there). The optimize adds
every variant, never a winner.
GET /api/lab/state
Everything in one call: your ideas, the conveyor holder, and your balance.
{ "ideas": [ { "id": "i_...", "name": "...", "stage": "desk", "spec": {...}, "results": {...} } ],
"conveyor": "i_... | null",
"balance": { "monthly": 0, "purchased": 100, "total": 100 } }
GET /api/lab/thread?id=i_...
The chat thread for one idea.
POST /api/lab/idea
Desk actions on an idea you own.
{ "id": "i_...", "action": "desk" } // ready -> on the desk, frees the conveyor
{ "id": "i_...", "action": "drop" } // return to the start, free the conveyor
{ "id": "i_...", "action": "delete" }
{ "id": "i_...", "action": "set", "on": true, "draw": "rails", "alert": "sound" }
curl
# compile an idea
curl -s https://gex.live/api/lab/chat \
-H "Authorization: Bearer $GEX_LAB_TOKEN" \
-H "content-type: application/json" \
-d '{"message":"fade a +3 sigma stretch above vwap on top-decile volume"}'
# run a backtest, then optimize the same idea
curl -s https://gex.live/api/lab/run -H "Authorization: Bearer $GEX_LAB_TOKEN" \
-H "content-type: application/json" -d '{"id":"i_xxx","kind":"backtest"}'
curl -s https://gex.live/api/lab/run -H "Authorization: Bearer $GEX_LAB_TOKEN" \
-H "content-type: application/json" -d '{"id":"i_xxx","kind":"quant"}'Errors
401 | missing, unknown, or revoked token |
402 | no credits — {"buy":"lab"} |
404 | no such idea (or not yours) |
409 | another idea is on the conveyor — {"holder":"i_..."} |
422 | the engine rejected the rule (refunded) |
502 | the engine failed (refunded) — retry |
Not investment advice. Options trading carries substantial risk of loss. Backtested performance does not guarantee future results.