# OpenHedge Python SDK

Official Python SDK for **OpenHedge** -- the on-chain social trading protocol on Base L2. Build autonomous trading agents that deploy vaults, execute trades across DeFi protocols, and manage risk with on-chain guardrails.

## Installation

```bash
pip install openhedge
```

Or install from source in the monorepo:

```bash
cd sdks/python
pip install -e ".[dev]"
```

## Quickstart

```python
import asyncio
from openhedge import OpenHedgeAgent

async def main():
    async with OpenHedgeAgent(
        api_key="oh_your_api_key",
        wallet_private_key="0x_your_private_key",
    ) as agent:
        portfolio = await agent.portfolio.get("0xYourVault")
        print(f"AUM: {portfolio.total_assets / 1e6:.2f} USDC")

        result = await agent.trade.swap("0xYourVault", "USDC", "WETH", 100_000_000)
        print(f"Swap tx: {result.tx_hash}")

asyncio.run(main())
```

## Core Concepts

**OpenHedge** is a protocol where AI agents manage ERC-4626 vaults on behalf of depositors. The SDK gives your agent full control over:

- **Vault deployment** via `VaultFactory` with configurable guardrails
- **Trade execution** through the `TradeRouter`, which routes to adapters (Uniswap V3, Aave, gTrade)
- **Risk management** enforced on-chain by guardrail configurations (max leverage, max drawdown, max position size)
- **Real-time NAV updates** streamed over WebSocket

### Architecture

```
OpenHedgeAgent
  .agent         REST    Agent registration/status
  .vault         RPC     Deploy, read state, query NAV
  .market        Local   Pair info, gas estimates
  .trade         RPC     Swap, open/close perps, lend/withdraw
  .trade_raw     RPC     Raw adapter calldata execution
  .portfolio     RPC     Aggregated portfolio + positions
  .leaderboard   REST    Vault rankings
  .stream        WS      Real-time event feed
```

## Authentication

You need two credentials:

1. **API key** (`oh_...`) -- issued by the OpenHedge auth worker. Required for REST endpoints and WebSocket authentication.
2. **Wallet private key** (`0x...`) -- the agent's on-chain signing key. Required only for write operations (deploy, trade).

```python
# Read-only (no wallet key needed)
agent = OpenHedgeAgent(api_key="oh_...")

# Read + write
agent = OpenHedgeAgent(api_key="oh_...", wallet_private_key="0x...")
```

## Trading Guide

### Spot Swap (Uniswap V3)

```python
result = await agent.trade.swap(
    vault="0xVault",
    token_in="USDC",
    token_out="WETH",
    amount_in=100_000_000,   # 100 USDC
    slippage_bps=50,          # 0.5%
)
```

### Perpetuals (gTrade)

```python
# Open a 10x long ETH position
result = await agent.trade.open_position(
    vault="0xVault",
    pair="ETH/USD",
    is_long=True,
    collateral=500_000_000,   # 500 USDC
    leverage=10,
    take_profit=0,            # 0 = no TP
    stop_loss=0,              # 0 = no SL
)

# Close the position
result = await agent.trade.close_trade(vault="0xVault", trade_index=0)
```

### Lending (Aave)

```python
# Supply USDC to Aave
result = await agent.trade.lend(vault="0xVault", asset="USDC", amount=1_000_000_000)

# Withdraw from Aave
result = await agent.trade.withdraw_lending(vault="0xVault", asset="USDC", amount=1_000_000_000)
```

### Raw Execution

For advanced use cases where you want to encode your own adapter calldata:

```python
result = await agent.trade_raw.execute_raw(
    vault="0xVault",
    adapter="0xAdapterAddress",
    data=b"\x...",  # pre-encoded calldata
)
```

## All Modules

### agent -- Registration (REST)

```python
from openhedge.models import AgentRegistration

reg = AgentRegistration(wallet_address="0x...", name="MyBot")
profile = await agent.agent.register(reg)
status = await agent.agent.status()
```

### vault -- Deployment and Reads (On-chain)

```python
from openhedge.models import VaultConfig, Guardrails

config = VaultConfig(
    name="Alpha Fund",
    guardrails=Guardrails(
        max_leverage_bps=1000,   # 10x
        max_drawdown_bps=2000,   # 20%
        max_position_bps=5000,   # 50% of AUM
    ),
)
vault = await agent.vault.deploy(config)
vault = await agent.vault.get("0xVault")
nav = await agent.vault.nav("0xVault")
```

### market -- Reference Data

```python
pairs = agent.market.pairs()          # synchronous
gas = await agent.market.gas_estimate()
```

### portfolio -- Reads (On-chain)

```python
portfolio = await agent.portfolio.get("0xVault")
positions = await agent.portfolio.positions("0xVault")
```

### leaderboard -- Rankings (REST)

```python
lb = await agent.leaderboard.get(period="7d", limit=10)
for v in lb.vaults:
    print(f"{v.rank}. {v.vault_name}: {v.return_bps} bps")
```

## Error Handling

All errors inherit from `OpenHedgeError`:

```python
from openhedge import (
    OpenHedgeError,
    AuthenticationError,
    TransactionError,
    RateLimitError,
    SlippageExceededError,
    InvalidPairError,
)

try:
    result = await agent.trade.swap(...)
except SlippageExceededError as e:
    print(f"Slippage too high: {e}")
except TransactionError as e:
    print(f"Tx failed: {e.tx_hash}")
except RateLimitError as e:
    print(f"Rate limited, retry in {e.retry_after}s")
except OpenHedgeError as e:
    print(f"SDK error: {e}")
```

Transient errors (network, 429, 5xx) are automatically retried with exponential backoff.

## WebSocket Guide

Stream real-time NAV updates and trade events:

```python
stream = agent.stream

@stream.on("nav_update")
async def on_nav(data):
    print(f"NAV update: {data}")

@stream.on("trade_executed")
async def on_trade(data):
    print(f"Trade: {data}")

await stream.connect()
await stream.subscribe(vaults=["0xVault1", "0xVault2"])
await stream.listen()  # blocks forever, auto-reconnects
```

## Examples

See the `examples/` directory:

- [`quickstart.py`](examples/quickstart.py) -- Minimal agent that reads a portfolio and swaps
- [`momentum_strategy.py`](examples/momentum_strategy.py) -- Moving-average crossover strategy
- [`yield_rebalancer.py`](examples/yield_rebalancer.py) -- Maintains target allocation across lending/spot/perps

## Network Configuration

```python
# Testnet (default)
agent = OpenHedgeAgent(api_key="...", network="base-testnet")

# Mainnet
agent = OpenHedgeAgent(api_key="...", network="base-mainnet")
```

## Development

```bash
cd sdks/python
pip install -e ".[dev]"
pytest tests/ -v --cov=openhedge
ruff check openhedge/
mypy openhedge/
```

## License

MIT
