Skip to main content

ccxt-rust

CCXT cryptocurrency exchange library for Rust developers. Covers both REST API (standard) and WebSocket API (real-time). Helps install CCXT, connect to exchanges, fetch market data, place orders, stream live tickers/orderbooks, handle authentication, and manage errors in Rust projects. Use when working with crypto exchanges in Rust applications, trading bots, or low-latency services. Async (tokio), typed wrappers returning Result<T, ExchangeError>.

معلومات المصدر

المستودع
ccxt/ccxt
آخر نشاط في المصدر
٢١ سبتمبر ٢٠٢٦ في ١١:٤٢
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٤٤٬٣٩٣
التفرعات
٨٬٨٩٩

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
ccxt-rust
description
CCXT cryptocurrency exchange library for Rust developers. Covers both REST API (standard) and WebSocket API (real-time). Helps install CCXT, connect to exchanges, fetch market data, place orders, stream live tickers/orderbooks, handle authentication, and manage errors in Rust projects. Use when working with crypto exchanges in Rust applications, trading bots, or low-latency services. Async (tokio), typed wrappers returning Result<T, ExchangeError>.
# CCXT for Rust A comprehensive guide to using CCXT in Rust projects for cryptocurrency exchange integration. Every exchange has a **typed wrapper** (`ccxt::Binance`, `ccxt::Kraken`, …) exposing the unified CCXT API with native Rust return types — `Ticker`, `Order`, `OrderBook`, `Market` — instead of a dynamic value. All methods are `async` and return `Result<T, ExchangeError>`. ## Installation ### REST API ```bash cargo add ccxt tokio --features tokio/full ``` ### WebSocket API (ccxt.pro) ```bash cargo add ccxt-pro ``` ### Prediction markets ```bash cargo add ccxt-prediction ``` ### Cargo.toml ```toml [dependencies] ccxt = "4.5.75" # REST exchanges (typed) — required ccxt-pro = "4.5.75" # WebSocket (watch*) exchanges — only if you stream ccxt-prediction = "4.5.75" # prediction markets — only if you trade them tokio = { version = "1", features = ["full"] } ``` ### Requirements - Rust **stable**, edition 2021 or later. - A **tokio** runtime — every unified method is `async`. There is no sync API. - `ccxt` alone is enough for REST. Add `ccxt-pro` only when you need `watch_*`; it is a separate crate so a REST-only build does not compile the whole WebSocket surface. ## Quick Start ### REST API ```rust use ccxt::{Binance, Params}; #[tokio::main] async fn main() -> Result<(), ccxt::ExchangeError> { let mut exchange = Binance::new(None); exchange.load_markets(false).await; let ticker = exchange.fetch_ticker("BTC/USDT", Params::none()).await?; println!("{} last={:?} bid={:?} ask={:?}", ticker.symbol, ticker.last, ticker.bid, ticker.ask); Ok(()) } ``` ### WebSocket API — real-time updates ```rust use ccxt::Params; use ccxt_pro::Binance; #[tokio::main] async fn main() -> Result<(), ccxt::ExchangeError> { let mut exchange = Binance::new(None); exchange.try_load_markets(false).await?; loop { let ticker = exchange.watch_ticker("BTC/USDT", Params::none()).await?; println!("{:?}", ticker.last); // live updates } } ``` Each `watch_*` call resolves to **one** decoded update, so consuming a stream is just calling it in a loop. ## Crate layout | Crate | Contains | Use when | |---|---|---| | `ccxt` | Typed REST wrappers (`ccxt::Binance`, …), `Params`, `Config`, `types::*`, `TypedExchange`. Re-exports the whole engine at its root. | Always | | `ccxt-pro` | Typed WebSocket wrappers (`ccxt_pro::Binance`, …) with `watch_*` | Streaming | | `ccxt-prediction` | Typed prediction-market wrappers (`ccxt_prediction::Kalshi`, …) | Prediction markets | | `ccxt-base` | The untyped engine (`Value`, HTTP, crypto, rate limiter, Cores, WS infra) | Rarely direct — `ccxt` re-exports it | `ccxt` re-exports `ccxt-base` at its root, so `ccxt::Value`, `ccxt::runtime::…`, `ccxt::exchanges::binance::BinanceCore` resolve alongside the typed `ccxt::Binance`. Coverage today: **105** typed REST venues, **76** typed WebSocket venues, **7** prediction venues. ## REST vs WebSocket | Feature | REST API | WebSocket API | |---------|----------|---------------| | **Use for** | One-time queries, placing orders | Real-time monitoring, live price feeds | | **Crate** | `ccxt` | `ccxt-pro` | | **Import** | `use ccxt::Binance;` | `use ccxt_pro::Binance;` | | **Methods** | `fetch_*` (`fetch_ticker`, `fetch_order_book`) | `watch_*` (`watch_ticker`, `watch_order_book`) | | **Speed** | Slower (HTTP request/response) | Faster (persistent connection) | | **Rate limits** | Strict (1–2 req/sec) | More lenient (continuous stream) | | **Best for** | Trading, account management | Price monitoring, arbitrage detection | Both crates expose a type named `Binance`. When you use both in one file, alias one of them: ```rust use ccxt::Binance as BinanceRest; use ccxt_pro::Binance as BinanceWs; ``` ## Runtime setup Two settings matter in real programs and are easy to miss: ```rust fn main() { // 1. The transpiled core signals errors by panicking across an internal // catch_unwind; the typed layer turns that back into `Result`. Silencing // the default hook stops caught panics from printing to stderr. // Set CCXT_SHOW_PANICS=1 to see them while debugging. if std::env::var("CCXT_SHOW_PANICS").is_err() { std::panic::set_hook(Box::new(|_| {})); } // 2. The generated exchange code is deeply nested — give worker threads a // large stack. The default 2 MB can overflow on some venues. let rt = tokio::runtime::Builder::new_multi_thread() .worker_threads(2) .thread_stack_size(64 * 1024 * 1024) .enable_all() .build() .unwrap(); rt.block_on(run()); } ``` `#[tokio::main]` is fine for short examples and scripts; use the explicit builder for anything long-running. ## Creating an Exchange Instance ### Public (no authentication) ```rust use ccxt::Binance; let mut exchange = Binance::new(None); ``` ### Private (with credentials), via the `Config` builder ```rust use ccxt::{Binance, Config, Params}; let mut exchange = Binance::with_config( Config::new() .api_key("YOUR_API_KEY") .secret("YOUR_SECRET") .enable_rate_limit(true) // on by default .timeout_ms(10_000) .option_str("defaultType", "swap") .option("fetchMarkets", Params::new().with_strs("types", &["spot", "linear"])), ); ``` `Config` covers every credential (`api_key`, `secret`, `password`, `uid`, `wallet_address`, `private_key`, `token`), plus `sandbox`, `verbose`, `enable_rate_limit`, `rate_limit_ms`, `timeout_ms`, and arbitrary properties via `set_str` / `set_int` / `set_float` / `set_bool`. `options` nests exactly as in the other bindings: `option_str`/`option_int`/`option_bool`/ `option_strs` for a flat key, `option(key, Params)` for a nested object, `options(Params)` for a whole block. Repeated calls deep-merge rather than replace. ### Settings after construction The core's fields are dynamic, and the wrapper derefs read-only, so `exchange.verbose = true` does not compile. Use the setters — they chain: ```rust let mut exchange = Binance::new(None); exchange.set_api_key("YOUR_API_KEY"); exchange.set_secret("YOUR_SECRET"); exchange.set_verbose(true).set_timeout_ms(10_000); exchange.set_enable_rate_limit(true); exchange.set_options(Params::new().with_str("defaultType", "spot")); println!("{} {} {}", exchange.id(), exchange.is_verbose(), exchange.is_sandbox_mode_enabled()); ``` ### Sandbox / testnet ```rust // at construction let mut a = Binance::with_config(Config::new().sandbox(true)); // or afterwards — returns Err(NotSupported) when the venue has no testnet let mut b = Binance::new(None); b.set_sandbox_mode(true)?; ``` ### Choosing an exchange at runtime `from_id` / `from_id_with_config` build any supported venue from its id and hand back a trait object; the typed API stays available through `TypedExchangeExt`. ```rust use ccxt::{from_id_with_config, Config, Params, TypedExchange, TypedExchangeExt}; for id in ["binance", "bybit", "okx"] { let Some(mut exchange) = from_id_with_config(id, Config::new().enable_rate_limit(true)) else { continue; // unknown id }; exchange.load_markets(false).await; let ticker = exchange.fetch_ticker("BTC/USDT", Params::none()).await?; println!("{id} {:?}", ticker.last); } ``` `Box<dyn TypedExchange>` works because `TypedExchange` is object-safe; the ergonomic typed methods live on the blanket `TypedExchangeExt`, so **both traits must be in scope**. The same pair exists in `ccxt_pro` (for `watch_*`) and `ccxt_prediction`. Write generic code the same way: ```rust async fn best_bid<E: TypedExchange + TypedExchangeExt>(ex: &mut E) -> Result<Option<f64>, ccxt::ExchangeError> { Ok(ex.fetch_ticker("BTC/USDT", Params::none()).await?.bid) } ``` ## The `params` argument Every unified method ends with `params` — the venue-specific knobs. On the typed layer that is a `Params` builder over Rust primitives, never a dynamic value: ```rust use ccxt::Params; // nothing extra — these three are equivalent exchange.fetch_ticker("BTC/USDT", Params::none()).await?; exchange.fetch_ticker("BTC/USDT", ()).await?; exchange.fetch_ticker("BTC/USDT", [("recvWindow", "5000")]).await?; // venue-specific extras exchange.create_order( "BTC/USDT", "limit", "buy", 0.001, Some(50_000.0), Params::new() .with_str("clientOrderId", "my-order-1") .with_bool("postOnly", true) .with_str("timeInForce", "GTC") .with_float("triggerPrice", 49_000.0) .with_int("recvWindow", 5_000) .with_strs("clientOrderIds", &["a", "b"]), ).await?; ``` Builders: `with_str`, `with_int`, `with_float`, `with_bool`, `with_strs`, `with_json`, `with_params` (nested object). Entries keep insertion order, which some signing routines depend on. Unified params (`clientOrderId`, `postOnly`, `timeInForce`, `reduceOnly`, `triggerPrice`, …) mean the same thing on every venue — CCXT translates them into whatever the exchange wants on the wire. ## Common REST Operations ### Loading markets ```rust // Untyped, panics on failure — fine for scripts exchange.load_markets(false).await; // Preferred: fallible and typed let markets: Vec<ccxt::types::Market> = exchange.try_load_markets(false).await?; ``` Loading markets is required before any call that resolves a unified symbol. ### Market metadata Trading rules can be checked locally, before sending an order and without an extra request: ```rust let market = exchange.market("BTC/USDT")?; // Err(BadSymbol) when not listed println!("{} {} active={}", market.symbol, market.market_type, market.active); println!("min amount {:?} min cost {:?}", market.limits.amount.min, market.limits.cost.min); println!("amount step {:?} price tick {:?}", market.precision.amount, market.precision.price); let swaps: Vec<_> = exchange.markets().into_iter().filter(|m| m.swap && m.active).collect();
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub