Backtest API & SDK
Run strategy backtests, browse the bot leaderboard, clone bots, and paper trade — all via API.
Quick Start
# Run a funding rate backtest
curl -X POST https://cymetica.com/api/v1/backtest-labs/run \
-H "Content-Type: application/json" \
-d '{"type":"funding_rate","params":{"coin":"BTC","days":30,"capital":10000,"leverage":1,"strategy":"cross_exchange"}}'
# Get bot leaderboard
curl https://cymetica.com/api/v1/backtest/leaderboard?sort=return&limit=10
from event_trader import EventTrader
client = EventTrader(api_key="evt_...")
# Run a backtest
result = await client.backtest.run_lab(
type="funding_rate",
params={"coin": "BTC", "days": 30, "capital": 10000}
)
# Get leaderboard
leaderboard = await client.backtest.leaderboard(sort="return", limit=10)
# Get bot profile
bot = await client.backtest.bot("cryptobull-blue")
The JS/TS SDK's npm release is in progress — these snippets show the interface it ships with. The Python SDK and the REST API are live today.
import { EventTrader } from "cymetica-eventtrader";
const client = new EventTrader({ apiKey: "evt_..." });
// Run a backtest
const result = await client.backtest.runLab({
type: "funding_rate",
params: { coin: "BTC", days: 30, capital: 10000 }
});
// Get leaderboard
const leaderboard = await client.backtest.leaderboard({ sort: "return", limit: 10 });
// Get bot profile
const bot = await client.backtest.bot("cryptobull-blue");
# Python
pip install cymetica-eventtrader
# TypeScript / Node.js — npm release in progress; Python SDK is live today
# npm install cymetica-eventtrader
Authentication
Most read endpoints are public (no auth required). Write operations use one of two methods depending on the endpoint family: Backtest Labs runs (/api/v1/backtest-labs/*) authenticate with an API key (X-API-Key header), while bot management (clone, trigger run, update settings) requires a Bearer token from a logged-in session.
# Authenticated request
curl -H "Authorization: Bearer $EVENTTRADER_API_KEY" \
https://cymetica.com/api/v1/backtest/bots/your-bot-slug/run-backtest
Get your API key from /account → API Keys.
Which backtest surface?
Five surfaces, all current, each answering a different question. None supersedes another. The machine-readable spec of record is openapi-public.json, llms.txt and the MCP tools list_backtest_surfaces / get_backtest_models; this page mirrors them.
| Page | Answers | API | Auth |
|---|---|---|---|
| /backtest | How has a specific clone-able bot performed, and can I clone it? | GET /api/v1/backtest/bots/{slug}, /equity, /trades, GET /api/v1/backtest/leaderboard, POST /api/v1/backtest/clone | reads: none · writes: Bearer |
| /backtest-labs | What would one parameterised strategy have returned on one asset? | POST /api/v1/backtest-labs/run — type: cross_exchange_arb | funding_rate | dex_replay | X-API-Key |
| /backtest-rally | Which theme basket beat BTC under a research model, then launch it as a rally card? | GET /api/v1/research-backtest/models, /themes, POST /api/v1/research-backtest/run, GET /runs, /runs/{run_id}, /queue, /leaderboard | none (30/min per IP; 2 in-flight runs per anonymous IP, 5 per account) |
| /events/builder | Would an event-card idea have paid off historically? | POST /api/v1/event-cards/backtest-idea | none (30/min per IP) |
| /macromarket | Build an AI Index Basket from a macro theme, backtest and paper-trade it. | POST /api/v1/macromarket/build, /backtest, /paper-trade | Bearer |
Backtest Labs
Run one parameterised strategy on one asset. Accepted type values: cross_exchange_arb (cross-exchange arbitrage), funding_rate (perp funding-rate capture) and dex_replay (DEX trade replay with params.strategy = mean_reversion | momentum | lp_vs_hold). Any other type returns {"error":"Unknown backtest type. Supported: cross_exchange_arb, funding_rate, dex_replay"}. Max 20 concurrent backtests via Redis queue.
Request Body
cross_exchange_arb, funding_rate, dex_replay (for dex_replay, params.strategy = mean_reversion | momentum | lp_vs_hold)cross_exchange)curl -X POST https://cymetica.com/api/v1/backtest-labs/run \
-H "Content-Type: application/json" \
-d '{
"type": "funding_rate",
"params": {
"coin": "BTC",
"days": 30,
"capital": 10000,
"leverage": 1,
"strategy": "cross_exchange"
}
}'
result = await client.backtest.run_lab(
type="funding_rate",
params={"coin": "BTC", "days": 30, "capital": 10000, "leverage": 1, "strategy": "cross_exchange"}
)
const result = await client.backtest.runLab({
type: "funding_rate",
params: { coin: "BTC", days: 30, capital: 10000, leverage: 1, strategy: "cross_exchange" }
});
Multi-Leg Backtesting — Baskets, AIBs and Themes
Backtest Labs above runs a strategy against one asset. To backtest a
basket — several legs with weights — use the endpoints below.
Basket symbols (AIB-, TREND-, EVCDX-,
RALLY-, MM-) are not accepted by the single-asset endpoints.
All results describe the past and are never a predicted return.
The API behind the “Backtest this idea” widget on /events/builder. Read-only: no card is created, no ledger or on-chain write happens, no money moves. Runs the same engine as the saved-card backtest, so an idea and a published card holding the same basket return identical numbers.
Request Body
{symbol, weight} (optional coingecko_id). Weights are relative and renormalized, so 50/30/20 equals 5/3/2.7, 30, 90, 180, 365. Anything else returns 422.Response
ending_capital_usdcnumberSimulated capital at each end of the window.
n_points).dropped_symbolsarrayLegs that could not be priced and were excluded. Always check these before trusting the numbers.
curl -X POST https://cymetica.com/api/v1/event-cards/backtest-idea \
-H "Content-Type: application/json" \
-d '{
"constituents": [
{"symbol": "BTC", "weight": 50},
{"symbol": "ETH", "weight": 30},
{"symbol": "SOL", "weight": 20}
],
"period_days": 90,
"starting_capital": 10000
}'
result = await client.basket_backtest.run(
constituents=[("BTC", 50), ("ETH", 30), ("SOL", 20)],
period_days=90,
starting_capital=10_000,
)
print(result["total_return_pct"], result["sharpe_ratio"])
print(result["unresolved_symbols"], result["dropped_symbols"])
const result = await client.basketBacktest.run({
constituents: [
{ symbol: "BTC", weight: 50 },
{ symbol: "ETH", weight: 30 },
{ symbol: "SOL", weight: 20 },
],
periodDays: 90,
startingCapital: 10000,
});
console.log(result.total_return_pct, result.sharpe_ratio);
et_basket_backtest(
constituents=[
{"symbol": "BTC", "weight": 50},
{"symbol": "ETH", "weight": 30},
{"symbol": "SOL", "weight": 20}
],
period_days=90,
starting_capital=10000
)
Give it a plain-language theme and the Tuatara semantic model selects real
trading vehicles (stocks, ETFs, crypto) and weights them by relevance. The basket
gets an MM-… symbol and a /macromarket page.
Request Body
"AI infrastructure".tuatara (relevance-weighted) or equal.crypto, equity. Omit for both.curl -X POST https://cymetica.com/api/v1/macromarket/build \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $EVENTTRADER_API_KEY" \
-d '{"theme": "AI infrastructure", "num_assets": 8, "weighting": "tuatara"}'
aib = await client.macromarket.build("AI infrastructure", num_assets=8)
print(aib["symbol"]) # e.g. "MM-AIINFRA"
const aib = await client.macromarket.build({
theme: "AI infrastructure",
numAssets: 8,
});
et_aib_build(theme="AI infrastructure", num_assets=8, weighting="tuatara")
Pass aib_symbol for an existing basket, or theme to build
and persist one first. Quota-gated: an over-quota caller gets 402
before any expensive work runs. Results are simulated, not investment advice.
Request Body
MM-… symbol. Required unless theme is given.curl -X POST https://cymetica.com/api/v1/macromarket/backtest \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $EVENTTRADER_API_KEY" \
-d '{"aib_symbol": "MM-AIINFRA", "period_days": 365}'
bt = await client.macromarket.backtest(aib_symbol="MM-AIINFRA", period_days=365)
# Or skip the build entirely and backtest a theme directly:
bt = await client.macromarket.backtest(theme="uranium miners")
const bt = await client.macromarket.backtest({
aibSymbol: "MM-AIINFRA",
periodDays: 365,
});
et_aib_backtest(aib_symbol="MM-AIINFRA", period_days=365)
et_aib_backtest(theme="uranium miners")
The headline-basket research engine behind /backtest-rally. Races strategies against BTC and can launch the winner as a Rally Card. Signal/backtest only — no orders are placed. Full reference: /backtest-rally/api.
curl -X POST https://cymetica.com/api/v1/research-backtest/run \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $EVENTTRADER_API_KEY" \
-d '{"themes": ["ai tokens"], "algo_model": "aib_sentiment", "hold_days": 2}'
run = await client.research_backtest.run(
themes=["defi tokens", "ai tokens"], hold_days=2)
result = await client.research_backtest.get(run["run_id"])
await client.research_backtest.launch_rally_card(run["run_id"], basket_index=0)
const run = await client.researchBacktest.run({
themes: ["defi tokens", "ai tokens"],
params: { hold_days: 2 },
});
const result = await client.researchBacktest.get(run.run_id);
et_research_backtest_run(params={"themes": ["ai tokens"], "hold_days": 2})
et_research_backtest_launch_rally_card(run_id="<run_id>", basket_index=0)
Bot Leaderboard
Browse ranked AI trading bots with sorting and filtering. 60-second cache on leaderboard results.
Query Parameters
return (headline return, desc), clones, win_rate, drawdown (asc). Default: return. Unknown values fall back to return.all, crypto, politics, sports, finance (default: all)all, red, blue30d, 6m, 24h (default: all). headline_return_pct is measured over each bot's own window and is NOT comparable across periods, so rank within one. Every row carries headline_period and headline_period_hours.curl "https://cymetica.com/api/v1/backtest/leaderboard?sort=return&team=red&period=30d&limit=10"
leaderboard = await client.backtest.leaderboard(sort="return", team="red", limit=10)
const lb = await client.backtest.leaderboard({ sort: "return", team: "red", limit: 10 });
Bot Profiles
Get bot details, equity curves, and trade history. 60-second cache on profile data.
Path Parameters
curl https://cymetica.com/api/v1/backtest/bots/cryptobull-blue
Returns time-series equity data for charting the bot's portfolio value over time.
curl https://cymetica.com/api/v1/backtest/bots/cryptobull-blue/equity
Query Parameters
curl "https://cymetica.com/api/v1/backtest/bots/cryptobull-blue/trades?limit=10"
Bot Operations
Run backtests and update settings. These endpoints require authentication.
Triggers a new backtest run for the specified bot (Bearer token; no request body — the bot's own strategy, top-10 asset universe and a 30-day window are used). Responds immediately with {"run_id", "status": "queued", "slug"}; the refreshed results appear on the bot's profile and the leaderboard when the async run completes. Also callable as the MCP tool et_backtest_bot_run.
curl -X POST https://cymetica.com/api/v1/backtest/bots/your-bot-slug/run-backtest \
-H "Authorization: Bearer $EVENTTRADER_API_KEY"
# 200 → {"run_id": "…", "status": "queued", "slug": "your-bot-slug"}
# then stream progress on wss://cymetica.com/ws/backtest/{instance_id}?run_id={run_id}
Request Body
curl -X PATCH https://cymetica.com/api/v1/backtest/bots/your-bot-slug/settings \
-H "Authorization: Bearer $EVENTTRADER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Alpha Bot v3"}'
Bot Cloning
Clone bot species into new instances. Cloned bots get dedicated HD wallets (account 4 derivation path). Requires authentication.
Request Body
curl -X POST https://cymetica.com/api/v1/backtest/clone \
-H "Authorization: Bearer $EVENTTRADER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"species_slug": "cryptobull-blue", "name": "My Momentum Clone"}'
Returns deposit address and minimum deposit required to activate a cloned bot.
curl https://cymetica.com/api/v1/backtest/clone/deposit-info/cryptobull-blue \
-H "Authorization: Bearer $EVENTTRADER_API_KEY"
Paper Trading
View paper trades and paper trading status for bots running in simulation mode.
Query Parameters
open, closed, allcurl "https://cymetica.com/api/v1/backtest/bots/cryptobull-blue/paper-trades?status=open&limit=20"
Returns current paper trading status including P&L, open positions, and account balance.
curl https://cymetica.com/api/v1/backtest/bots/cryptobull-blue/paper-status
WebSocket — Real-Time Backtest Updates
Stream real-time backtest progress and results via WebSocket.
Message Types
// JavaScript WebSocket example
const ws = new WebSocket("wss://cymetica.com/ws/backtest/bot-123?run_id=run-456");
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
switch (msg.type) {
case "progress":
console.log(`${msg.percent}% — ${msg.step}`);
break;
case "completed":
console.log("Results:", msg.results);
break;
case "failed":
console.error("Error:", msg.error);
break;
}
};
Rate Limits
MCP Tools
Two MCP surfaces. The hosted server at https://cymetica.com/mcp/v1 (JSON-RPC tools/list / tools/call, no install) exposes list_backtest_surfaces, get_backtest_models and get_strategy_returns (accepts cryptobull-blue, cryptobull_blue or bt-cryptobull-blue; returns the latest run's metrics with its measurement period plus the leaderboard headline figure and its window). The installable server (pip install cymetica-eventtrader-mcp) ships the full endpoint mirror below — these et_backtest_* names come from that package.