Agent Zero Integration
Drop skill.md into Agent Zero for instant trading capability, or add typed SDK tool wrappers
This guide shows you how to connect AgentExchange to an Agent Zero agent in under 10 minutes. Agent Zero reads skill files — plain-text Markdown instruction files — to extend an LLM agent's knowledge and capabilities. Drop docs/skill.md into Agent Zero's skill directory and your agent instantly knows how to trade on a simulated crypto exchange backed by real-time Binance prices.
What You Get
After following this guide your Agent Zero agent will be able to:
- Fetch live prices for any of 600+ Binance trading pairs
- Place, monitor, and cancel market / limit / stop-loss / take-profit orders
- Read account balances, open positions, and portfolio summary
- Pull performance analytics (Sharpe ratio, drawdown, win rate)
- Stream real-time prices over WebSocket
- Reset its trading session to restart a strategy cleanly
All on simulated funds backed by real Binance market data.
Prerequisites
| Requirement | Version |
|---|---|
| Python | 3.10+ |
| Agent Zero | latest (git clone https://github.com/frdel/agent-zero) |
| AgentExchange server | running (see quickstart) |
| AgentExchange Python SDK | optional but recommended (pip install agentexchange) |
docker compose up -d
curl http://localhost:8000/health
# {"status":"ok"}
Step 1 — Register an Account
curl -s -X POST http://localhost:8000/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"display_name": "MyAgentZeroBot", "starting_balance": "10000.00"}'
Store credentials in .env:
AGENTEXCHANGE_API_KEY=ak_live_...
AGENTEXCHANGE_API_SECRET=sk_live_...
AGENTEXCHANGE_BASE_URL=http://localhost:8000
AGENTEXCHANGE_WS_URL=ws://localhost:8000
Step 2 — Drop the Skill File Into Agent Zero
docs/skill.md is the canonical LLM-readable instruction file for AgentExchange. It contains the full API reference, authentication instructions, error codes, and trading workflows in plain Markdown.
# From the agent-exchange repo root
cp docs/skill.md /path/to/agent-zero/skills/agentexchange.mdThe symlink stays in sync when skill.md is updated:
ln -s "$(pwd)/docs/skill.md" /path/to/agent-zero/skills/agentexchange.mdIf your AgentExchange instance is deployed, configure Agent Zero to fetch the skill file from the server:
{
"skills": [
{
"name": "agentexchange",
"url": "https://your-deployed-host/docs/skill.md"
}
]
}After placing the file, restart Agent Zero so it picks up the new skill on its next context-building pass.
Step 3 — Inject Credentials Into the Agent Context
The skill file instructs the agent to include X-API-Key: YOUR_API_KEY on every request. Supply the actual key at runtime.
import os
from python.helpers.dotenv import load_dotenv
import agent
load_dotenv()
a = agent.AgentContext.get(0)
a.system_note(
"AgentExchange credentials:\n"
f" API Key: {os.environ['AGENTEXCHANGE_API_KEY']}\n"
f" Base URL: {os.environ['AGENTEXCHANGE_BASE_URL']}\n"
"Always include `X-API-Key: <your key>` on every HTTP request to AgentExchange.\n"
"Never expose the api_secret in responses or tool outputs."
)Add the following block to Agent Zero's system prompt template (prompts/default/agent.system.md):
## AgentExchange Trading Platform
You have access to a simulated cryptocurrency exchange via the AgentExchange skill.
- Base URL: {{env.AGENTEXCHANGE_BASE_URL}}
- API Key: {{env.AGENTEXCHANGE_API_KEY}}
- Always include header: `X-API-Key: {{env.AGENTEXCHANGE_API_KEY}}` on every request.
- All quantity and price values must be decimal strings (e.g. `"0.01"`, not `0.01`).
- Check your balance before every order. Set a stop-loss after every new position.Step 4 — Run the Agent
Start Agent Zero normally and send trading prompts:
from run_ui import app # or run_cli for terminal mode
app.run(debug=False)
Then send a message in the Agent Zero UI or CLI:
One-shot task:
Check the current BTC price and buy 0.01 BTC if it's below $65,000.
Then set a stop-loss at $62,000.
Multi-step strategy:
You are a momentum trading bot.
1. Scan all prices and find the coin with the highest 24-hour percentage gain.
2. Check my available USDT balance.
3. Buy $500 worth of that coin at market price.
4. Immediately set a stop-loss at -5% of the entry price.
5. Set a take-profit at +10% of the entry price.
6. Report every action taken and the final positions.
Autonomous loop:
Every 10 minutes:
1. Call GET /account/portfolio and report total equity and ROI.
2. If any position has unrealized PnL > 15%, sell half of it to lock in profit.
3. If total equity has dropped below 90% of starting balance, cancel all open orders and hold cash.
4. Log what you did each cycle.
Agent Zero reads the skill file, constructs the correct HTTP calls with your injected API key, and executes the strategy step by step.
Step 5 — Add SDK Tools (Optional, Recommended)
For tighter integration — typed responses, automatic retries, rate-limit handling — register Python functions backed by the AgentExchange SDK as Agent Zero tools. This is more robust than letting the LLM construct raw HTTP calls.
Install the SDK:
pip install -e sdk/
Create a tool file at python/tools/agentexchange_tools.py:
"""AgentExchange trading tools for Agent Zero."""
import os
from decimal import Decimal
from typing import Any
from python.helpers.tool import Tool, Response
from agentexchange import AgentExchangeClient
from agentexchange.exceptions import (
AgentExchangeError,
InsufficientBalanceError,
RateLimitError,
InvalidSymbolError,
DailyLossLimitError,
)
_client: AgentExchangeClient | None = None
def _get_client() -> AgentExchangeClient:
global _client
if _client is None:
_client = AgentExchangeClient(
api_key=os.environ["AGENTEXCHANGE_API_KEY"],
api_secret=os.environ["AGENTEXCHANGE_API_SECRET"],
base_url=os.environ.get("AGENTEXCHANGE_BASE_URL", "http://localhost:8000"),
)
return _client
class GetPrice(Tool):
"""Get the current price of a trading pair, e.g. BTCUSDT."""
async def execute(self, symbol: str = "", **kwargs: Any) -> Response:
try:
price = _get_client().get_price(symbol.upper())
return Response(
message=f"{price.symbol}: ${price.price} (as of {price.timestamp.isoformat()})",
break_loop=False,
)
except InvalidSymbolError:
return Response(
message=f"Unknown symbol '{symbol}'. Call list_pairs to see valid symbols.",
break_loop=False,
)
except AgentExchangeError as exc:
return Response(message=f"AgentExchange error: {exc}", break_loop=False)
class GetBalance(Tool):
"""Get account balances for all assets."""
async def execute(self, **kwargs: Any) -> Response:
try:
balance = _get_client().get_balance()
lines = [f"Total equity: ${balance.total_equity_usdt}"]
for b in balance.balances:
lines.append(f" {b.asset}: available={b.available} total={b.total}")
return Response(message="\n".join(lines), break_loop=False)
except AgentExchangeError as exc:
return Response(message=f"AgentExchange error: {exc}", break_loop=False)
class PlaceOrder(Tool):
"""Place a market, limit, stop_loss, or take_profit order.
Args:
symbol: Trading pair, e.g. BTCUSDT
side: buy or sell
order_type: market | limit | stop_loss | take_profit
quantity: Decimal string, e.g. "0.01"
price: Required for limit orders (decimal string)
trigger_price: Required for stop_loss / take_profit (decimal string)
"""
async def execute(
self,
symbol: str = "",
side: str = "",
order_type: str = "market",
quantity: str = "0",
price: str = "",
trigger_price: str = "",
**kwargs: Any,
) -> Response:
try:
extra: dict[str, Any] = {}
if price:
extra["price"] = Decimal(price)
if trigger_price:
extra["trigger_price"] = Decimal(trigger_price)
order = _get_client().place_order(
symbol=symbol.upper(), side=side.lower(),
order_type=order_type.lower(), quantity=Decimal(quantity), **extra,
)
msg = (
f"Order {order.order_id} → {order.status}\n"
f" Executed price: {order.executed_price or 'pending'}\n"
f" Slippage: {order.slippage_pct or 'N/A'}%"
)
return Response(message=msg, break_loop=False)
except InsufficientBalanceError:
return Response(
message="Insufficient balance. Call get_balance to check available funds and reduce quantity.",
break_loop=False,
)
except RateLimitError as exc:
wait = getattr(exc, "retry_after", 60)
return Response(message=f"Rate limit hit. Wait {wait} seconds before retrying.", break_loop=False)
except DailyLossLimitError:
return Response(
message="Daily loss limit reached. No new orders until 00:00 UTC.",
break_loop=False,
)
except AgentExchangeError as exc:
return Response(message=f"Order failed: {exc}", break_loop=False)
class GetPortfolio(Tool):
"""Get full portfolio summary including total equity, PnL, and ROI."""
async def execute(self, **kwargs: Any) -> Response:
try:
pf = _get_client().get_portfolio()
msg = (
f"Portfolio summary:\n"
f" Total equity: ${pf.total_equity}\n"
f" Available cash: ${pf.available_cash}\n"
f" Unrealized PnL: ${pf.unrealized_pnl}\n"
f" Realized PnL: ${pf.realized_pnl}\n"
f" ROI: {pf.roi_pct}%"
)
return Response(message=msg, break_loop=False)
except AgentExchangeError as exc:
return Response(message=f"AgentExchange error: {exc}", break_loop=False)
class GetPerformance(Tool):
"""Get performance metrics: Sharpe ratio, win rate, max drawdown.
Args:
period: 1d | 7d | 30d | all (default: all)
"""
async def execute(self, period: str = "all", **kwargs: Any) -> Response:
try:
perf = _get_client().get_performance(period=period)
msg = (
f"Performance ({period}):\n"
f" Sharpe ratio: {perf.sharpe_ratio}\n"
f" Win rate: {perf.win_rate}%\n"
f" Max drawdown: {perf.max_drawdown_pct}%\n"
f" Total trades: {perf.total_trades}\n"
f" Profit factor: {perf.profit_factor}"
)
return Response(message=msg, break_loop=False)
except AgentExchangeError as exc:
return Response(message=f"AgentExchange error: {exc}", break_loop=False)
Register the tools in Agent Zero's config (initialize.py):
from python.tools.agentexchange_tools import (
GetPrice, GetBalance, PlaceOrder, GetPortfolio, GetPerformance,
)
tools = [
# ... existing Agent Zero tools ...
GetPrice(agent, name="get_price", args={"symbol": "str"}, message=""),
GetBalance(agent, name="get_balance", args={}, message=""),
PlaceOrder(
agent, name="place_order",
args={"symbol": "str", "side": "str", "order_type": "str",
"quantity": "str", "price": "str", "trigger_price": "str"},
message="",
),
GetPortfolio(agent, name="get_portfolio", args={}, message=""),
GetPerformance(agent, name="get_performance", args={"period": "str"}, message=""),
]
Step 6 — Add WebSocket Streaming
For agents that need to react to live price changes rather than polling:
# python/tools/agentexchange_ws.py
import os
import threading
from agentexchange import AgentExchangeWS
latest_prices: dict[str, str] = {}
latest_order_updates: list[dict] = []
ws = AgentExchangeWS(
api_key=os.environ["AGENTEXCHANGE_API_KEY"],
base_url=os.environ.get("AGENTEXCHANGE_WS_URL", "ws://localhost:8000"),
)
@ws.on_ticker("BTCUSDT")
def on_btc(msg: dict) -> None:
latest_prices["BTCUSDT"] = msg["data"]["price"]
@ws.on_ticker("ETHUSDT")
def on_eth(msg: dict) -> None:
latest_prices["ETHUSDT"] = msg["data"]["price"]
@ws.on_order_update()
def on_order(msg: dict) -> None:
data = msg["data"]
latest_order_updates.append(data)
if len(latest_order_updates) > 100:
latest_order_updates.pop(0)
def start_ws_feed() -> None:
thread = threading.Thread(target=ws.run_forever, daemon=True)
thread.start()
Add a GetStreamedPrice tool:
from python.helpers.tool import Tool, Response
from python.tools.agentexchange_ws import latest_prices, start_ws_feed
from typing import Any
start_ws_feed() # call once at startup
class GetStreamedPrice(Tool):
"""Get the most recently streamed price (faster than HTTP polling).
Args:
symbol: Trading pair, e.g. BTCUSDT
"""
async def execute(self, symbol: str = "", **kwargs: Any) -> Response:
sym = symbol.upper()
price = latest_prices.get(sym)
if not price:
return Response(
message=f"No streamed price yet for {sym}. Use get_price instead.",
break_loop=False,
)
return Response(message=f"{sym}: ${price} (WebSocket, real-time)", break_loop=False)
Configuration Reference
Recommended system prompt additions
Add to prompts/default/agent.system.md:
## AgentExchange Simulated Trading
You have access to AgentExchange — a simulated crypto exchange backed by real-time Binance data.
- Base URL: http://localhost:8000/api/v1
- Auth header: X-API-Key: <injected at runtime>
### Rules before placing any order
1. Call `get_balance` to confirm you have enough available USDT.
2. Check `get_price` for the current price; do not rely on a price older than 30 seconds.
3. After filling a market order, immediately place a stop-loss.
4. Never risk more than 10% of total equity on a single trade.
5. All quantity and price values must be decimal strings: `"0.01"`, not `0.01`.
### When things go wrong
- `INSUFFICIENT_BALANCE` → call `get_balance`, reduce quantity, retry.
- `RATE_LIMIT_EXCEEDED` → wait for X-RateLimit-Reset, then retry.
- `DAILY_LOSS_LIMIT` → stop trading, report status, wait until 00:00 UTC.
- `INVALID_SYMBOL` → call `GET /market/pairs` to find the correct symbol.
- `PRICE_NOT_AVAILABLE` → wait 3 seconds and retry.
Required environment variables
| Variable | Description |
|---|---|
AGENTEXCHANGE_API_KEY | Your ak_live_... key from registration |
AGENTEXCHANGE_API_SECRET | Your sk_live_... secret (needed only by the SDK) |
AGENTEXCHANGE_BASE_URL | REST base URL, e.g. http://localhost:8000 |
AGENTEXCHANGE_WS_URL | WebSocket base URL, e.g. ws://localhost:8000 |
Error Handling
| Error Code | Recommended Agent Behavior |
|---|---|
INSUFFICIENT_BALANCE | Call get_balance, reduce order quantity, retry |
RATE_LIMIT_EXCEEDED | Read X-RateLimit-Reset, wait until that timestamp, retry |
DAILY_LOSS_LIMIT | Stop placing orders; wait until 00:00 UTC |
INVALID_SYMBOL | Call GET /market/pairs to find the correct symbol |
INVALID_QUANTITY | Check min_qty and step_size for the pair |
ORDER_REJECTED | Check position limits and open order count |
PRICE_NOT_AVAILABLE | Retry after 2–3 seconds |
INTERNAL_ERROR | Retry with exponential back-off: 1s → 2s → 4s → 8s → max 60s |
Troubleshooting
Skill file not being read by Agent Zero
- Confirm the file extension is
.md - Restart Agent Zero after adding the file
- Check Agent Zero logs for skill loading errors
PRICE_NOT_AVAILABLE on startup
- The Binance ingestion service needs ~30 seconds after a cold start. Wait and retry.
Agent constructs malformed request bodies
- Add to the system prompt: "All quantity and price fields must be decimal strings, e.g.
"0.01", never bare numbers." - Use the SDK tool wrappers from Step 5 — they handle serialization automatically.
Next Steps
- LangChain Guide — typed LangChain
Toolwrappers - CrewAI Guide — multi-agent crew setup
- OpenClaw Guide —
@openclaw.toolSDK wrappers - SDK Reference — full method list
- API Reference — direct REST endpoint documentation