AI Trading Coliseum Developer API

Every trade these twelve agents make is published, and so is the fee and the slippage on each fill. This page describes the read only JSON endpoints that serve it. There is no key, no account, no sign up and no attribution header.

Machine readable description: /openapi.json (OpenAPI 3.1). Site brief for agents: /llms.txt. Full URL inventory: /sitemap.xml. API catalog (RFC 9727): /.well-known/api-catalog.

Read this before you parse anything

  • A 200 is not always data. When the engine is unreachable these routes return HTTP 200 with {"status":"reconnecting"}. Check the shape of the body, not only the status code.
  • The tape truncates silently. /api/trades?limit=N returns exactly N rows with no flag saying it stopped early, and the earliest timestamp in that result is then not the start of the season. Ask for more rows than the tape holds and confirm the count stopped growing.
  • Entries and exits are separate rows, and action does not tell them apart. Closing a short is a BUY. The only reliable mark for an exit is the CLOSE prefix on reasoning.
  • Exits cannot be reliably paired back to their entries. Entry timestamps are captured at a second clock and sit one second off the matching entry row on a large minority of exits, and rows before 2026-06-26 carry no entry timestamp at all. A round trip view built on this would invent a substantial share of its pairings, which is why the site publishes none.
  • Coverage is not continuous. Some calendar days inside the range carry no rows, so the span of the tape is not the same thing as its coverage.
  • Absence is marked, not zeroed. sharpe_measurable and max_drawdown_measurable say whether the figure beside them was computed at all. A false there means the number is missing, and rendering it as 0 is a fabrication.

Endpoints

GET /api/trades

The published trade tape, newest first.

Returns trade rows. An entry and its exit are separate rows; the only reliable mark for an exit is the CLOSE prefix on reasoning, because action is BUY or SELL on both sides (closing a short is a BUY).

KNOWN LIMIT: the tape truncates silently. Asking for fewer rows than the tape holds returns exactly that many with no flag saying so, and the earliest timestamp in the result is then not the start of the season. To read the whole tape, ask for more rows than it can hold and confirm the count stopped growing.

KNOWN LIMIT: the eight cost fields (gross_pnl, fee, slippage, funding and the exit fields) appear only on exit rows, and only from 2026-06-26 onward. Their absence on an older row is a cutover, not a gap.

If the engine is unreachable this returns HTTP 200 with {"status":"reconnecting","trades":[]} rather than an error status, so a caller must check the shape of the body and not only the status code.

Query parameters

  • limit (optional). Rows to return. Defaults to 50, which is far short of the tape. Clamped to [1, 50000].

Try it: curl https://arena.aicoliseum.io/api/trades

GET /api/agents

The twelve agents and their live state.

The agents carry the names of well known AI models. They are strategy personas, not those models: all twelve run one mean reversion strategy and differ only in four parameters. sharpe_measurable and max_drawdown_measurable say whether the corresponding figure was computed at all, and a false there means the number is absent rather than zero.

Returns {"status":"reconnecting","agents":[]} at HTTP 200 when the engine is unreachable.

Try it: curl https://arena.aicoliseum.io/api/agents

GET /api/research/cost-decomposition

The whole season decomposed into gross result, fee, slippage and funding.

The same arithmetic the home page and /research render, over the same tape, so a reader of the page and a reader of this endpoint cannot be looking at different numbers.

Read integrity before the figures. totalsFullyVerified is false when rows could not be reconciled to within toleranceUsd, and unverifiableRows counts rows that carry no cost fields at all.

Try it: curl https://arena.aicoliseum.io/api/research/cost-decomposition

GET /api/levels

Derived price levels for one symbol and timeframe.

Prior extremes, session opens and the current ATR, each carrying the method that produced it. method is part of the payload on purpose: a level with no stated lookback is an assertion rather than a measurement.

Query parameters

  • symbol (optional). Symbol id. Defaults to BTC.
  • tf (optional). Timeframe. Defaults to 1h.

Try it: curl https://arena.aicoliseum.io/api/levels

Errors

Every 4xx is an RFC 9457 application/problem+json document. Branch on code, which is stable; title and detail are prose and may be reworded. hint says what to do instead.

One shape that is not an error: when the engine is unreachable these routes answer HTTP 200 with a reconnecting body. Check the shape of a 200 before trusting it.

endpoint_not_found (404)
No endpoint at that path. The body lists every documented endpoint. /openapi.json has the full description.
method_not_allowed (405)
The API is read only and you sent something other than GET or HEAD. Read the Allow header, which lists what the endpoint accepts.
invalid_parameter (400)
A query parameter was rejected. The parameter member names the offending one, and hint gives the accepted values.
upstream_unavailable (502)
The engine could not be reached on a route that fails loudly rather than returning a sentinel. Retry with backoff. This is transient and not a fault in the request.

Versioning and deprecation

Every response carries API-Version: 1. There is deliberately no /api/v1/ path: these URLs are already published as permanent, and renaming them to add a version segment would break every existing caller to satisfy a convention. The guarantee is the same either way.

Markdown for agents

This site content negotiates. Send Accept: text/markdown to a URL and the pages whose content is held as structured data return Markdown from that same canonical URL, with Vary: Accept set. That covers the home page, the academy and every order flow guide. Pages whose content lives in components return HTML and advertise no Markdown alternate, because a rel="alternate" pointing at a dead end costs an agent a request and tells it nothing.

A request that accepts neither HTML nor Markdown gets a 406 naming what is available, rather than HTML it did not ask for.

Rate limits and fair use

Every response carries the rate limit fields from draft-ietf-httpapi-ratelimit-headers, so you can pace yourself rather than discovering the wall:

RateLimit-Policy: "default";q=100;w=60
RateLimit: "default";r=94;t=25

q is the quota, w the window in seconds, r what is left and t the seconds until it resets. A 429 adds Retry-After in seconds, matching t, and its body is the same problem document as any other error, with code: rate_limited.

Treat the quota as a floor you can rely on, not a ceiling to probe. The counter lives in one server instance rather than in a shared store, so a burst from one client usually meets it exactly, and requests spread across instances may get further. Measured on production: a sequential run of 130 requests was refused at the 95th. We would rather publish that than imply a global counter we do not operate.

The trade tape is cached at the edge for 30 seconds, so polling faster than that returns the same bytes and helps nobody. The median gap between trades is about two minutes. If you want the whole tape, pull it once and page forward using id, which is monotonic with time and works as a cursor.

Paper trading only, no real funds. Simulation, not financial advice. Nothing returned by these endpoints is a trading signal, a recommendation or an offer, and nothing on this site is for sale.