Skip to content

Doc: standx-python-sdk 设计文档 & 测试验收文档 #171

@wjllance

Description

@wjllance

standx-python-sdk 设计文档 & 测试验收文档


一、设计文档

1.1 项目概述

项目 内容
项目名称 standx-python-sdk
目标用户 Python 开发者、量化交易者、AI Agent
Python 版本 3.10+
许可证 MIT

1.2 架构设计

┌─────────────────────────────────────────────────────────────────┐
│                        standx-python-sdk                        │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐      │
│  │   User Code  │    │   Strategy   │    │    Agent     │      │
│  │              │    │   Scripts    │    │   (AI)       │      │
│  └──────┬───────┘    └──────┬───────┘    └──────┬───────┘      │
│         │                   │                   │              │
│         └───────────────────┼───────────────────┘              │
│                             ▼                                   │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                    StandXClient                         │   │
│  ├─────────────────────────────────────────────────────────┤   │
│  │  market: MarketAPI      │  account: AccountAPI          │   │
│  │    - ticker()             │    - positions()              │   │
│  │    - depth()              │    - balances()               │   │
│  │    - trades()             │    - orders()                 │   │
│  │    - kline()              │    - history()                │   │
│  │                          │                               │   │
│  │  order: OrderAPI         │  ws: WebSocketAPI             │   │
│  │    - create()             │    - subscribe_price()        │   │
│  │    - cancel()             │    - subscribe_depth()        │   │
│  │    - cancel_all()         │    - subscribe_trade()        │   │
│  │                          │    - on_order_update()        │   │
│  └─────────────────────────────────────────────────────────┘   │
│                             │                                   │
│                             ▼                                   │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                 HTTP / WebSocket Layer                  │   │
│  │   httpx + websockets                                    │   │
│  └─────────────────────────────────────────────────────────┘   │
│                             │                                   │
│                             ▼                                   │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │              StandX Exchange API                        │   │
│  │   REST: https://perps.standx.com                        │   │
│  │   WS: wss://perps.standx.com/ws-stream/v1              │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

1.3 API 设计

1.3.1 StandXClient 主类

class StandXClient:
    def __init__(
        self,
        private_key: str = None,          # 钱包私钥
        jwt_token: str = None,            # 或直接传入 JWT
        api_url: str = \"https://perps.standx.com\",
        ws_url: str = \"wss://perps.standx.com/ws-stream/v1\",
        timeout: float = 30.0,
        verbose: bool = False
    ):
        \"\"\"
        初始化客户端
        
        Args:
            private_key: 钱包私钥 (0x...)
            jwt_token: 预生成的 JWT token
            api_url: REST API 地址
            ws_url: WebSocket 地址
            timeout: 请求超时时间 ()
            verbose: 调试模式
        \"\"\"

1.3.2 Market API

class MarketAPI:
    async def ticker(self, symbol: str) -> dict:
        \"\"\"获取 ticker 数据
        
        Args:
            symbol: 交易对 ( \"BTC-USD\")
            
        Returns:
            {
                \"symbol\": \"BTC-USD\",
                \"last_price\": \"67000.00\",
                \"mark_price\": \"67000.00\",
                \"index_price\": \"66980.00\",
                \"24h_high\": \"68000.00\",
                \"24h_low\": \"66000.00\",
                \"24h_volume\": \"12345.67\",
                \"funding_rate\": \"0.0001\",
                \"next_funding_time\": \"2024-01-01T08:00:00Z\"
            }
        \"\"\"
    
    async def tickers(self) -> list[dict]:
        \"\"\"获取所有 ticker\"\"\"
    
    async def depth(self, symbol: str, limit: int = 20) -> dict:
        \"\"\"获取订单簿
        
        Args:
            symbol: 交易对
            limit: 深度数量 (默认 20)
            
        Returns:
            {
                \"symbol\": \"BTC-USD\",
                \"bids\": [[\"67000\", \"1.5\"], [\"66999\", \"2.0\"], ...],
                \"asks\": [[\"67001\", \"1.0\"], [\"67002\", \"2.5\"], ...],
                \"timestamp\": \"1704067200000\"
            }
        \"\"\"
    
    async def trades(self, symbol: str, limit: int = 50) -> list[dict]:
        \"\"\"获取近期成交\"\"\"
    
    async def kline(
        self,
        symbol: str,
        interval: str = \"1m\",
        start_time: int = None,
        end_time: int = None,
        limit: int = 100
    ) -> list[dict]:
        \"\"\"获取 K 线数据
        
        Args:
            symbol: 交易对
            interval: 周期 (\"1m\", \"5m\", \"15m\", \"1h\", \"4h\", \"1d\")
            start_time: 开始时间 (毫秒)
            end_time: 结束时间 (毫秒)
            limit: 数量限制
            
        Returns:
            [
                {
                    \"time\": 1704067200000,
                    \"open\": \"67000\",
                    \"high\": \"67100\",
                    \"low\": \"66900\",
                    \"close\": \"67050\",
                    \"volume\": \"123.45\"
                },
                ...
            ]
        \"\"\"
    
    async def funding(self, symbol: str, limit: int = 10) -> list[dict]:
        \"\"\"获取资金费率历史\"\"\"
    
    async def symbols(self) -> list[dict]:
        \"\"\"获取所有交易对\"\"\"

1.3.3 Account API

class AccountAPI:
    async def balances(self) -> dict:
        \"\"\"获取账户余额
        
        Returns:
            {
                \"total_equity\": \"10000.00\",
                \"total_margin\": \"5000.00\",
                \"available\": \"8000.00\",
                \"pnl_24h\": \"100.00\",
                \"wallets\": [
                    {
                        \"asset\": \"USD\",
                        \"balance\": \"5000.00\",
                        \"available\": \"4000.00\",
                        \"locked\": \"1000.00\"
                    }
                ]
            }
        \"\"\"
    
    async def positions(self, symbol: str = None) -> list[dict]:
        \"\"\"获取持仓
        
        Args:
            symbol: 可选按交易对筛选
            
        Returns:
            [
                {
                    \"id\": 12345,
                    \"symbol\": \"BTC-USD\",
                    \"side\": \"buy\",  # \"buy\" = LONG, \"sell\" = SHORT
                    \"qty\": \"0.5\",
                    \"entry_price\": \"66000.00\",
                    \"mark_price\": \"67000.00\",
                    \"leverage\": \"10\",
                    \"margin_mode\": \"cross\",
                    \"unrealized_pnl\": \"500.00\",
                    \"roe\": \"10.0\",
                    \"liq_price\": \"59400.00\",
                    \"updated_at\": \"2024-01-01T12:00:00Z\"
                }
            ]
        \"\"\"
    
    async def orders(
        self,
        symbol: str = None,
        status: str = None,
        limit: int = 100
    ) -> list[dict]:
        \"\"\"获取订单
        
        Args:
            symbol: 交易对
            status: 状态 (\"open\", \"filled\", \"canceled\")
            limit: 数量限制
        \"\"\"
    
    async def history(
        self,
        symbol: str = None,
        start_time: int = None,
        end_time: int = None,
        limit: int = 50
    ) -> list[dict]:
        \"\"\"获取历史订单\"\"\"

1.3.4 Order API

class OrderAPI:
    async def create(
        self,
        symbol: str,
        side: str,           # \"buy\" / \"sell\"
        order_type: str,     # \"limit\" / \"market\"
        qty: str,
        price: str = None,   # 限价单必需
        time_in_force: str = \"gtc\",  # \"gtc\" / \"ioc\" / \"fok\"
        tp_price: str = None,  # 止盈价格
        sl_price: str = None   # 止损价格
    ) -> dict:
        \"\"\"创建订单
        
        Returns:
            {
                \"id\": \"order_123456\",
                \"symbol\": \"BTC-USD\",
                \"side\": \"buy\",
                \"order_type\": \"limit\",
                \"qty\": \"0.1\",
                \"price\": \"67000.00\",
                \"status\": \"new\",
                \"created_at\": \"2024-01-01T12:00:00Z\"
            }
        \"\"\"
    
    async def cancel(self, order_id: str, symbol: str) -> dict:
        \"\"\"取消订单\"\"\"
    
    async def cancel_all(self, symbol: str = None) -> dict:
        \"\"\"取消所有订单\"\"\"
    
    async def get_order(self, order_id: str, symbol: str) -> dict:
        \"\"\"查询订单详情\"\"\"

1.3.5 Leverage & Margin API

class LeverageAPI:
    async def set_leverage(self, symbol: str, leverage: int) -> dict:
        \"\"\"设置杠杆\"\"\"

class MarginAPI:
    async def set_margin_mode(self, symbol: str, mode: str) -> dict:
        \"\"\"设置保证金模式
        
        Args:
            mode: \"cross\" / \"isolated\"
        \"\"\"
    
    async def add_margin(self, symbol: str, amount: str) -> dict:
        \"\"\"增加保证金\"\"\"
    
    async def remove_margin(self, symbol: str, amount: str) -> dict:
        \"\"\"减少保证金\"\"\"

1.3.6 WebSocket API

class WebSocketAPI:
    async def connect(self):
        \"\"\"建立 WebSocket 连接\"\"\"
    
    async def disconnect(self):
        \"\"\"断开连接\"\"\"
    
    # ========== Public Channels ==========
    async def subscribe_price(self, symbol: str, callback: callable):
        \"\"\"订阅价格更新
        
        Args:
            symbol: 交易对
            callback: 回调函数 (price: dict) -> None
        \"\"\"
    
    async def subscribe_depth(self, symbol: str, callback: callable):
        \"\"\"订阅订单簿更新\"\"\"
    
    async def subscribe_trade(self, symbol: str, callback: callable):
        \"\"\"订阅成交推送\"\"\"
    
    # ========== Private Channels (需要认证) ==========
    async def subscribe_order(self, callback: callable):
        \"\"\"订阅订单更新\"\"\"
    
    async def subscribe_position(self, callback: callable):
        \"\"\"订阅持仓更新\"\"\"
    
    async def subscribe_balance(self, callback: callable):
        \"\"\"订阅余额更新\"\"\"
    
    async def subscribe_fills(self, callback: callable):
        \"\"\"订阅成交记录 (用户买卖)\"\"\"

1.4 认证模块

class Auth:
    @staticmethod
    def generate_jwt(
        private_key: str,
        wallet_address: str,
        permissions: list[str] = [\"trade\", \"view\"],
        expiry_days: int = 7
    ) -> str:
        \"\"\"生成 JWT token
        
        Args:
            private_key: 钱包私钥
            wallet_address: 钱包地址
            permissions: 权限列表 [\"trade\", \"view\"]
            expiry_days: 过期天数
            
        Returns:
            JWT token 字符串
        \"\"\"

1.5 策略模板 (可选)

1.5.1 网格策略

class GridStrategy:
    def __init__(
        self,
        client: StandXClient,
        symbol: str,
        grid_count: int = 10,
        grid_range: float = 0.05,  # 5% 范围
        qty_per_grid: str = \"0.01\"
    ):
        \"\"\"
        网格交易策略
        
        Args:
            client: StandX 客户端
            symbol: 交易对
            grid_count: 网格数量
            grid_range: 价格范围 (5% = 0.05)
            qty_per_grid: 每个网格的数量
        \"\"\"
    
    async def start(self):
        \"\"\"启动策略\"\"\"
    
    async def stop(self):
        \"\"\"停止策略\"\"\"
    
    async def restart(self):
        \"\"\"重启策略 (重新平衡网格)\"\"\"

二、测试验收文档

2.1 测试环境

环境 配置
Python 3.10, 3.11, 3.12
测试网络 StandX Testnet (如可用)
测试账号 测试钱包 + 测试 JWT

2.2 测试用例

2.2.1 单元测试

模块 测试项 预期结果
Auth generate_jwt() 正确生成签名 JWT 字符串有效
Auth jwt 包含正确权限 permissions 匹配
MarketAPI ticker() 返回完整数据 包含 last_price, mark_price 等
MarketAPI depth() 订单簿格式正确 bids/asks 数组格式
MarketAPI kline() 返回 K 线数据 open/high/low/close/volume
AccountAPI positions() 持仓结构正确 包含 qty, entry_price, upnl
AccountAPI balances() 余额结构正确 包含 equity, available
OrderAPI create() 限价单成功 返回 order_id, status=new
OrderAPI create() 市价单成功 返回 order_id, status=filled
OrderAPI cancel() 取消订单成功 status=canceled
OrderAPI cancel_all() 取消所有成功 所有订单 canceled
WebSocket connect() 连接成功 ws.connected = True
WebSocket subscribe_price() 收到推送 callback 收到实时价格

2.2.2 集成测试

场景 测试步骤 验收标准
完整交易流程 1. 获取 ticker
2. 下限价单
3. 查询订单
4. 取消订单
订单状态正确变更
持仓管理 1. 开多仓
2. 查询持仓
3. 平仓
持仓数量正确
WebSocket 实时 1. 连接 ws
2. 订阅 price
3. 下单触发成交
4. 收到 fill 推送
实时数据正确
认证过期处理 1. 使用过期 jwt
2. 调用 API
抛出 AuthExpiredError

2.3 测试用例代码示例

import pytest
import asyncio
from standx import StandXClient

# 测试配置
TEST_PRIVATE_KEY = \"0x...\"  # 测试钱包私钥
TEST_SYMBOL = \"BTC-USD\"

@pytest.fixture
def client():
    return StandXClient(private_key=TEST_PRIVATE_KEY)

class TestMarketAPI:
    @pytest.mark.asyncio
    async def test_ticker(self, client):
        result = await client.market.ticker(TEST_SYMBOL)
        assert \"last_price\" in result
        assert \"mark_price\" in result
        assert result[\"symbol\"] == TEST_SYMBOL
    
    @pytest.mark.asyncio
    async def test_depth(self, client):
        result = await client.market.depth(TEST_SYMBOL, limit=10)
        assert \"bids\" in result
        assert \"asks\" in result
        assert len(result[\"bids\"]) <= 10

class TestOrderAPI:
    @pytest.mark.asyncio
    async def test_create_limit_order(self, client):
        # 获取当前价格
        ticker = await client.market.ticker(TEST_SYMBOL)
        price = float(ticker[\"last_price\"])
        
        # 下限价单
        order = await client.order.create(
            symbol=TEST_SYMBOL,
            side=\"buy\",
            order_type=\"limit\",
            qty=\"0.001\",
            price=str(price * 0.99)  # 低于市价
        )
        
        assert \"id\" in order
        assert order[\"status\"] in [\"new\", \"open\"]
        
        # 清理: 取消订单
        await client.order.cancel(order[\"id\"], TEST_SYMBOL)

class TestWebSocket:
    @pytest.mark.asyncio
    async def test_price_stream(self, client):
        prices = []
        
        async def on_price(price):
            prices.append(price)
        
        await client.ws.connect()
        await client.ws.subscribe_price(TEST_SYMBOL, on_price)
        
        # 等待 5 秒收集数据
        await asyncio.sleep(5)
        
        await client.ws.disconnect()
        
        assert len(prices) > 0
        assert \"last_price\" in prices[0]

2.4 验收标准

2.4.1 功能验收

功能 验收条件
初始化 私钥或 JWT 可正常初始化
市场数据 ticker/depth/trades/kline 全部返回正确数据
账户 positions/balances/orders 全部正常
订单 create/cancel/cancel-all 全部正常
WebSocket price/depth/trade 订阅全部正常
认证 JWT 生成和验证正确

2.4.2 性能验收

指标 目标
API 响应时间 < 1 秒
WebSocket 延迟 < 500ms
SDK 启动时间 < 2 秒
内存占用 < 50MB (空闲)

2.4.3 错误处理验收

场景 预期行为
网络超时 抛出 TimeoutError
认证失败 抛出 AuthError
订单失败 抛出 OrderError 并包含原因
WebSocket 断开 自动重连 (最多 3 次)
限价单价格无效 抛出 ValidationError

三、发布计划

版本 功能 状态
0.1.0 MVP - 基础 REST API TODO
0.2.0 WebSocket 支持 TODO
0.3.0 策略模板 (网格) TODO
1.0.0 正式版 TODO

四、后续扩展

  • 策略回测框架
  • 多账户管理
  • 交易信号生成
  • 风险管理模块

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions