Skill: bevanding/cex-trader (version 2.0.2)

--- name: cex-trader version: 2.0.2 description: | Unified CEX trading capability layer for AI agents. Supports OKX and Binance spot and futures trading, account balance queries, order management, position queries, leverage settings, margin mode configuration, and guided API key setup flow. MCP tools: cex-spot-place-order, cex-spot-cancel-order, cex-futures-place-order, cex-futures-cancel-order, cex-futures-get-positions, cex-futures-set-leverage, cex-futures-close-position, cex-account-get-balance, cex-account-get-info, cex-setup-check, cex-setup-save, cex-setup-verify. Supports action semantics (open_long/open_short/close_long/close_short) and native side+posSide parameters. Built-in idempotency check, rate limiting, and risk controls (margin monitoring, position limits). Supports OKX and Binance exchanges. Swap tokens, buy crypto, sell crypto, CEX trade, exchange order, spot order, futures order, perpetual contract, leverage trading, close position, binance trade, okx trade. license: MIT metadata: openclaw: requires: bins: [] env: - name: CEX_OKX_API_KEY description: OKX API key. Required if trading on OKX. required: false - name: CEX_OKX_API_SECRET description: OKX API secret. Required if trading on OKX. required: false - name: CEX_OKX_PASSPHRASE description: OKX API passphrase. Required if trading on OKX. required: false - name: CEX_BINANCE_API_KEY description: Binance API key. Required if trading on Binance. required: false - name: CEX_BINANCE_API_SECRET description: Binance API secret. Required if trading on Binance. required: false - name: MCP_SERVER_URL description: MCP server base URL for the CLI script. Defaults to http://localhost:3000. Set to https://mcp-skills.ai.antalpha.com/mcp to use the hosted server. required: false credentials: primary: env note: | API keys are transmitted to the MCP server (see mcp.url or MCP_SERVER_URL). The ~/.trader/config.toml written by install.sh stores risk parameters only — never API keys. Credentials are NOT stored on disk by this skill. mcp: url: "https://mcp-skills.ai.antalpha.com/mcp" tools: - name: cex-spot-place-order description: Place a spot order (market or limit) on OKX or Binance - name: cex-spot-cancel-order description: Cancel an existing spot order on OKX or Binance - name: cex-account-get-balance description: Query account balance for all assets on OKX or Binance - name: cex-futures-place-order description: Place a futures/perpetual order with action semantics or native params on OKX or Binance - name: cex-futures-cancel-order description: Cancel an existing futures order on OKX or Binance - name: cex-futures-get-positions description: Query open futures positions on OKX or Binance - name: cex-futures-set-leverage description: Set leverage for a futures instrument on OKX or Binance - name: cex-futures-close-position description: Close an open futures position on OKX or Binance - name: cex-account-get-info description: Get account configuration and summary on OKX or Binance - name: cex-setup-check description: Check whether API credentials are configured for OKX or Binance. Call this at the start of every session. - name: cex-setup-save description: Save OKX or Binance API credentials (apiKey, secretKey, and passphrase for OKX) - name: cex-setup-verify description: Verify saved API credentials by making a test call to the exchange --- # cex-trader > v2.0.2 · Unified CEX Trading Capability Layer for AI Agents ⚠️ **Risk Warning**: Futures trading involves high leverage and may result in significant losses. Only use funds you can afford to lose. ## Overview `cex-trader` is a unified CEX trading MCP server that enables AI agents to trade on centralized exchanges (OKX, Binance) through a consistent interface. ## Supported Exchanges - **OKX** — Spot + Futures (MVP-α, production ready) - **Binance** — Spot + Futures (MVP-β, production ready) ## MCP Tools (12 total) ### Setup Tools | Tool | Description | |------|-------------| | `cex-setup-check` | Check if API credentials are configured | | `cex-setup-save` | Save API credentials for OKX or Binance | | `cex-setup-verify` | Verify credentials via a test API call | ### Spot Tools | Tool | Description | |------|-------------| | `cex-spot-place-order` | Place spot market or limit order | | `cex-spot-cancel-order` | Cancel spot order | | `cex-account-get-balance` | Query account balance | ### Futures Tools | Tool | Description | |------|-------------| | `cex-futures-place-order` | Place futures order (action semantics or native params) | | `cex-futures-cancel-order` | Cancel futures order | | `cex-futures-get-positions` | Query open positions | | `cex-futures-set-leverage` | Set leverage (1-20x) | | `cex-futures-close-position` | Close position | | `cex-account-get-info` | Get account config and summary | ## Changelog ### v2.0.2 (2026-04-14) - Fix: Corrected MCP server URL from mcp.antalpha.com/cex-trader to mcp-skills.ai.antalpha.com/mcp in mcp.url and MCP_SERVER_URL description ### v2.0.1 (2026-04-14) - Docs: Declared required env vars (CEX_OKX_*, CEX_BINANCE_*, MCP_SERVER_URL) in SKILL.md metadata - Docs: Clarified credential transmission path (env vars → MCP server; ~/.trader/config.toml stores risk params only) - Docs: Aligned MCP_SERVER_URL default (localhost:3000) with hosted URL in SKILL.md ### v2.0.0 (2026-04-13) - Added: Full Binance exchange support (Spot + Futures, MVP-β) - Added: ExchangeRouter, BinanceClientService (HMAC-SHA256 signing) - Added: cex-setup-check / cex-setup-save / cex-setup-verify onboarding tools - Fixed: BINANCE_ERROR_MAP error code mappings - Fixed: closePosition dual-side mode handling - All original tools now accept exchange parameter (defaults to okx, backward-compatible) ### v1.0.0 (2026-04-10) - Initial release: OKX spot + futures trading (MVP-α) - 9 MCP tools, action semantics, idempotency, risk controls

path: README.md
content: [🇺🇸 English](#english) · [🇨🇳 中文](#chinese)

---

<a name="english"></a>

# cex-trader

> v2.0.2 · Unified CEX Trading Capability Layer for AI Agents

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Version](https://img.shields.io/badge/version-2.0.2-blue.svg)](https://github.com/AntalphaAI/cex-trader)

⚠️ **Risk Warning**: Futures/perpetual contract trading involves high leverage and significant risk of loss. Only use funds you can afford to lose entirely.

---

## Overview

`cex-trader` is a unified CEX trading MCP (Model Context Protocol) server that enables AI agents to trade on centralized exchanges through a consistent, exchange-agnostic interface.

- **One configuration** — supports OKX (MVP-α) and Binance (MVP-β)
- **Unified interface** — AI agents don't need to handle exchange-specific differences
- **Safety first** — built-in rate limiting, idempotency checks, margin monitoring
- **Action semantics** — simplified `open_long / open_short / close_long / close_short` for AI agents
- **Guided setup** — conversational API key onboarding via `cex-setup-*` tools

---

## Supported Exchanges

| Exchange | Spot | Futures | Status |
|----------|------|---------|--------|
| OKX      | ✅   | ✅      | MVP-α (production ready) |
| Binance  | ✅   | ✅      | MVP-β (production ready) |

---

## MCP Tools (12 total)

### Setup Module

| Tool | Description |
|------|-------------|
| `cex-setup-check` | Check if API credentials are configured |
| `cex-setup-save` | Save API credentials for OKX or Binance |
| `cex-setup-verify` | Verify credentials via a test API call |

### Spot Module

| Tool | Description |
|------|-------------|
| `cex-spot-place-order` | Place spot market or limit order |
| `cex-spot-cancel-order` | Cancel an existing spot order |
| `cex-account-get-balance` | Query account balance for all assets |

### Futures Module

| Tool | Description |
|------|-------------|
| `cex-futures-place-order` | Place futures order (action semantics or native params) |
| `cex-futures-cancel-order` | Cancel futures order |
| `cex-futures-get-positions` | Query open positions |
| `cex-futures-set-leverage` | Set leverage (1-20x) |
| `cex-futures-close-position` | Close position (auto-detects margin mode) |
| `cex-account-get-info` | Get account config and summary |

---

## Quick Start

### Step 1 — Configure API Credentials

```python
# Check if already set up
mcp.call("cex-setup-check", {})

# Save OKX credentials (requires API Key + Secret + Passphrase)
mcp.call("cex-setup-save", {
    "exchange": "okx",
    "apiKey": "your-api-key",
    "secretKey": "your-secret-key",
    "passphrase": "your-passphrase"
})

# Save Binance credentials (requires API Key + Secret only)
mcp.call("cex-setup-save", {
    "exchange": "binance",
    "apiKey": "your-api-key",
    "secretKey": "your-secret-key"
})

# Verify credentials
mcp.call("cex-setup-verify", {"exchange": "binance"})
```

### Spot Trading

```python
# Binance — Limit buy
result = mcp.call("cex-spot-place-order", {
    "exchange": "binance",
    "instId": "BTC-USDT",
    "side": "buy",
    "ordType": "limit",
    "sz": "0.001",
    "px": "50000"
})

# OKX — Market sell
result = mcp.call("cex-spot-place-order", {
    "exchange": "okx",
    "instId": "BTC-USDT",
    "side": "sell",
    "ordType": "market",
    "sz": "0.001"
})
```

### Futures Trading — Action Semantics (Recommended for AI Agents)

```python
# Open long position — 10x leverage, isolated margin
result = mcp.call("cex-futures-place-order", {
    "exchange": "binance",
    "instId": "BTC-USDT-SWAP",
    "action": "open_long",
    "ordType": "market",
    "sz": "1",
    "leverage": 10,
    "mgnMode": "isolated"
})

# Close long position
result = mcp.call("cex-futures-place-order", {
    "exchange": "binance",
    "instId": "BTC-USDT-SWAP",
    "action": "close_long",
    "ordType": "market",
    "sz": "1"
})
```

### Futures Trading — Native Params (Advanced Users)

```python
# Open long (side=buy + posSide=long)
result = mcp.call("cex-futures-place-order", {
    "exchange": "okx",
    "instId": "BTC-USDT-SWAP",
    "side": "buy",
    "posSide": "long",
    "ordType": "limit",
    "sz": "1",
    "px": "50000",
    "leverage": 10,
    "mgnMode": "isolated"
})
```

---

## Action Semantics

| Action | side | posSide | Description |
|--------|------|---------|-------------|
| `open_long` | buy | long | Open long position |
| `open_short` | sell | short | Open short position |
| `close_long` | sell | long | Close long position |
| `close_short` | buy | short | Close short position |

If both `action` and native `side+posSide` are provided:
- Semantically consistent → `action` takes priority
- Conflicting → returns `ACTION_CONFLICT (4009)` error

---

## Configuration

```bash
# OKX
export CEX_OKX_API_KEY="your-api-key"
export CEX_OKX_API_SECRET="your-secret"
export CEX_OKX_PASSPHRASE="your-passphrase"

# Binance
export CEX_BINANCE_API_KEY="your-api-key"
export CEX_BINANCE_API_SECRET="your-secret"
```

Risk parameters (`~/.trader/config.toml`):

```toml
[general]
default_exchange = "okx"
log_level = "info"

[profiles.ai-trading.futures]
max_leverage = 10
max_position_usd = 5000
daily_limit_usd = 10000
margin_warning_ratio = 1.05
margin_danger_ratio = 1.02
```

---

## Error Codes

| Code | Name | Description |
|------|------|-------------|
| 1001 | NETWORK_ERROR | Network connectivity issue |
| 1002 | RATE_LIMIT_EXCEEDED | Too many requests |
| 2001 | INSUFFICIENT_BALANCE | Not enough balance |
| 2002 | INVALID_API_KEY | API key authentication failed |
| 2003 | PERMISSION_DENIED | API key lacks required permissions |
| 3001 | INVALID_PRICE | Order price out of range |
| 4001 | INSUFFICIENT_MARGIN | Not enough margin for position |
| 4002 | POSITION_NOT_FOUND | Position does not exist |
| 4003 | INVALID_LEVERAGE | Leverage value out of range |
| 4004 | LIQUIDATION_RISK | Position near liquidation |
| 4005 | ORDER_REJECTED | Order rejected by exchange |
| 4007 | DUPLICATE_ORDER | Duplicate clientOrderId detected |
| 4008 | INVALID_POSITION_SIDE | Invalid side+posSide combination |
| 4009 | ACTION_CONFLICT | action conflicts with native params |

---

## Security

- API keys are stored in environment variables (`CEX_OKX_*` / `CEX_BINANCE_*`) and transmitted to the MCP server when `cex-setup-save` is called
- The MCP server URL is `https://mcp-skills.ai.antalpha.com/mcp` (hosted) or override via `MCP_SERVER_URL=http://localhost:3000` for self-hosted
- `~/.trader/config.toml` (written by `install.sh`) stores **risk parameters only** — never API keys
- Withdrawal and transfer permissions **must NOT** be granted to the API key
- IP allowlist recommended
- Built-in rate limiting (token bucket algorithm)
- Demo/simulation mode supported (`x-simulated-trading: 1` for OKX)

---

## Changelog

### v2.0.2 (2026-04-14)
- **Fix**: Corrected MCP server URL to `https://mcp-skills.ai.antalpha.com/mcp` (was `mcp.antalpha.com/cex-trader`)

### v2.0.1 (2026-04-14)
- **Docs**: Declared required env vars (`CEX_OKX_*`, `CEX_BINANCE_*`, `MCP_SERVER_URL`) in SKILL.md metadata
- **Docs**: Clarified credential transmission path — env vars → MCP server; `~/.trader/config.toml` stores risk params only
- **Docs**: Aligned `MCP_SERVER_URL` default (`localhost:3000`) with hosted MCP URL in SKILL.md

### v2.0.0 (2026-04-13)
- **Added**: Full Binance exchange support — Spot + Futures (MVP-β, production ready)
- **Added**: ExchangeRouter for unified OKX/Binance dispatch
- **Added**: BinanceClientService with HMAC-SHA256 signing
- **Added**: BinanceSpotService, BinanceFuturesService, BinanceAccountService, BinanceMarketService
- **Added**: `cex-setup-check` / `cex-setup-save` / `cex-setup-verify` — guided API key onboarding (OKX + Binance)
- **Fixed**: BINANCE_ERROR_MAP[-2010] → ORDER_REJECTED (was PERMISSION_DENIED)
- **Fixed**: BINANCE_ERROR_MAP[-1021] → NETWORK_ERROR (was ORDER_REJECTED)
- **Fixed**: `closePosition` now iterates all positions (fix for dual-side mode)
- **Fixed**: POST Content-Type set to `application/x-www-form-urlencoded`
- All 9 original MCP tools now accept `exchange` parameter (backward-compatible, defaults to `"okx"`)

### v1.0.0 (2026-04-10)
- Initial release: OKX spot + futures trading (MVP-α)
- 9 MCP tools: spot/futures/account modules
- Action semantics: open_long/open_short/close_long/close_short
- Idempotency check via clientOrderId (crypto.randomUUID)
- Risk controls: margin monitoring, position limits
- Futures error codes: 4001-4009
- Verified on OKX demo trading environment (acctLv=2, long_short_mode)

---

<a name="chinese"></a>

# cex-trader（中文说明）

> v2.0.2 · 面向 AI Agent 的统一 CEX 交易能力层

⚠️ **风险提示**：合约/永续合约交易涉及高杠杆，存在重大亏损风险，请仅使用可以承受全部损失的资金。

---

## 概述

`cex-trader` 是一个统一的 CEX 交易 MCP 服务器，让 AI Agent 通过一致的接口在中心化交易所进行交易。

- **统一接口** — 支持 OKX（MVP-α）和 Binance（MVP-β）
- **安全优先** — 内置限频、幂等校验、保证金监控
- **Action 语义** — 简化合约方向：open_long / open_short / close_long / close_short
- **引导式配置** — 通过 `cex-setup-*` 工具完成 API Key 配置引导

---

## 支持的交易所

| 交易所   | 现货 | 合约 | 状态 |
|----------|------|------|------|
| OKX      | ✅   | ✅   | MVP-α（生产就绪） |
| Binance  | ✅   | ✅   | MVP-β（生产就绪） |

---

## MCP 工具（共 12 个）

### 配置工具

| 工具 | 说明 |
|------|------|
| `cex-setup-check` | 检查 API Key 是否已配置 |
| `cex-setup-save` | 保存 OKX 或 Binance 的 API 凭证 |
| `cex-setup-verify` | 通过测试 API 调用验证凭证有效性 |

### 现货工具

| 工具 | 说明 |
|------|------|
| `cex-spot-place-order` | 下现货市价单或限价单 |
| `cex-spot-cancel-order` | 撤销现货订单 |
| `cex-account-get-balance` | 查询账户余额 |

### 合约工具

| 工具 | 说明 |
|------|------|
| `cex-futures-place-order` | 下合约单（Action 语义或原生参数） |
| `cex-futures-cancel-order` | 撤销合约订单 |
| `cex-futures-get-positions` | 查询持仓 |
| `cex-futures-set-leverage` | 设置杠杆（1-20x） |
| `cex-futures-close-position` | 平仓（自动识别保证金模式） |
| `cex-account-get-info` | 查询账户配置和摘要 |

---

## 快速开始

```python
# 第一步：检查配置
mcp.call("cex-setup-check", {})

# 配置 Binance（只需 API Key + Secret）
mcp.call("cex-setup-save", {
    "exchange": "binance",
    "apiKey": "your-api-key",
    "secretKey": "your-secret-key"
})

# 验证
mcp.call("cex-setup-verify", {"exchange": "binance"})

# 开多（10 倍杠杆，逐仓）
mcp.call("cex-futures-place-order", {
    "exchange": "binance",
    "instId": "BTC-USDT-SWAP",
    "action": "open_long",
    "ordType": "market",
    "sz": "1",
    "leverage": 10,
    "mgnMode": "isolated"
})
```

---

## 更新日志

### v2.0.2 (2026-04-14)
- **修复**：更正 MCP Server 地址为 `https://mcp-skills.ai.antalpha.com/mcp`（原地址 `mcp.antalpha.com/cex-trader` 不可用）

### v2.0.1 (2026-04-14)
- **文档**：在 SKILL.md 元数据中声明所需环境变量（`CEX_OKX_*`、`CEX_BINANCE_*`、`MCP_SERVER_URL`）
- **文档**：明确凭证传输路径 — 环境变量 → MCP 服务器；`~/.trader/config.toml` 仅存风控参数
- **文档**：统一 `MCP_SERVER_URL` 默认值说明（`localhost:3000`）与 SKILL.md 中托管 URL 的关系

### v2.0.0 (2026-04-13)
- **新增**：完整 Binance 交易所支持 — 现货 + 合约（MVP-β，生产就绪）
- **新增**：ExchangeRouter 统一 OKX/Binance 调度
- **新增**：BinanceClientService（HMAC-SHA256 签名）
- **新增**：cex-setup-check / cex-setup-save / cex-setup-verify（引导式 API Key 配置）
- **修复**：BINANCE_ERROR_MAP 多处语义错误
- **修复**：closePosition 双向持仓漏平问题
- 原有 9 个 MCP 工具新增 `exchange` 参数（默认 `"okx"`，向后兼容）

### v1.0.0 (2026-04-10)
- 初始版本：OKX 现货 + 合约交易（MVP-α）
- 9 个 MCP 工具：现货/合约/账户模块
- Action 语义、clientOrderId 幂等校验、风控保证金监控


path: examples/futures_trading.py
content: """
Futures/perpetual trading examples for cex-trader MCP.

OKX futures instrument format: BTC-USDT-SWAP, ETH-USDT-SWAP
Account requirements: acctLv >= 2 (single or multi-currency margin)
Position mode: long_short_mode required for two-way positions
"""

# ── Set leverage ───────────────────────────────────────────────────────────────
set_leverage = {
    "tool": "cex-futures-set-leverage",
    "params": {
        "exchange": "okx",
        "instId": "BTC-USDT-SWAP",
        "leverage": 10,
        "mgnMode": "isolated"
    }
}

# ── Open long (action semantics — recommended for AI agents) ───────────────────
open_long_action = {
    "tool": "cex-futures-place-order",
    "params": {
        "exchange": "okx",
        "instId": "BTC-USDT-SWAP",
        "action": "open_long",        # simplified semantics
        "ordType": "market",
        "sz": "1",                    # 1 contract
        "leverage": 10,
        "mgnMode": "isolated"
    }
}

# ── Open short (action semantics) ─────────────────────────────────────────────
open_short_action = {
    "tool": "cex-futures-place-order",
    "params": {
        "exchange": "okx",
        "instId": "BTC-USDT-SWAP",
        "action": "open_short",
        "ordType": "limit",
        "sz": "1",
        "px": "100000",               # limit price
        "leverage": 5,
        "mgnMode": "isolated"
    }
}

# ── Close long (action semantics) ─────────────────────────────────────────────
close_long_action = {
    "tool": "cex-futures-place-order",
    "params": {
        "exchange": "okx",
        "instId": "BTC-USDT-SWAP",
        "action": "close_long",
        "ordType": "market",
        "sz": "1",
        "leverage": 10,
        "mgnMode": "isolated"
    }
}

# ── Open long (native params — advanced users) ─────────────────────────────────
open_long_native = {
    "tool": "cex-futures-place-order",
    "params": {
        "exchange": "okx",
        "instId": "BTC-USDT-SWAP",
        "side": "buy",                # native OKX param
        "posSide": "long",            # native OKX param
        "ordType": "limit",
        "sz": "1",
        "px": "50000",
        "leverage": 10,
        "mgnMode": "isolated",
        "clientOrderId": "my-order-001"  # for idempotency
    }
}

# ── Query positions ────────────────────────────────────────────────────────────
get_positions = {
    "tool": "cex-futures-get-positions",
    "params": {
        "exchange": "okx",
        "instId": "BTC-USDT-SWAP"    # optional, omit for all positions
    }
}

# ── Close entire position (uses market order, auto-detects margin mode) ────────
close_position = {
    "tool": "cex-futures-close-position",
    "params": {
        "exchange": "okx",
        "instId": "BTC-USDT-SWAP"
    }
}

# ── Cancel futures order ───────────────────────────────────────────────────────
cancel_futures_order = {
    "tool": "cex-futures-cancel-order",
    "params": {
        "exchange": "okx",
        "instId": "BTC-USDT-SWAP",
        "orderId": "1234567890"
    }
}


path: examples/spot_trading.py
content: """
Spot trading examples for cex-trader MCP.
These examples show how to call cex-trader MCP tools.
"""

# ── Place a limit buy order ────────────────────────────────────────────────────
spot_limit_buy = {
    "tool": "cex-spot-place-order",
    "params": {
        "exchange": "okx",
        "instId": "BTC-USDT",
        "side": "buy",
        "ordType": "limit",
        "sz": "0.001",
        "px": "50000"
    }
}

# ── Place a market sell order ──────────────────────────────────────────────────
spot_market_sell = {
    "tool": "cex-spot-place-order",
    "params": {
        "exchange": "okx",
        "instId": "BTC-USDT",
        "side": "sell",
        "ordType": "market",
        "sz": "0.001"
    }
}

# ── Cancel an order ────────────────────────────────────────────────────────────
spot_cancel = {
    "tool": "cex-spot-cancel-order",
    "params": {
        "exchange": "okx",
        "instId": "BTC-USDT",
        "orderId": "1234567890"
    }
}

# ── Query balance ──────────────────────────────────────────────────────────────
account_balance = {
    "tool": "cex-account-get-balance",
    "params": {
        "exchange": "okx"
    }
}


path: install.sh
content: #!/bin/bash
# cex-trader skill installer
# Sets up the cex-trader CLI and configuration

set -e

SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_DIR="$HOME/.trader"

echo "=== cex-trader skill installer ==="
echo ""

# Create config directory
mkdir -p "$CONFIG_DIR"

# Copy default config if not exists
if [ ! -f "$CONFIG_DIR/config.toml" ]; then
    echo "Creating default config at $CONFIG_DIR/config.toml ..."
    cat > "$CONFIG_DIR/config.toml" << 'EOF'
[general]
default_exchange = "okx"
log_level = "info"

[profiles.ai-trading.futures]
max_leverage = 10
max_position_usd = 5000
daily_limit_usd = 10000
margin_warning_ratio = 1.05
margin_danger_ratio = 1.02

[profiles.ai-trading.risk]
max_daily_trades = 50
stop_loss_ratio = 0.05
EOF
    echo "✅ Config created."
else
    echo "ℹ️  Config already exists at $CONFIG_DIR/config.toml, skipping."
fi

# Make CLI executable
chmod +x "$SKILL_DIR/scripts/cex_trader_cli.py"

echo ""
echo "=== Setup complete ==="
echo ""
echo "Next steps:"
echo "1. Set your API credentials as environment variables:"
echo "   export CEX_OKX_API_KEY='your-api-key'"
echo "   export CEX_OKX_API_SECRET='your-secret'"
echo "   export CEX_OKX_PASSPHRASE='your-passphrase'"
echo ""
echo "2. Review and adjust: $CONFIG_DIR/config.toml"
echo ""
echo "3. Start the MCP server (see backend repo: antalpha-com/antalpha-skills)"
echo ""
echo "⚠️  WARNING: Never grant withdrawal or transfer permissions to the API key!"
echo "⚠️  WARNING: Futures trading involves high leverage risk!"


path: requirements.txt
content: # cex-trader skill — Python dependencies
# The CLI script uses only Python standard library (no third-party deps required)
# Backend MCP server dependencies are in the backend repository:
#   antalpha-com/antalpha-skills

# Optional: for development/testing
# requests>=2.28.0


path: scripts/cex_trader_cli.py
content: #!/usr/bin/env python3
"""
cex-trader CLI — Unified CEX Trading Capability Layer
Calls the cex-trader MCP server tools via HTTP.

Usage:
    python cex_trader_cli.py setup check
    python cex_trader_cli.py setup save --exchange binance --apiKey KEY --secretKey SECRET
    python cex_trader_cli.py setup verify --exchange binance
    python cex_trader_cli.py spot place --exchange okx --instId BTC-USDT --side buy --ordType limit --sz 0.001 --px 50000
    python cex_trader_cli.py spot place --exchange binance --instId BTC-USDT --side buy --ordType limit --sz 0.001 --px 50000
    python cex_trader_cli.py futures place --exchange binance --instId BTC-USDT-SWAP --action open_long --ordType market --sz 1 --leverage 10
    python cex_trader_cli.py futures positions --exchange binance
    python cex_trader_cli.py futures leverage --exchange okx --instId BTC-USDT-SWAP --leverage 10 --mgnMode isolated
    python cex_trader_cli.py futures close --exchange okx --instId BTC-USDT-SWAP
    python cex_trader_cli.py account balance --exchange okx

Environment variables:
    MCP_SERVER_URL  — MCP server base URL (default: http://localhost:3000)
"""

import argparse
import json
import os
import sys
import urllib.request
import urllib.error

MCP_SERVER_URL = os.environ.get("MCP_SERVER_URL", "http://localhost:3000")


def call_tool(tool_name: str, params: dict) -> dict:
    """Call an MCP tool via HTTP POST."""
    url = f"{MCP_SERVER_URL}/tools/{tool_name}"
    data = json.dumps(params).encode("utf-8")
    req = urllib.request.Request(
        url,
        data=data,
        headers={"Content-Type": "application/json"},
        method="POST",
    )
    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        body = e.read().decode()
        print(f"HTTP Error {e.code}: {body}", file=sys.stderr)
        sys.exit(1)
    except urllib.error.URLError as e:
        print(f"Connection error: {e.reason}", file=sys.stderr)
        print(f"Is the MCP server running at {MCP_SERVER_URL}?", file=sys.stderr)
        sys.exit(1)


def print_result(result: dict):
    print(json.dumps(result, indent=2, ensure_ascii=False))


# ── Spot commands ──────────────────────────────────────────────────────────────

def cmd_spot_place(args):
    params = {
        "exchange": args.exchange,
        "instId": args.instId,
        "side": args.side,
        "ordType": args.ordType,
        "sz": args.sz,
    }
    if args.px:
        params["px"] = args.px
    if args.quoteOrderQty:
        params["quoteOrderQty"] = args.quoteOrderQty
    print_result(call_tool("cex-spot-place-order", params))


def cmd_spot_cancel(args):
    params = {
        "exchange": args.exchange,
        "instId": args.instId,
        "orderId": args.orderId,
    }
    print_result(call_tool("cex-spot-cancel-order", params))


# ── Futures commands ───────────────────────────────────────────────────────────

def cmd_futures_place(args):
    params = {
        "exchange": args.exchange,
        "instId": args.instId,
        "ordType": args.ordType,
        "sz": args.sz,
        "leverage": int(args.leverage),
        "mgnMode": args.mgnMode,
    }
    # Action semantics (recommended)
    if args.action:
        params["action"] = args.action
    # Native params (advanced)
    if args.side:
        params["side"] = args.side
    if args.posSide:
        params["posSide"] = args.posSide
    if args.px:
        params["px"] = args.px
    if args.clientOrderId:
        params["clientOrderId"] = args.clientOrderId
    print_result(call_tool("cex-futures-place-order", params))


def cmd_futures_cancel(args):
    params = {
        "exchange": args.exchange,
        "instId": args.instId,
        "orderId": args.orderId,
    }
    print_result(call_tool("cex-futures-cancel-order", params))


def cmd_futures_positions(args):
    params = {"exchange": args.exchange}
    if args.instId:
        params["instId"] = args.instId
    print_result(call_tool("cex-futures-get-positions", params))


def cmd_futures_leverage(args):
    params = {
        "exchange": args.exchange,
        "instId": args.instId,
        "leverage": int(args.leverage),
        "mgnMode": args.mgnMode,
    }
    print_result(call_tool("cex-futures-set-leverage", params))


def cmd_futures_close(args):
    params = {
        "exchange": args.exchange,
        "instId": args.instId,
    }
    print_result(call_tool("cex-futures-close-position", params))


# ── Setup commands ────────────────────────────────────────────────────────────

def cmd_setup_check(args):
    print_result(call_tool("cex-setup-check", {}))


def cmd_setup_save(args):
    params = {
        "exchange": args.exchange,
        "apiKey": args.apiKey,
        "secretKey": args.secretKey,
    }
    if args.passphrase:
        params["passphrase"] = args.passphrase
    print_result(call_tool("cex-setup-save", params))


def cmd_setup_verify(args):
    params = {"exchange": args.exchange}
    print_result(call_tool("cex-setup-verify", params))


# ── Account commands ───────────────────────────────────────────────────────────

def cmd_account_balance(args):
    params = {"exchange": args.exchange}
    print_result(call_tool("cex-account-get-balance", params))


def cmd_account_info(args):
    params = {"exchange": args.exchange}
    print_result(call_tool("cex-account-get-info", params))


# ── Parser ─────────────────────────────────────────────────────────────────────

def build_parser():
    parser = argparse.ArgumentParser(
        description="cex-trader CLI — Unified CEX Trading Tool",
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    sub = parser.add_subparsers(dest="module", required=True)

    # ── setup ──
    setup = sub.add_parser("setup", help="API credential setup commands")
    setup_sub = setup.add_subparsers(dest="command", required=True)

    s_check = setup_sub.add_parser("check", help="Check if credentials are configured")
    s_check.set_defaults(func=cmd_setup_check)

    s_save = setup_sub.add_parser("save", help="Save API credentials")
    s_save.add_argument("--exchange", required=True, choices=["okx", "binance"])
    s_save.add_argument("--apiKey", required=True, help="API Key")
    s_save.add_argument("--secretKey", required=True, help="API Secret")
    s_save.add_argument("--passphrase", help="Passphrase (required for OKX)")
    s_save.set_defaults(func=cmd_setup_save)

    s_verify = setup_sub.add_parser("verify", help="Verify credentials via test API call")
    s_verify.add_argument("--exchange", required=True, choices=["okx", "binance"])
    s_verify.set_defaults(func=cmd_setup_verify)

    # ── spot ──
    spot = sub.add_parser("spot", help="Spot trading commands")
    spot_sub = spot.add_subparsers(dest="command", required=True)

    sp_place = spot_sub.add_parser("place", help="Place a spot order")
    sp_place.add_argument("--exchange", required=True, choices=["okx", "binance"])
    sp_place.add_argument("--instId", required=True, help="e.g. BTC-USDT")
    sp_place.add_argument("--side", required=True, choices=["buy", "sell"])
    sp_place.add_argument("--ordType", required=True, choices=["market", "limit"])
    sp_place.add_argument("--sz", required=True, help="Order size")
    sp_place.add_argument("--px", help="Price (required for limit orders)")
    sp_place.add_argument("--quoteOrderQty", help="Quote asset quantity for market buy")
    sp_place.set_defaults(func=cmd_spot_place)

    sp_cancel = spot_sub.add_parser("cancel", help="Cancel a spot order")
    sp_cancel.add_argument("--exchange", required=True, choices=["okx", "binance"])
    sp_cancel.add_argument("--instId", required=True)
    sp_cancel.add_argument("--orderId", required=True)
    sp_cancel.set_defaults(func=cmd_spot_cancel)

    # ── futures ──
    futures = sub.add_parser("futures", help="Futures trading commands")
    fut_sub = futures.add_subparsers(dest="command", required=True)

    fp_place = fut_sub.add_parser("place", help="Place a futures order")
    fp_place.add_argument("--exchange", required=True, choices=["okx", "binance"])
    fp_place.add_argument("--instId", required=True, help="e.g. BTC-USDT-SWAP")
    fp_place.add_argument("--action", choices=["open_long", "open_short", "close_long", "close_short"],
                          help="Action semantics (recommended for AI agents)")
    fp_place.add_argument("--side", choices=["buy", "sell"], help="Native param")
    fp_place.add_argument("--posSide", choices=["long", "short"], help="Native param")
    fp_place.add_argument("--ordType", required=True, choices=["market", "limit"])
    fp_place.add_argument("--sz", required=True, help="Size in contracts")
    fp_place.add_argument("--px", help="Price (required for limit orders)")
    fp_place.add_argument("--leverage", required=True, help="Leverage (1-20)")
    fp_place.add_argument("--mgnMode", required=True, choices=["isolated", "cross"])
    fp_place.add_argument("--clientOrderId", help="Client order ID for idempotency")
    fp_place.set_defaults(func=cmd_futures_place)

    fp_cancel = fut_sub.add_parser("cancel", help="Cancel a futures order")
    fp_cancel.add_argument("--exchange", required=True, choices=["okx", "binance"])
    fp_cancel.add_argument("--instId", required=True)
    fp_cancel.add_argument("--orderId", required=True)
    fp_cancel.set_defaults(func=cmd_futures_cancel)

    fp_pos = fut_sub.add_parser("positions", help="Query open positions")
    fp_pos.add_argument("--exchange", required=True, choices=["okx", "binance"])
    fp_pos.add_argument("--instId", help="Filter by instrument (optional)")
    fp_pos.set_defaults(func=cmd_futures_positions)

    fp_lev = fut_sub.add_parser("leverage", help="Set leverage")
    fp_lev.add_argument("--exchange", required=True, choices=["okx", "binance"])
    fp_lev.add_argument("--instId", required=True)
    fp_lev.add_argument("--leverage", required=True, help="1-20")
    fp_lev.add_argument("--mgnMode", required=True, choices=["isolated", "cross"])
    fp_lev.set_defaults(func=cmd_futures_leverage)

    fp_close = fut_sub.add_parser("close", help="Close a position")
    fp_close.add_argument("--exchange", required=True, choices=["okx", "binance"])
    fp_close.add_argument("--instId", required=True)
    fp_close.set_defaults(func=cmd_futures_close)

    # ── account ──
    account = sub.add_parser("account", help="Account commands")
    acc_sub = account.add_subparsers(dest="command", required=True)

    ac_bal = acc_sub.add_parser("balance", help="Query balance")
    ac_bal.add_argument("--exchange", required=True, choices=["okx", "binance"])
    ac_bal.set_defaults(func=cmd_account_balance)

    ac_info = acc_sub.add_parser("info", help="Query account info")
    ac_info.add_argument("--exchange", required=True, choices=["okx", "binance"])
    ac_info.set_defaults(func=cmd_account_info)

    return parser


def main():
    parser = build_parser()
    args = parser.parse_args()
    if hasattr(args, "func"):
        args.func(args)
    else:
        parser.print_help()


if __name__ == "__main__":
    main()


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)