precolator-sdk 1.0.0

Rust async client SDK for the Precolator perpetual futures trading platform — markets, portfolio, leaderboard, and trading statistics.
Documentation
# precolator-sdk

> Async Rust client SDK for the **Precolator** perpetual futures trading platform on Solana.

[![Crates.io](https://img.shields.io/crates/v/precolator-sdk)](https://crates.io/crates/precolator-sdk)
[![docs.rs](https://docs.rs/precolator-sdk/badge.svg)](https://docs.rs/precolator-sdk)
[![License](https://img.shields.io/crates/l/precolator-sdk)](LICENSE)

## Features

- **Full API coverage** — markets, portfolio, trades, leaderboard, tokens, statistics
- **Strongly typed** — every endpoint returns a concrete Rust struct
- **Async-first** — built on `tokio` + `reqwest`
- **Configurable** — point at mainnet, devnet, or your own deployment
- **Rate-limit aware** — detects 429 responses and surfaces them as typed errors

## Quick Start

```toml
[dependencies]
precolator-sdk = "1.0"
tokio = { version = "1", features = ["full"] }
```

```rust
use precolator_sdk::PrecolatorClient;

#[tokio::main]
async fn main() -> precolator_sdk::Result<()> {
    let client = PrecolatorClient::new("https://precolator.xyz");

    // List all markets
    let markets = client.get_markets().await?;
    for m in &markets {
        println!("{}: ${:.2}", m.name, m.price);
    }

    // Fetch a user portfolio
    let portfolio = client.get_portfolio("5TfY...xQw").await?;
    println!("Balance: {:.2}  PnL: {:.2}", portfolio.total_balance, portfolio.unrealized_pnl);

    // Platform stats
    let stats = client.get_platform_stats().await?;
    println!("Total volume: ${:.0}", stats.total_volume);

    Ok(())
}
```

## Available Methods

| Method | Endpoint |
|--------|----------|
| `health()` | `GET /api/v1/health` |
| `health_detailed()` | `GET /api/v1/health/detailed` |
| `get_markets()` | `GET /api/v1/markets` |
| `get_market(id)` | `GET /api/v1/markets/:id` |
| `get_market_stats(id)` | `GET /api/v1/markets/:id/stats` |
| `get_trades()` | `GET /api/v1/trades` |
| `get_trade(id)` | `GET /api/v1/trades/:tradeId` |
| `get_user_trades(wallet)` | `GET /api/v1/trades/user/:wallet` |
| `get_portfolio(wallet)` | `GET /api/v1/portfolio/:wallet` |
| `get_portfolio_history(wallet)` | `GET /api/v1/portfolio/:wallet/history` |
| `get_portfolio_stats(wallet)` | `GET /api/v1/portfolio/:wallet/stats` |
| `get_leaderboard()` | `GET /api/v1/leaderboard` |
| `get_leaderboard_by_timeframe(tf)` | `GET /api/v1/leaderboard/:timeframe` |
| `get_tokens()` | `GET /api/v1/tokens` |
| `get_token(symbol)` | `GET /api/v1/tokens/:symbol` |
| `get_platform_stats()` | `GET /api/v1/stats` |
| `get_market_overview()` | `GET /api/v1/stats/markets/overview` |
| `get_exchange_metrics()` | `GET /api/v1/stats/exchange/metrics` |

## Custom HTTP Client

```rust
use reqwest::Client;
use precolator_sdk::PrecolatorClient;
use std::time::Duration;

let http = Client::builder()
    .timeout(Duration::from_secs(10))
    .build()
    .unwrap();

let client = PrecolatorClient::with_client("https://precolator.xyz", http).unwrap();
```

## Error Handling

The SDK uses `PrecolatorError` with variants for HTTP, API, rate-limits, and serialization errors:

```rust
use precolator_sdk::{PrecolatorClient, PrecolatorError};

match client.get_market("INVALID").await {
    Ok(m) => println!("{}", m.name),
    Err(PrecolatorError::NotFound(path)) => eprintln!("Not found: {path}"),
    Err(PrecolatorError::RateLimited { retry_after_secs }) => {
        eprintln!("Rate limited, retry in {retry_after_secs}s");
    }
    Err(e) => eprintln!("Error: {e}"),
}
```

## License

Apache License 2.0 — see [LICENSE](LICENSE) for details.