🤖 🤺 The Agents Trading Arena
A multi-agent crypto trading arena where AI agents compete against each other, trading with live crypto market data from Coinbase or Binance. Each agent consumes a livestream of ticker data and standard candlestick charts, has access to its portfolio and calculator, and executes trades autonomously.
🐮 Built on calfkit
-
The Agents Trading Arena is built on 🐮 calfkit, the SDK for highly-connected, event-driven, and scalable agents.
-
Want to build your own multi-agent system? Start with the calfkit quickstart and examples.
Architecture
Live market data
(Coinbase / Binance — WebSocket + REST)
│
▼
┌─────────────────────────────────────────────┐
│ Exchange connector │
│ (live-market-data proxy) │
└─────────────────────────────────────────────┘
│ │
live prices market snapshots
▼ ▼
┌────────────────────────────┐ ┌────────────────────────────┐
│ Tools & Dashboard │ │ Agent process × N │
│ paper wallets · tools │◀─▶│ embedded LLM + strategy │
│ live dashboard (Rich) │ │ agent 1 … agent N │
└────────────────────────────┘ └────────────────────────────┘
tool calls ⇄ tool results
A single exchange connector turns the live market into a continuous event stream that the agents and the Tools process consume in realtime. Each agent reacts on every update — reasoning over the latest prices and candlesticks to decide whether to buy, sell, or hold. The Tools & Dashboard process consumes the same stream to keep its price book current, so trades fill and the dashboard marks against up-to-the-moment prices. Agents act by calling tools (trade, portfolio, calculator), forming a tight loop: market event → decision → trade → updated state.
Key design points:
- Connector as market-data proxy: One process owns the exchange link and fans the feed out, so neither agents nor tools touch the exchange directly.
- Per-agent model selection: Each agent embeds its own model client, so different agents can use different LLMs with different providers.
- Fan-out: Every agent independently receives every market-data update, with no replicated work.
- Shared tools via ToolContext: A single deployed set of trading tools serves all agents — each tool resolves the calling agent's identity at runtime.
- Dynamic agent accounts: Agents appear on the dashboard automatically on their first trade — no pre-registration needed.
Prerequisites
- Python 3.10+
- uv — fast Python package manager
- Docker installed and running (in order to run a kafka broker)
- An API key (and optionally base url) for your LLM provider
1. Install uv
If you don't have uv installed:
# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
# Or via Homebrew
brew install uv
After installation, restart your terminal.
2. Install the Calfkit SDK
Calfkit is the event-stream SDK that powers this project — it handles the agents' realtime stream consumption and orchestration. It's already a pinned dependency (calfkit>=0.12.6,<0.13 in pyproject.toml), installed along with everything else by uv sync in the Quickstart below.
3. Start the Broker
The broker orchestrates all nodes and enables realtime data streaming between all components.
Option A: Local broker setup (Docker required)
Run the following to clone the calfkit-broker repo and start a local Kafka broker container:
git clone https://github.com/calf-ai/calfkit-broker && cd calfkit-broker && make dev-up
Once the broker is ready, open a new terminal tab to continue with the quickstart. The default broker address is localhost:9092.
Option B: Calfkit cloud broker
There's also a cloud broker version so you can simply use the cloud broker URL (which would be provided to you) to deploy your agents instead of setting up and maintaining a broker locally.
Quickstart
Clone the repo and install dependencies:
git clone https://github.com/ryan-yuuu/crypto-trading-arena && cd crypto-trading-arena
uv sync
Add your LLM provider's API key:
cp .env.example .env # then edit .env and set your provider's API key
Then launch each component in its own terminal. All components connect to the same broker (localhost:9092 for the local broker from step 3, or your cloud broker URL).
1. Start the exchange connector
Start either the Coinbase or Binance connector to stream live market data:
# Coinbase (default)
uv run python -m exchanges.coinbase --bootstrap-servers <broker-url>
# Or, Binance (experimental)
# uv run python -m exchanges.binance --bootstrap-servers <broker-url>
Optional: You can use the --min-interval <seconds> flag which controls how often agents are fed market data (default: 60s). Note that candle data is only updated every 60 seconds due to Coinbase API restrictions, so intervals below a minute mean agents will receive updated live pricing (bid/ask spread, ~5s granularity) but the same candle data.
2. Deploy tools & dashboard
uv run python -m deploy.tools_and_dashboard --bootstrap-servers <broker-url>
3. Deploy agents
Deploy an agent with an embedded model client and a trading strategy. Each agent runs its own LLM inference. See arena/strategies.py for the full system prompts.
# OpenAI model
uv run python -m deploy.agent \
--name <unique-agent-name> --model-id <openai-model-id> \
--strategy <strategy> --bootstrap-servers <broker-url>
# Or, any OpenAI-compatible provider (e.g. DeepInfra, OpenRouter, etc.)
# uv run python -m deploy.agent \
# --name <unique-agent-name> --model-id <model-id> \
# --base-url <llm-provider-base-url> --api-key <api-key> \
# --strategy <strategy> --bootstrap-servers <broker-url>
# Or, load agent config from config.json
# uv run python -m deploy.agent \
# --from-config <agent-name> --strategy <strategy> \
# --bootstrap-servers <broker-url>
Once agents are deployed, market data flows to them and trades should hydrate the dashboard soon.
4. (Optional) Start the response viewer
A live dashboard that shows all agent activity, such as tool calls, text responses (agent reasoning), and tool results, as they happen.
uv run python -m deploy.response_viewer --bootstrap-servers <broker-url>
Data Recording
All trades and periodic portfolio snapshots are automatically saved to CSV files in the data/ directory. Each session produces two files:
trades_<timestamp>.csv— every executed trade with price, quantity, fee charged, and agent cash after settlementsnapshots_<timestamp>.csv— periodic portfolio state per agent, including positions, market values, unrealized and realized P&L, and cumulative fees paid
You can configure the snapshot interval and output directory:
uv run python -m deploy.tools_and_dashboard \
--bootstrap-servers <broker-url> \
--snapshot-interval <default-600-seconds> \
--data-dir ./data
To disable recording entirely, pass --snapshot-interval 0.
For full column descriptions and examples, see docs/csv-data-recording.md.
CLI Reference & Config-Based Deployments
For full CLI flags, config-based deployment options, and the config schema, see CLI_REFERENCE.md.
Testing
The suite separates fast, deterministic tests from ones that need external resources:
# Fast unit + in-memory tests (what CI runs on every PR). No broker, no API key.
uv run pytest -m "not llm and not broker"
# Broker integration tests against a real Redpanda broker (needs Docker; a
# container is started automatically via testcontainers).
uv run pytest -m broker --run-broker
# Live LLM tests (needs OPENAI_API_KEY); a bare `uv run pytest` includes these.
uv run pytest -m llm
Markers: llm (live inference call) and broker (live Kafka-API broker, opt-in via
--run-broker). CI (.github/workflows/ci.yml) runs lint, the non-LLM unit tests on
Python 3.10–3.12, and the Redpanda broker job. Known-but-unfixed issues are tracked as
strict xfails; see docs/REVIEW_FINDINGS.md.
Available Agent Tools
| Tool | Description |
|---|---|
execute_trade | Buy or sell a crypto product at the current market price. A configurable taker fee is charged on every fill (see trading.fees.taker_bps below) |
get_portfolio | View cash, open positions, cost basis (fee-inclusive), P&L, and average time held |
calculator | Evaluate math expressions for position sizing, P&L calculations, etc. |
Deployment Configurations
| File | Constant | Default | Description |
|---|---|---|---|
arena/models.py | INITIAL_CASH | 100_000.0 | Starting cash balance per agent |
exchanges/coinbase.py | DEFAULT_PRODUCTS | 3 products | Coinbase products tracked by the price feed |
exchanges/binance.py | DEFAULT_SYMBOLS | 3 symbols | Binance symbols tracked by the price feed |
config.json | trading.fees.taker_bps | 60 | Taker fee in basis points charged on every simulated fill (both buys and sells). 60 ≈ Coinbase Advanced Trade base tier; 10 ≈ Binance global VIP 0; 40 ≈ Kraken Pro; 0 disables. Read by both the tools node (which charges the fee) and the price-feed connector (which advertises it to agents). |
License
Built on 🐮 calfkit — the SDK for highly-connected, event-driven, and scalable agents.
Building your own multi-agent system? Start with the calfkit quickstart · ⭐ star the repo