CCXT
Rust Examples

Ws Typed Demo

Ws Typed Demo — CCXT Rust code example.

// Typed WebSocket API demo — the `ccxt_pro::<Exchange>` wrappers expose each
// `watch_*` method with a native Rust return type (one decoded update per call)
// instead of the dynamic `Value`. This is the WS analog of `iexchange_demo`
// (REST).
//
// This demo actually connects and consumes a few live updates from binance's
// public streams. No credentials, no private data.
//
// Build/run: `cargo run --bin ws_typed_demo --features ws`
use ccxt::Params;
use ccxt_pro::{Binance, TypedExchange, TypedExchangeExt};

const SYMBOL: &str = "BTC/USDT";
const UPDATES: usize = 3;

#[tokio::main]
async fn main() {
    println!("=== ccxt_pro typed watch_* demo — binance {SYMBOL} ===\n");

    // ── A. concrete wrapper — typed returns ──────────────────────────────────
    let mut b = Binance::new(None);
    b.load_markets(false).await;

    // Each typed `watch_*` resolves to one decoded, statically-typed update,
    // so consuming a stream is just calling it in a loop.
    println!("→ watch_ticker -> Ticker");
    for i in 1..=UPDATES {
        match b.watch_ticker(SYMBOL, Params::none()).await {
            Ok(t) => println!("   #{i} last={:?} bid={:?} ask={:?}", t.last, t.bid, t.ask),
            Err(e) => {
                eprintln!("   x [{}] {}", e.kind, e.message);
                break;
            }
        }
    }

    // `limit` is best-effort: some venues only publish a full book, so expect
    // more levels than requested.
    println!("\n→ watch_order_book -> OrderBook");
    for i in 1..=UPDATES {
        match b.watch_order_book(SYMBOL, Some(20), Params::none()).await {
            Ok(ob) => println!(
                "   #{i} bids={} asks={} top_bid={:?}",
                ob.bids.len(),
                ob.asks.len(),
                ob.bids.first()
            ),
            Err(e) => {
                eprintln!("   x [{}] {}", e.kind, e.message);
                break;
            }
        }
    }

    // One update carries the batch of trades the venue published.
    println!("\n→ watch_trades -> Vec<Trade>");
    for i in 1..=UPDATES {
        match b.watch_trades(SYMBOL, None, Some(50), Params::none()).await {
            Ok(tr) => println!(
                "   #{i} {} trade(s), first px={:?} amount={:?}",
                tr.len(),
                tr.first().and_then(|t| t.price),
                tr.first().and_then(|t| t.amount)
            ),
            Err(e) => {
                eprintln!("   x [{}] {}", e.kind, e.message);
                break;
            }
        }
    }

    // ── B. generic / dynamic via the `ccxt_pro::TypedExchange` trait ─────────
    // Same object-safe pattern as the REST `iexchange_demo`, but over `watch_*`.
    println!("\n→ same surface through Box<dyn TypedExchange>");
    let mut ex: Box<dyn TypedExchange> = Box::new(Binance::new(None));
    ex.load_markets(false).await;
    match ex.watch_ticker(SYMBOL, Params::none()).await {
        Ok(t) => println!("   last={:?}", t.last),
        Err(e) => eprintln!("   x [{}] {}", e.kind, e.message),
    }

    println!("\ndone.");
}