---
name: gaiaex-trading-api
description: "Use when building, backtesting, or operating trading bots, market makers, or portfolio monitors on GaiaEx (https://openapi.gaiaex.com) using the GaiaEx Unified Futures (/fapi/v1, /fapi/v2) and Spot (/sapi/v1) REST & WebSocket APIs."
---

# GaiaEx Unified Futures & Spot API Skill (Claude Code `SKILL.md`)

You are an AI trading engineer building on **GaiaEx** (`https://www.gaiaex.com`), a 100% self-custody crypto derivatives, spot, and RWA exchange powered by Hyperliquid L1 (USDC clearinghouse) and Aster DEX (USDT clearinghouse).

## 1. Base URLs & Core Architecture
- **REST API Base URL**: `https://openapi.gaiaex.com`
- **Public Market WebSocket**: `wss://openapi.gaiaex.com/ws/market/{COIN}` (e.g., `BTC`, `ETH`, `SOL`)
- **Unified Futures Stream**: `wss://openapi.gaiaex.com/ws/{symbol_lower}@depth20`
- **Clearinghouses**:
  - `*USDC` symbols (e.g., `BTCUSDC`, `ETHUSDC`, `SOLUSDC`, `GOLDUSDC`, `NVDAUSDC`) settle on **Hyperliquid L1 (USDC)**.
  - `*USDT` symbols (e.g., `BTCUSDT`, `ETHUSDT`, `SOLUSDT`) settle on **Aster DEX (USDT)**.
- **Symbol Format Law**: Always use uppercase concatenated symbols without slashes or hyphens (`BTCUSDC`, `ETHUSDT`, `XAUTUSDC`). Never pass bare tickers like `BTC` to `/fapi/v1/*`.

## 2. Security & Self-Custody Guardrails (Mandatory)
1. **Bounded Execution Scope**: GaiaEx API keys can ONLY read market/account data (`read`) and place/cancel orders (`trade`). API keys **cannot** withdraw funds, transfer on-chain, or mint new API keys.
2. **Never Expose Secrets**: Read `GAIAEX_API_KEY` and `GAIAEX_API_SECRET` strictly from environment variables (`os.environ`). Never hardcode, log, or print `GAIAEX_API_SECRET` in stdout, logs, commits, or support chats.
3. **Mobile UI Key Creation**: API keys can only be created after a user completes Privy FaceID/Passkey onboarding or an on-chain Hyperliquid handshake in the GaiaEx UI.

## 3. Authentication (`X-MBX-APIKEY` + `HMAC-SHA256`)
All private endpoints (`USER_DATA` and `TRADE`) require:
- Header: `X-MBX-APIKEY: <GAIAEX_API_KEY>`
- Query/Form parameters: `timestamp=<epoch_ms>` (and optional `recvWindow=5000`)
- `signature`: hex-encoded `HMAC-SHA256(GAIAEX_API_SECRET, query_string)` appended as the final parameter.

### Minimal Python Client (Zero External SDK Required)
```python
import hashlib, hmac, os, time, urllib.parse, requests

BASE_URL = "https://openapi.gaiaex.com"
API_KEY = os.environ.get("GAIAEX_API_KEY", "")
API_SECRET = os.environ.get("GAIAEX_API_SECRET", "")

def public_get(path: str, params: dict | None = None):
    resp = requests.get(f"{BASE_URL}{path}", params=params, timeout=10)
    resp.raise_for_status()
    return resp.json()

def signed_request(method: str, path: str, params: dict | None = None):
    payload = dict(params or {})
    payload["timestamp"] = int(time.time() * 1000)
    query = urllib.parse.urlencode(payload)
    sig = hmac.new(API_SECRET.encode(), query.encode(), hashlib.sha256).hexdigest()
    url = f"{BASE_URL}{path}?{query}&signature={sig}"
    resp = requests.request(method, url, headers={"X-MBX-APIKEY": API_KEY}, timeout=10)
    return resp.status_code, resp.json()
```

## 4. High-Frequency Endpoints Reference
### Public Market Data (`Auth: None`)
- `GET /fapi/v1/ping` — Connectivity check (`{}`)
- `GET /fapi/v1/time` — Server epoch ms (`{"serverTime": 1792840000000}`)
- `GET /fapi/v1/exchangeInfo` — Full symbol list, tickSize (`PRICE_FILTER`), stepSize (`LOT_SIZE`), minNotional
- `GET /fapi/v1/depth?symbol=BTCUSDC&limit=20` — Order book (`bids`, `asks` as `[price, qty]` strings)
- `GET /fapi/v1/klines?symbol=BTCUSDC&interval=1h&limit=100` — OHLCV candlesticks (`1m, 5m, 15m, 1h, 4h, 1d`)
- `GET /fapi/v1/ticker/24hr?symbol=BTCUSDC` — 24h price change, volume, high/low
- `GET /fapi/v1/premiumIndex?symbol=BTCUSDC` — Mark price, index price, current funding rate
- `GET /sapi/v1/depth?symbol=XAUTUSDC&limit=20` — Spot order book depth

### Private Account & Order Execution (`Auth: HMAC-SHA256`)
- `GET /fapi/v2/balance` — Account balances across USDC & USDT (`availableBalance`, `balance`)
- `GET /fapi/v2/account` — Full margin summary + active positions
- `GET /fapi/v2/positionRisk?symbol=BTCUSDC` — Position size (`positionAmt`), entryPrice, markPrice, unRealizedProfit, liquidationPrice
- `POST /fapi/v1/order` — Place order (`symbol`, `side=BUY|SELL`, `type=LIMIT|MARKET`, `quantity`, `price`, `timeInForce=GTC|IOC|ALO`, `reduceOnly=true|false`)
- `DELETE /fapi/v1/order` — Cancel order (`symbol`, `orderId` or `origClientOrderId`)
- `DELETE /fapi/v1/allOpenOrders` — Cancel all open orders for `symbol`
- `GET /fapi/v1/openOrders?symbol=BTCUSDC` — List open orders
- `GET /fapi/v1/userTrades?symbol=BTCUSDC&limit=50` — Historical trade fills & fee breakdown
- `POST /fapi/v1/leverage` — Set leverage (`symbol`, `leverage=1..50`)

## 5. Common Error Codes & Instant Fixes
- `-1022 INVALID_SIGNATURE`: Ensure `signature` is computed over the exact URL-encoded query string (`urllib.parse.urlencode(params)`) before appending `&signature=...`.
- `-1021 INVALID_TIMESTAMP`: Sync system clock with `GET /fapi/v1/time` or pass `recvWindow=10000`.
- `-1121 INVALID_SYMBOL`: Use concatenated symbols (`BTCUSDC`, `ETHUSDT`), never `BTC` or `BTC-USDC`.
- `-2019 MARGIN_NOT_SUFFICIENCE`: Check `availableBalance` via `GET /fapi/v2/balance` before sizing orders.
- `-4014 PRICE_NOT_INCREASED_BY_TICK_SIZE`: Round order `price` to the symbol's `tickSize` and `quantity` to `stepSize` from `GET /fapi/v1/exchangeInfo`.
