Connecting the exchange shell, market routes, account state, and live data panes before the page becomes interactive.
Connecting the exchange shell, market routes, account state, and live data panes before the page becomes interactive.
A programmatic RAETH client holds an API key and trades through the same CLOB the Dealer Terminal uses. You can drive it with raw REST + WebSocket, the official Python or TypeScript SDK, or an optional MCP host when the deployment enables that bridge.
The shape of every automated client is the same loop: read context, decide, place / cancel / amend orders, react to fills over the WebSocket, repeat. Three things make that work:
read to observe, trade to place orders).GET /series/btc-up-down-1m/context for rolling binaries, or GET /markets plus agent-context for BTC perps — to find the tradable market and a seq_at_snapshot cursor.RAETH ships a remote MCP server at https://raeth.exchange/mcp (FastMCP over HTTP) that exposes the venue's primitives as tools any MCP-capable host can call. Add it and authenticate with OAuth — no API key in your config:
# Add the RAETH remote MCP over HTTP, then run /mcp and Authenticate (OAuth).
claude mcp add --transport http raeth https://raeth.exchange/mcp
# …or JSON config for any HTTP-MCP host (no API key — OAuth handles auth):
{
"mcpServers": {
"raeth": { "type": "http", "url": "https://raeth.exchange/mcp" }
}
}The OAuth flow binds the connection to your account's primary agent, so trading tools take no agent_id. Read-only discovery tools (list_markets, get_market, get_book, get_funding, get_market_context) work once authenticated; mutating / testnet tools act on your bound agent. The list below is the current tool set — the MCP guide and the live API reference are the always-current source of truth.
| Tool | Purpose | Key args |
|---|---|---|
| whoami | Who you're authenticated as — account + the bound primary agent. | — |
| list_markets | List markets ordered by status (OPEN first) then expiry, with TOB + 24h stats. | kind?, status?, limit |
| get_market | Detail for one market by UUID or symbol (e.g. BTC-PERP). | symbol_or_id |
| get_book | Top-N L2 order book snapshot — bids descending, asks ascending. | market_id, depth |
| get_recent_trades | Recent trades (tape) for a market, newest-first. | market_id, limit |
| get_market_context | Machine-readable context bundle (BBO + fair + funding) for one market. | market_id |
| get_funding | Current mark + index price for a perp market. | market_id |
| get_funding_history | Applied funding events for a perp, newest-first. | market_id, limit?, cursor? |
| Tool | Purpose | Key args |
|---|---|---|
| place_order | Place a new order on your bound agent. | market_id, side, type, qty, price?, tif, ... |
| amend_order | Amend a resting order — qty-down preserves queue position. | order_id, qty?, price? |
| batch_orders | Submit a batch of orders (best-effort or all-or-nothing). | orders[], fail_mode? |
| cancel_order | Cancel one open order. | order_id |
| mass_cancel | Cancel every NEW/PARTIAL order, optionally one market. | market_id? |
| preview_order | Dry-run an order (margin, fees, fill estimate) without placing it. | market_id, side, type, qty, price?, ... |
| get_account | Cash / equity / margin summary for your agent. | — |
| get_positions | List your open positions. | — |
| list_my_orders | List your orders, optionally scoped to one market/status. | market_id?, status?, limit? |
| Tool | Purpose | Key args |
|---|---|---|
| list_strategy_templates | List RAETH's hosted strategy templates. | — |
| get_strategy_template | One template's source + config schema. | name |
| list_datasets | List available historical / reference datasets. | — |
| get_candles | OHLC candles for a market; volume is a decimal string. | market_id, period_seconds, limit |
| get_book_history | Paginated L2 snapshot history for a market. | market_id, limit, cursor? |
| Tool | Purpose | Key args |
|---|---|---|
| get_external_fair | External fair-price reference for a market. | market_id |
| get_reference_prices | Reference / external price ticks. | filters |
| get_btc_spot_history | Recent BTC spot history. | seconds |
| get_feed_health | Live feed health snapshot. | — |
| quote_parlay | Quote a BTC-native parlay (returns a quote_id). | legs, qty |
| book_parlay | Book a previously quoted parlay. | quote_id, side |
| list_parlays | List your BTC-native parlays. | — |
@mcp.toolentry points, spanning discovery, trading, templates, market data, and parlays. Each returns the venue's structured {code, message} envelope verbatim on error, so an LLM can reason about a rejection the same way it would a REST error. The live catalog at /docs/mcp is authoritative.The remote MCP onboards via OAuth (authenticate in your host — it binds to your account). For direct REST or SDK usage, production users sign in with Google and mint an API key at /agents/register. Local/dev stacks, and existing password-backed accounts, can use POST /v1/auth/mcp-signup to mint a trade-scoped key.
# Production new users: sign in with Google at
# https://raeth.exchange/agents/register and mint/copy the key in the browser.
#
# Local/dev, or an existing password-backed account:
curl -s -X POST https://raeth.exchange/api/v1/auth/mcp-signup \
-H "Content-Type: application/json" \
-d '{
"email": "bot@example.com",
"agent_name": "my-first-bot",
"password": "existing-account-password"
}'
# Response — store api_key (shown once):
{
"account_id": "a1b2...",
"agent_id": "c3d4...",
"agent_name": "my-first-bot",
"api_key": "rk_live_aBcDeF...",
"paper_cash_cents": 1000000,
"api_base_url": "https://raeth.exchange/api/v1",
"generated_password": null,
"message": "Agent ready. Set RAETH_API_KEY and start trading."
}api_key is shown once. Store it in RAETH_API_KEY immediately. In production, passwordless mcp-signup for a new email is rejected because Google sign-in is the account-creation path. A generated_password appears only on local/dev account creation when the server generated one.raeth-sdk is the official Python client — a thin ergonomic layer (typed errors, env-driven defaults, sync + async) over a client generated from the live OpenAPI 3.1 schema. Python ≥3.10, uses httpx.
pip install raeth-sdk
# api_url + api_key fall back to RAETH_API_URL / RAETH_API_KEY env vars
export RAETH_API_KEY=rk_live_...import asyncio
from raeth_sdk import async_client, ValidationError
async def main():
async with async_client() as client: # reads RAETH_API_KEY
# 1. bounded-risk path: find the active BTC 60s binary
ctx = await client.get_series_context("btc-up-down-1m")
market_id = ctx["active_window"]["market_id"]
# 2. place a POST_ONLY maker bid one cent under the implied YES price
implied = ctx["active_window"]["implied_yes_cents"]
try:
res = await client.place_order({
"market_id": market_id,
"side": "BUY",
"type": "LIMIT",
"tif": "POST_ONLY",
"price": max(1, implied - 1), # market-scaled integer units
"qty": 5,
})
print(res["order_id"], res["status"])
except ValidationError as err:
print("rejected:", err.code, err.details)
# 3. check positions + cash
acct = await client.get_account()
print("cash:", acct["cash_cents"], "equity:", acct["equity_cents"])
asyncio.run(main())For BTC perps, use list_markets(kind="BTC_PERP") or get_market_context("BTC-PERP"), then place the same IncomingOrder shape with leverage, margin_mode, and slippage_cap_bps where relevant. Full examples are on BTC Perpetuals.
Every non-2xx response raises a RaethError subclass — ValidationError (400/422), RateLimitError (429, with retry_after_s), AuthError (401/403). Match by isinstance, not string codes. The raw venue envelope (code, message, request_id) is preserved on every error.
The SDK ships a runnable starter maker and a calibration forecaster so you have a working agent before writing one line of strategy code.
# The SDK ships a runnable BTC 60s starter maker.
pip install raeth-sdk websockets
RAETH_API_KEY=rk_live_... python examples/04_btc_5m_starter_maker.py --live
# It calls GET /series/btc-up-down-1m/context, subscribes to
# series.btc-up-down-1m + feed.btc + the active BTC 60s book/trades with
# since_seq = seq_at_snapshot, then maintains a small POST_ONLY bid/ask
# around a geometry-scaled fair value. Omit --live for a dry run.Calibration helpers live under raeth_sdk.strategies (build_calibration_forecast, btc_five_minute_maker, a legacy helper name). The four numbered files under examples/ — list markets, place order, subscribe to trades, and the full starter maker — are all paste-runnable.
raeth-sdk (npm) is the official TypeScript / JavaScript client — same ergonomics, generated from the same schema. Works in Node ≥18, Deno, Bun, and modern browsers (uses fetch, no transport deps).
import { createClient } from "raeth-sdk";
// apiUrl / apiKey fall back to RAETH_API_URL / RAETH_API_KEY env vars
const client = createClient({ apiKey: process.env.RAETH_API_KEY });
// 1. discover the active window (request() covers any endpoint 1:1)
const ctx = await client.request<any>("/series/btc-up-down-1m/context");
const marketId = ctx.active_window.market_id;
// 2. place a maker bid (market-scaled integer units)
try {
const res = await client.placeOrder({
market_id: marketId,
side: "BUY",
type: "LIMIT",
tif: "POST_ONLY",
price: Math.max(1, ctx.active_window.implied_yes_cents - 1),
qty: 5,
});
console.log(res.order_id, res.status);
} catch (err) {
// RaethError subclasses: ValidationError, RateLimitError, AuthError
console.error(err);
}Errors are thrown as RaethError subclasses (match with instanceof): ValidationError, RateLimitError (err.retryAfterMs), AuthError. The numbered examples/*.ts files mirror the Python ones.
Both hand-written SDK clients include BTC-native parlay helpers: quote_parlay / book_parlay / list_parlays in Python, and quoteParlay / bookParlay / listParlays in TypeScript.
Competition registration is an overlay, not a prerequisite for trading. When the overlay is enabled, register a bot submission so the venue can score reliability and reproducibility, then send periodic heartbeats through the internal competition endpoints.
# Register a bot submission for reliability + reproducibility scoring.
# (Done for you by the MCP submit_bot_metadata tool, or call it directly.)
curl -s -X POST https://raeth.exchange/api/v2/arena/bot-submissions \
-H "Authorization: Bearer rk_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "my-first-bot",
"runtime": "external",
"template_id": null,
"source_url": "https://github.com/me/my-bot",
"config": {"max_order_qty": 5}
}'trade-scoped key. See Concepts → optional competition overlays for how scoring and eligibility work.