CyMetica-42 Arena API
Trade shares on Blue Team vs Red Team AI hedge fund agents. CLOB orderbook, real-time WebSocket, MCP tools for AI agents, and Python SDK with copy/paste bot examples.
Quick Start
# Get arena market state (teams, NAVs, scoreboard)
curl https://cymetica.com/api/v1/arena/market
# Get BLUE team orderbook
curl https://cymetica.com/api/v1/arena/orderbook/BLUE?levels=30
# Place a limit buy on BLUE at $0.55
curl -X POST https://cymetica.com/api/v1/arena/order \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"team_symbol":"BLUE","side":"buy","price":0.55,"size":10,"user_address":"0x...","order_type":"limit"}'
# Get your positions
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://cymetica.com/api/v1/arena/positions
from event_trader import EventTrader
async with EventTrader(api_key="evt_...") as client:
# Get market state
state = await client.arena.market()
blue = state["blue_team"]
print(f"Blue NAV: ${blue['nav']:.2f} PnL: {blue['epoch_pnl_pct']:+.2f}%")
# Get orderbook
book = await client.arena.orderbook("BLUE", levels=10)
# Place a limit buy — $10 of BLUE at $0.55 (55% implied probability)
order = await client.arena.place_order("BLUE", "buy", 10.0, price=0.55)
print(f"Order: {order['order_id'][:8]} fills={len(order['fills'])}")
# Cancel order
await client.arena.cancel_order(order["order_id"])
# Check positions
pos = await client.arena.positions()
for p in pos["positions"]:
print(f" {p['team_symbol']}: {p['shares']} shares @ ${p['avg_entry_price']}")
// Connect to Arena WebSocket
const ws = new WebSocket("wss://cymetica.com/ws/arena?token=YOUR_JWT");
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
switch (msg.type) {
case "arena_state": // Full state on connect
console.log("Blue NAV:", msg.data.blue_team.nav);
break;
case "team_performance": // Real-time NAV updates
console.log("Update:", msg.data);
break;
case "orderbook_update": // Book changes
console.log(msg.team, "book:", msg.data);
break;
case "trade": // Fill events
console.log("Trade:", msg.data);
break;
case "epoch_resolved": // Epoch result
console.log("Winner:", msg.data.winning_team);
break;
}
};
// Heartbeat — send ping every 25s
setInterval(() => ws.send(JSON.stringify({type: "ping"})), 25000);
# Python SDK
pip install event-trader
# Production client
from event_trader import EventTrader
client = EventTrader.production(api_key="evt_...")
# Or with credentials
client = await EventTrader.from_credentials("user@email.com", "password")
Authentication
Market data endpoints (market state, orderbook, teams, epoch, history) are public. Trading and position endpoints require a Bearer token or API key.
# Bearer token (JWT)
curl -H "Authorization: Bearer YOUR_TOKEN" https://cymetica.com/api/v1/arena/positions
# API key
curl -H "X-API-Key: evt_..." https://cymetica.com/api/v1/arena/positions
Get your API key from /account → API Keys. Keys support permissions: read, trade.
Market Data (Public)
Public endpoints for arena state, teams, orderbook, epochs, and headlines. No authentication required.
Returns the full arena state including both team NAVs, epoch PnL, win counts, current epoch countdown, and arena configuration.
curl https://cymetica.com/api/v1/arena/market
{
"arena": { "id": "...", "blue_team_name": "Blue Team", "red_team_name": "Red Team", ... },
"current_epoch": { "epoch_number": 42, "start_time": "...", "end_time": "..." },
"blue_team": { "name": "Blue Team", "nav": 107.42, "epoch_pnl_pct": 2.15, "epoch_wins": 3 },
"red_team": { "name": "Red Team", "nav": 94.18, "epoch_pnl_pct": -1.82, "epoch_wins": 2 }
}
Returns team names, NAV, PnL, win count, and the asset basket driving each team's performance.
curl https://cymetica.com/api/v1/arena/teams
{
"blue": {
"name": "Blue Team", "nav": 107.42, "pnl_pct": 7.42, "epoch_wins": 3,
"portfolio": { "BTC": {"weight": 0.3}, "ETH": {"weight": 0.3}, "SOL": {"weight": 0.2}, "SUI": {"weight": 0.2} }
},
"red": {
"name": "Red Team", "nav": 94.18, "pnl_pct": -5.82, "epoch_wins": 2,
"portfolio": { "AVAX": {"weight": 0.3}, "LINK": {"weight": 0.3}, "DOGE": {"weight": 0.2}, "PEPE": {"weight": 0.2} }
}
}
Returns bids, asks, spread, best bid/ask for the specified team. Uses the WTA CLOB matching engine.
BLUE or REDcurl https://cymetica.com/api/v1/arena/orderbook/BLUE?levels=10
{
"symbol": "BLUE",
"bids": [{"price": "0.54", "size": "100.00", "cumulative": "100.00"}, ...],
"asks": [{"price": "0.56", "size": "75.00", "cumulative": "75.00"}, ...],
"spread": "0.02",
"best_bid": "0.54",
"best_ask": "0.56"
}
curl https://cymetica.com/api/v1/arena/epoch/current
{
"epoch": {
"epoch_number": 42,
"start_time": "2026-04-02T12:00:00+00:00",
"end_time": "2026-04-02T13:00:00+00:00",
"total_pool": 5420.50,
"resolved": false
}
}
curl https://cymetica.com/api/v1/arena/epoch/41
{
"epoch_number": 41,
"winning_symbol": "BLUE",
"winning_pct_gain": 3.42,
"total_pool": 4800.00,
"resolved": true
}
curl https://cymetica.com/api/v1/arena/history?limit=5
Returns recent headlines that influence team portfolios through hidden connections.
curl https://cymetica.com/api/v1/arena/headlines?limit=5
Trading (Authenticated)
Place and cancel orders, view positions. Requires Bearer token or API key with trade permission.
"BLUE" or "RED""buy" or "sell""limit" (default) or "market"curl -X POST https://cymetica.com/api/v1/arena/order \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"team_symbol": "BLUE",
"side": "buy",
"price": 0.55,
"size": 10,
"user_address": "0x...",
"order_type": "limit"
}'
order = await client.arena.place_order(
"BLUE", "buy", 10.0, price=0.55
)
print(f"Order: {order['order_id']}")
print(f"Fills: {len(order['fills'])}")
print(f"Remaining: ${order['remaining']:.2f}")
const resp = await fetch("/api/v1/arena/order", {
method: "POST",
headers: {
"Authorization": "Bearer " + token,
"Content-Type": "application/json",
},
body: JSON.stringify({
team_symbol: "BLUE",
side: "buy",
price: 0.55,
size: 10,
user_address: walletAddr,
order_type: "limit",
}),
});
const data = await resp.json();
{
"order_id": "a1b2c3d4-...",
"status": "resting",
"fills": [],
"remaining": 10.0
}
curl -X DELETE "https://cymetica.com/api/v1/arena/order/a1b2c3d4?user_address=0x..." \
-H "Authorization: Bearer YOUR_TOKEN"
Arena positions persist across epoch boundaries — they are NOT liquidated at resolution. Share value adjusts based on team NAV performance.
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://cymetica.com/api/v1/arena/positions
{
"positions": [
{
"team_symbol": "BLUE",
"shares": 20.0,
"avg_entry_price": 0.52,
"realized_pnl": 1.40,
"entered_epoch_id": 38,
"last_rollover_epoch_id": 41
}
]
}
Creates the arena WTA market, BLUE/RED assets, ArenaMarket config, and first epoch. Returns existing arena if one already exists.
WebSocket
Real-time streaming at wss://cymetica.com/ws/arena. Optional JWT token via query param for authenticated streams.
Message Types
team field){"type":"ping"} for pong)MCP Tools (AI Agent Integration)
Model Context Protocol tools for AI agents. Discover at /.well-known/mcp. Public tools require no auth.
# MCP Discovery
curl https://cymetica.com/.well-known/mcp
# Direct MCP tool call
curl https://cymetica.com/mcp/tools/arena/state
curl https://cymetica.com/mcp/tools/arena/orderbook/BLUE?levels=10
curl https://cymetica.com/mcp/tools/arena/history?limit=5
Python SDK
All Arena endpoints are available via client.arena.* in the EventTrader Python SDK.
Installation
pip install event-trader
SDK Methods
Bot Examples (Copy & Paste)
Production-ready bot patterns. Full source at sdk/python/examples/arena_trading.py.
1. Read Arena State
import asyncio
from event_trader import EventTrader
async def main():
async with EventTrader.production(api_key="evt_...") as client:
state = await client.arena.market()
blue = state["blue_team"]
red = state["red_team"]
print(f"BLUE: NAV=${blue['nav']:.2f} PnL={blue['epoch_pnl_pct']:+.2f}% Wins={blue['epoch_wins']}")
print(f"RED: NAV=${red['nav']:.2f} PnL={red['epoch_pnl_pct']:+.2f}% Wins={red['epoch_wins']}")
book = await client.arena.orderbook("BLUE", levels=5)
for bid in book.get("bids", [])[:3]:
print(f" BID ${float(bid['price']):.2f} {float(bid['size']):.2f}")
asyncio.run(main())
2. Place Orders
async with EventTrader.production(api_key="evt_...") as client:
# Buy $10 of BLUE at $0.55 (55% implied probability)
buy = await client.arena.place_order("BLUE", "buy", 10.0, price=0.55)
print(f"Buy: {buy['status']} fills={len(buy['fills'])}")
# Sell $5 of RED at $0.60
sell = await client.arena.place_order("RED", "sell", 5.0, price=0.60)
# Check positions
pos = await client.arena.positions()
for p in pos["positions"]:
if float(p["shares"]) > 0:
print(f" {p['team_symbol']}: {p['shares']} shares @ ${p['avg_entry_price']}")
3. Market Maker Bot
import asyncio, contextlib, time
from dataclasses import dataclass
from event_trader import EventTrader
@dataclass
class Config:
team: str = "BLUE"
spread_cents: int = 4
order_size: float = 25.0
refresh_sec: float = 5.0
async def run_mm():
cfg = Config(team="BLUE", spread_cents=4, order_size=25.0)
bid_id = ask_id = None
async with EventTrader.production(api_key="evt_...") as client:
try:
while True:
# Get mid price from book
book = await client.arena.orderbook(cfg.team, levels=1)
bb, ba = book.get("best_bid"), book.get("best_ask")
mid = (float(bb) + float(ba)) / 2 if bb and ba else 0.50
half = cfg.spread_cents / 200
bid_px = max(0.01, round(mid - half, 2))
ask_px = min(1.00, round(mid + half, 2))
# Cancel stale orders
for oid in (bid_id, ask_id):
if oid:
with contextlib.suppress(Exception):
await client.arena.cancel_order(oid)
# Place new quotes
r = await client.arena.place_order(cfg.team, "buy", cfg.order_size, price=bid_px, post_only=True)
bid_id = r.get("order_id")
r = await client.arena.place_order(cfg.team, "sell", cfg.order_size, price=ask_px, post_only=True)
ask_id = r.get("order_id")
print(f"Mid=${mid:.2f} Bid=${bid_px:.2f} Ask=${ask_px:.2f}")
await asyncio.sleep(cfg.refresh_sec)
finally:
for oid in (bid_id, ask_id):
if oid:
with contextlib.suppress(Exception):
await client.arena.cancel_order(oid)
asyncio.run(run_mm())
4. Momentum Bot
async with EventTrader.production(api_key="evt_...") as client:
state = await client.arena.market()
blue_pnl = state["blue_team"]["epoch_pnl_pct"]
red_pnl = state["red_team"]["epoch_pnl_pct"]
if blue_pnl > red_pnl and blue_pnl > 0:
team = "BLUE"
elif red_pnl > blue_pnl and red_pnl > 0:
team = "RED"
else:
print("No momentum signal"); exit()
book = await client.arena.orderbook(team, levels=1)
price = float(book["best_ask"])
order = await client.arena.place_order(team, "buy", 10.0, price=price)
print(f"Momentum: {team} buy $10 @ ${price:.2f} -> {order['status']}")
5. Epoch Watcher
async with EventTrader.production(api_key="evt_...") as client:
last = None
while True:
ep = await client.arena.current_epoch()
data = ep.get("epoch")
if data:
num = data["epoch_number"]
if last and num != last:
result = await client.arena.epoch_result(last)
print(f"Epoch #{last} resolved: {result['winning_symbol']} wins!")
last = num
await asyncio.sleep(30)
Rate Limits
Rate limit headers returned on every response:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 97
X-RateLimit-Reset: 1712073600
Key Concepts
Paper vs Live Trading Mode
Trading mode is determined server-side by the user's simulation_mode flag — not by request parameters. All new accounts start in paper mode.
Paper Mode (Default)
Tracks positions and P&L without real funds. All orders return "mode": "paper". Positions tagged is_live: false. No USDC balance required.
Live Mode
Real USDC debited/credited via internal ledger. Requires verified balance. Epoch loss limit: $500/epoch. Position is_live flag locked at creation — prevents paper-to-live exploit.
Authorization: Bearer YOUR_TOKEN for all trading endpointsUser.simulation_mode boolean in database — client cannot overrideArenaPosition.is_live set once at creation, never changes