# AgentBroker Python SDK

[![PyPI version](https://img.shields.io/pypi/v/agentbroker)](https://pypi.org/project/agentbroker/)
[![PyPI downloads](https://img.shields.io/pypi/dm/agentbroker)](https://pypi.org/project/agentbroker/)
[![Python](https://img.shields.io/badge/python-3.8%2B-blue)](https://python.org)
[![License: MIT](https://img.shields.io/badge/License-MIT-green)](LICENSE)

Official Python SDK for [AgentBroker](https://agentbroker.polsia.app) — the crypto trading platform built for autonomous agents.

## Features

- **Full API coverage** — registration, deposits, orders, market data, WebSocket streaming
- **Type hints throughout** — autocomplete-friendly with `dataclass` response models
- **Smart error handling** — typed exceptions for auth failures, insufficient balance, not found, etc.
- **WebSocket helpers** — decorator-style event handlers with auto-reconnect
- **Zero extra dependencies** — only `requests` required; `websocket-client` optional for WS

## Installation

```bash
pip install agentbroker
```

With WebSocket support:

```bash
pip install "agentbroker[ws]"
```

## Quickstart

### 1. Register an agent

```python
from agentbroker import AgentBroker

agent = AgentBroker.register(
    name="my-trading-bot",
    email="me@example.com",
    preferred_pairs=["BTC-USDC", "ETH-USDC"],
)

print(agent.api_key)  # ← save this! it won't be shown again
# ab_live_xxxxxxxxxxxxx
```

> **Sandbox mode** — free 10,000 virtual USDC, no real funds needed:
> ```python
> agent = AgentBroker.register(name="my-bot", mode="sandbox")
> # starts with 10,000 virtual USDC — withdrawals disabled
> ```

### 2. Deposit USDC & trade

```python
client = AgentBroker(api_key="ab_live_xxxxxxxxxxxxx")

# Deposit
client.deposit(amount=1000)

# Choose a strategy
client.select_strategy("momentum")  # "momentum" | "grid" | "mean_reversion"

# Market buy
order = client.place_order(
    pair="BTC-USDC",
    side="buy",
    type="market",
    quantity=0.001,
)
print(f"Order #{order.order_id}: {order.status}")

# Limit sell
order = client.place_order(
    pair="BTC-USDC",
    side="sell",
    type="limit",
    quantity=0.001,
    price=120_000,   # USDC
)
```

### 3. Real-time events via WebSocket

```python
from agentbroker import AgentBroker

client = AgentBroker(api_key="ab_live_xxxxxxxxxxxxx")
ws = client.connect_ws()

@ws.on_trade
def handle_trade(event):
    print(f"Fill! {event['pair']} {event['side']} @ {event['price']}")

@ws.on_balance
def handle_balance(event):
    print(f"Balance updated: {event['balance_usdc']} USDC")

@ws.on_connected
def on_connect():
    print("WebSocket connected ✓")

ws.run_forever()  # blocks — use ws.connect() for background thread
```

## API Reference

### `AgentBroker(api_key, base_url, timeout)`

```python
client = AgentBroker(api_key="ab_live_...", timeout=30)
```

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `api_key` | `str` | `None` | API key (required for authenticated endpoints) |
| `base_url` | `str` | `https://agentbroker.polsia.app` | API base URL |
| `timeout` | `int` | `30` | HTTP timeout in seconds |

---

### Registration

#### `AgentBroker.register(name, email, callback_url, preferred_pairs)` → `Agent`

Register a new agent. Returns `Agent` with `api_key` set.

```python
agent = AgentBroker.register(
    name="arb-bot-v2",
    email="trader@example.com",
    callback_url="https://mybot.example.com/webhooks/trades",
    preferred_pairs=["BTC-USDC", "ETH-USDC", "SOL-USDC"],
)
print(agent.api_key)
```

---

### Account

| Method | Returns | Description |
|--------|---------|-------------|
| `client.get_profile()` | `Agent` | Full profile: balance, strategy, trade count |
| `client.update_profile(callback_url, preferred_pairs)` | `Agent` | Update webhook URL / pairs |
| `client.get_account()` | `Account` | Balance + totals summary |
| `client.get_balance()` | `float` | Current USDC balance |

---

### Deposits & Withdrawals

| Method | Returns | Description |
|--------|---------|-------------|
| `client.deposit(amount, currency, tx_hash)` | `Deposit` | Credit USDC to balance |
| `client.get_deposits()` | `list[Deposit]` | Deposit history |
| `client.withdraw(amount, address)` | `Withdrawal` | Withdraw USDC |
| `client.get_withdrawals()` | `list[Withdrawal]` | Withdrawal history |
| `client.get_balance_history()` | `list[BalanceHistory]` | All balance events |

---

### Strategies

| Method | Returns | Description |
|--------|---------|-------------|
| `client.get_strategies()` | `list[Strategy]` | Available strategies |
| `client.select_strategy(name)` | `dict` | Activate a strategy |

Available strategies: `"momentum"`, `"grid"`, `"mean_reversion"`

---

### Orders

| Method | Returns | Description |
|--------|---------|-------------|
| `client.place_order(pair, side, type, quantity, price)` | `Order` | Place limit or market order |
| `client.get_orders(status, pair, limit)` | `list[Order]` | List orders |
| `client.cancel_order(order_id)` | `dict` | Cancel open order |
| `client.get_trades(pair, limit)` | `list[Trade]` | Executed trades |

```python
# Market buy
order = client.place_order("ETH-USDC", "buy", "market", quantity=0.1)

# Limit sell
order = client.place_order("ETH-USDC", "sell", "limit", quantity=0.1, price=3500)

# List open orders
open_orders = client.get_orders(status="open", pair="BTC-USDC")

# Cancel
client.cancel_order(order.order_id)
```

---

### Market Data *(public, no API key required)*

| Method | Returns | Description |
|--------|---------|-------------|
| `client.get_prices()` | `dict[str, Price]` | All pair prices |
| `client.get_price(pair)` | `Price` | Single pair price |
| `client.get_orderbook(pair)` | `OrderBook` | Bids/asks for a pair |
| `client.get_pairs()` | `list[str]` | Supported trading pairs |

```python
# No API key needed
client = AgentBroker()

prices = client.get_prices()
btc = prices["BTC-USDC"]
print(f"BTC: ${btc.price:,.2f}")

ob = client.get_orderbook("ETH-USDC")
print(f"Best bid: {ob.bids[0].price}, Best ask: {ob.asks[0].price}")

pairs = client.get_pairs()
# ["BTC-USDC", "ETH-USDC", "SOL-USDC", ...]
```

---

### WebSocket

```python
ws = client.connect_ws()

@ws.on_trade
def on_trade(event): ...

@ws.on_balance
def on_balance(event): ...

@ws.on_orderbook
def on_orderbook(event): ...

@ws.on_connected
def on_connected(): ...

@ws.on_disconnect
def on_disconnect(code, msg): ...

@ws.on_error
def on_error(err): ...

# Subscribe / unsubscribe channels at runtime
ws.subscribe("trades")
ws.unsubscribe("orderbook")

# Run in background thread
ws.connect()

# Or block main thread
ws.run_forever()

# Close permanently
ws.close()
```

**Channels:** `"trades"`, `"balance"`, `"orderbook"`

---

### Exceptions

```python
from agentbroker.exceptions import (
    AgentBrokerError,        # Base class
    AuthenticationError,     # 401 — missing/invalid API key
    ValidationError,         # 400 — bad request params
    InsufficientBalanceError,# 400 with code INSUFFICIENT_BALANCE
    NotFoundError,           # 404 — resource not found
    RateLimitError,          # 429 — too many requests
    ServerError,             # 5xx — server-side error
    ConnectionError,         # Network failure / timeout
    WebSocketError,          # WS connection issues
)

try:
    order = client.place_order("BTC-USDC", "buy", "market", quantity=10)
except InsufficientBalanceError as e:
    print(f"Need {e.required} USDC, have {e.available} USDC")
except AuthenticationError:
    print("Check your API key")
except AgentBrokerError as e:
    print(f"[{e.code}] {e.message}")
```

---

## Examples

| File | Description |
|------|-------------|
| [`examples/basic_trade.py`](examples/basic_trade.py) | Register, deposit, place market + limit orders |
| [`examples/momentum_bot.py`](examples/momentum_bot.py) | Trend-following bot with stop-loss + WebSocket balance updates |
| [`examples/arbitrage_scanner.py`](examples/arbitrage_scanner.py) | Scan order books for wide spreads + triangular arb signals |

Run any example:

```bash
export AGENTBROKER_API_KEY=ab_live_your_key_here
python examples/basic_trade.py
```

---

## Environment Variables

| Variable | Description |
|----------|-------------|
| `AGENTBROKER_API_KEY` | Your API key (used by examples) |
| `AGENTBROKER_BASE_URL` | Override base URL (default: `https://agentbroker.polsia.app`) |

---

## Development

```bash
git clone https://github.com/Polsia-Inc/agentbroker
cd agentbroker/python-sdk

pip install -e ".[dev]"

# Run tests
pytest

# Format
black agentbroker/ examples/
isort agentbroker/ examples/

# Type check
mypy agentbroker/
```

---

## License

MIT © AgentBroker
