Reference · API & Docs

Integration docs.

Everything you need to integrate your matching engine. The browser-runtime contract here matches the production HTTP/WS contract one-to-one: write once, run on either.

01Overview

Your submission is a matching engine. The platform sends you orders; you respond with acks and fills. Lower latency, higher throughput, and lower error rate score higher. The platform measures both the wall-clock time of submit() and the correctness of fills under price-time priority.

02The submit() contract

Same shape across every language. Your engine is a container exposing POST /submit that takes an order and returns {acks, fills} — see the Engine contract below.

JavaScript template

// orderbook.js: minimal valid JS submission const bids = new Map(); // price → [{id, qty}] const asks = new Map(); let nextFillId = 1; function bestPrice(book, isBid) { if (book.size === 0) return null; let b = null; for (const p of book.keys()) { if (b === null || (isBid ? p > b : p < b)) b = p; } return b; } function match(order) { const opp = order.side === 'buy' ? asks : bids; const fills = []; let qty = order.qty; while (qty > 0) { const px = bestPrice(opp, order.side === 'sell'); if (px === null) break; const crosses = order.type === 'market' || (order.side === 'buy' ? px <= order.price : px >= order.price); if (!crosses) break; const q = opp.get(px); while (q.length && qty > 0) { const rest = q[0]; const m = Math.min(qty, rest.qty); qty -= m; rest.qty -= m; fills.push({ id: nextFillId++, price: px, qty: m, makerId: rest.id }); if (rest.qty === 0) q.shift(); } if (q.length === 0) opp.delete(px); } return { qty, fills }; } module.exports.submit = (order) => { if (!order || !(order.qty > 0)) return { acks: [{ id: order?.id, status: 'rejected' }], fills: [] }; if (order.type === 'cancel') { // implement cancel handling here… return { acks: [{ id: order.id, status: 'cancelled' }], fills: [] }; } const { qty: remaining, fills } = match(order); if (order.type === 'limit' && remaining > 0) { const book = order.side === 'buy' ? bids : asks; if (!book.has(order.price)) book.set(order.price, []); book.get(order.price).push({ id: order.id, qty: remaining }); } return { acks: [{ id: order.id, status: 'accepted', filled: order.qty - remaining }], fills }; };

Python template

Python runs as real CPython compiled to WASM (Pyodide). Cold-start is ~5s; once loaded each submit() typically runs in 100–500µs.

# orderbook.py: minimal valid Python submission bids = {} # price -> [(id, qty), ...] asks = {} _fill_id = [0] def best_price(book, is_bid): if not book: return None return max(book) if is_bid else min(book) def match(order): opp = asks if order["side"] == "buy" else bids fills, qty = [], order["qty"] while qty > 0: px = best_price(opp, order["side"] == "sell") if px is None: break crosses = order["type"] == "market" or ( order["side"] == "buy" and px <= order["price"]) or ( order["side"] == "sell" and px >= order["price"]) if not crosses: break q = opp[px] while q and qty > 0: rid, rqty = q[0] m = min(qty, rqty) qty -= m; q[0] = (rid, rqty - m) _fill_id[0] += 1 fills.append({"id": _fill_id[0], "price": px, "qty": m, "makerId": rid}) if q[0][1] == 0: q.pop(0) if not q: del opp[px] return qty, fills def submit(order): if not order or order.get("qty", 0) <= 0: return {"acks": [{"id": order.get("id"), "status": "rejected"}], "fills": []} if order["type"] == "cancel": return {"acks": [{"id": order["id"], "status": "cancelled"}], "fills": []} remaining, fills = match(order) if order["type"] == "limit" and remaining > 0: book = bids if order["side"] == "buy" else asks book.setdefault(order["price"], []).append((order["id"], remaining)) return { "acks": [{"id": order["id"], "status": "accepted", "filled": order["qty"] - remaining}], "fills": fills, }

WebAssembly ABI (C++/Rust/Go/Zig)

Compile your engine to a .wasm module that exports five symbols. Wire format: JSON-over-linear-memory. Compatible with emcc, wasm-bindgen, TinyGo, AssemblyScript, Zig.

// Required exports memory: WebAssembly.Memory alloc(n: i32) -> i32 // allocate n bytes in wasm linear memory free(ptr: i32) -> void // matching free submit_bytes(ptr: i32, len: i32) -> i32 // returns response ptr submit_bytes_len() -> i32 // length of last response // Optional env.log_str(ptr: i32, len: i32) // platform logging hook env.now_ns() -> i64 // monotonic clock

03Order schema

Every call to submit() receives a single order object:

{ "id": 42, // monotonic uint64 "side": "buy" | "sell", "type": "limit" | "market" | "cancel", "price": 10000, // integer ticks (price×100); ignored for market "qty": 5, "ts": 1735689600000000, // µs since epoch "targetId": 17 // only on cancel }

Return value:

{ "acks": [{ id, status, filled, remaining, message? }], "fills": [{ id, price, qty, takerId, makerId }] }

04Scoring formula

Composite score per run (0–100):

// each component is normalised to [0, 100] speedScore = max(0, 100 - p99_µs / 5) // 0µs = 100, 500µs = 0 throughputScore = min(100, tps / 30_000) // 3M ops/s = 100 correctnessScore = max(0, 100 - err_rate × 5000) // 2% err = 0 composite = 0.40 × speedScore + 0.40 × throughputScore + 0.20 × correctnessScore

Weights are tunable by an operator (see the Judge Console). The platform recomputes scores using new weights when a re-score is triggered.

05Engine contract

Your engine is a container exposing POST /submit (port 9001 by convention) and GET /healthz. Prices are integer ticks (price × 100) — no floats in the matching path.

POST /submit

$ curl -X POST http://<engine>:9001/submit \ -H "Content-Type: application/json" \ -d '{"id":1,"clientId":7,"side":"buy","type":"limit","price":10000,"qty":5}' // 200 OK {"acks":[{"id":1,"status":"filled","filled":5}],"fills":[...]}

type ∈ limit · market · cancel (cancel targets a resting targetId). side ∈ buy · sell. GET /healthz returns {"status":"ok"}.

06Live telemetry (platform WebSocket)

While a run is in flight the platform streams rolling metrics over a WebSocket — this is exactly what the Console dashboard consumes.

ws://<host>:8080/ws/runs/<runId> // every 1s while running { "type":"metrics", "orders":.., "tps":.., "avgLatMs":.., "errPct":.. } // on finish { "type":"final", "p50":..,"p99":..,"p99_9":..,"p99_99":..,"tps":..,"score":.. }

07Run & leaderboard REST

GET /api/leaderboard // ranked teams: score, p50, p99, tps POST /api/runs // {submissionId,profile,durationSec,botsPerFleet,targetRatePerBot} GET /api/runs/<id> // status + composite score POST /api/runs/<id>/baseline // promote a regression baseline GET /api/runs/<id>/regression // diff vs baseline → OK | REGRESSION

08Sandbox limits

cpu: 1 vCPU (pinned, no oversubscription) memory: 256 MB hard cap (RLIMIT_AS + cgroup memory.max) disk: 100 MB ephemeral, mounted RW only on /tmp network: inbound only · gateway-mesh only syscalls: seccomp default-deny + curated allowlist build budget: 60s · failures recorded run budget: 300s per stress test

09Codebase map

For anyone (human or agent) editing this platform, here's what each file does:

/ ├─ index.html // public landing page └─ platform/ ├─ dashboard.html // developer home: subs + runs + team ├─ submit.html // upload + hash + sandbox-build · multi-language ├─ run.html // stress test · runtime workers · profiles · feed ├─ correctness.html // validation suite (17 tests · 6 categories) ├─ leaderboard.html // public rankings + CSV export ├─ architecture.html // system diagram ├─ judge.html // admin · re-score · DQ · platform state ├─ docs.html // you're reading it └─ assets/ ├─ tokens.css // design tokens - colors, type, spacing ├─ platform.css // shared layout + components ├─ store.js // localStorage + IDB + BroadcastChannel ├─ layout.js // sidebar/topbar injector + toast helper ├─ engine.js // reference matching engine (price-time) ├─ bot-worker.js // fallback in-process bot fleet ├─ tdigest.js // streaming percentiles (p50/p99 sketch) ├─ rng.js // seeded RNG · xoshiro128** · deterministic ├─ runtime.js // multi-language runtime adapter (main thread) ├─ runtime-js.js // JS runtime worker ├─ runtime-py.js // Python via Pyodide worker ├─ runtime-wasm.js // .wasm instantiate worker ├─ runtime-judge0.js // remote Judge0 CE adapter ├─ correctness.js // validation tests · severity-weighted score └─ market-feed.js // optional Binance WS for realistic flow

10Adversarial test inputs

The correctness suite probes these: your engine must handle them without crashing or producing impossible output. Run correctness.html to see the full list.

// Inputs your engine WILL receive in adversarial mode { qty: -5 } // negative quantity { qty: 0 } // zero quantity { qty: 1e15 } // astronomical quantity { price: NaN } // not-a-number price { price: Infinity } { type: "fok" } // unknown order type { type: "cancel", targetId: 99999 } // cancel of unknown id // All must be rejected gracefully · no crashes · no phantom resting orders