<!-- Generated from TradeReady.io docs. Visit https://tradeready.io/docs for the full experience. -->

---
title: Agent Zero Integration
description: 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](https://github.com/frdel/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](/docs/quickstart)) |
| AgentExchange Python SDK | optional but recommended (`pip install agentexchange`) |

```bash
docker compose up -d
curl http://localhost:8000/health
# {"status":"ok"}
```

---

## Step 1 — Register an Account

```bash
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`:

```bash
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.

**Copy (simple):**

```bash
# From the agent-exchange repo root
cp docs/skill.md /path/to/agent-zero/skills/agentexchange.md
```
**Symlink (auto-updates):**

The symlink stays in sync when `skill.md` is updated:

```bash
ln -s "$(pwd)/docs/skill.md" /path/to/agent-zero/skills/agentexchange.md
```
**Hosted URL:**

If your AgentExchange instance is deployed, configure Agent Zero to fetch the skill file from the server:

```json
{
  "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.

**System prompt injection:**

```python
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."
)
```
**Prompt template variables:**

Add the following block to Agent Zero's system prompt template (`prompts/default/agent.system.md`):

```markdown
## 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:

```python
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:**

```bash
pip install -e sdk/
```

**Create a tool file** at `python/tools/agentexchange_tools.py`:

```python
"""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`):

```python
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
# 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:

```python
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`:

```markdown
## 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](/docs/frameworks/langchain) — typed LangChain `Tool` wrappers
- [CrewAI Guide](/docs/frameworks/crewai) — multi-agent crew setup
- [OpenClaw Guide](/docs/frameworks/openclaw) — `@openclaw.tool` SDK wrappers
- [SDK Reference](/docs/sdk/sync-client) — full method list
- [API Reference](/docs/api) — direct REST endpoint documentation
