minicheddar / crypto-stream

High performance market data handlers for cryptocurrency exchanges
MIT License
4 stars 1 forks source link
binance ccxt coinbase cryptocurrency exchange gate-io huobi kraken okx websocket

crypto-stream

An experiment in unifying multiple cryptocurrency exchange streams under a single API. Think CCXT websockets, but in Rust.

:construction: This library is an active work in progress and not yet suitable for production use :construction:


animated

Features:

Roadmap:

Getting started:

$ cargo run --example combine_books --release

or

use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;

use crypto_stream::{
    build_venue_subscriptions,
    model::*,
    orderbook::CrossVenueOrderBook,
    subscriptions_into_stream,
    tui::{render_orderbook, setup_terminal_ui},
    websocket::{WebsocketSubscription, WebsocketSubscriptionKind},
};
use futures::StreamExt;
use std::time::{Duration, Instant};
use std::vec;

#[tokio::main]
async fn main() {
    let subscriptions = vec![
        WebsocketSubscription::new(
            Venue::BinanceSpot,
            "BTC",
            "USDT",
            InstrumentKind::Spot,
            WebsocketSubscriptionKind::Quote,
        ),
        WebsocketSubscription::new(
            Venue::GateIO,
            "BTC",
            "USDT",
            InstrumentKind::Spot,
            WebsocketSubscriptionKind::Quote,
        ),
        WebsocketSubscription::new(
            Venue::Okx,
            "BTC",
            "USDT",
            InstrumentKind::Spot,
            WebsocketSubscriptionKind::Quote,
        ),
    ];

    // subscribe to websockets for each venue
    let venue_subs = build_venue_subscriptions(subscriptions);

    // combine each venues websocket stream into a combined stream
    let mut market_data = subscriptions_into_stream(venue_subs).await;

    // initialise TUI
    let mut terminal = setup_terminal_ui();
    const TICK_RATE: Duration = Duration::from_millis(100);
    let mut last_draw = Instant::now();

    let mut cross_book = CrossVenueOrderBook::new("BTC/USD".to_string(), 10);
    while let Some(msg) = market_data.next().await {
        // map quote streams to combined orderbook levels
        cross_book.update(&msg);
        let levels = cross_book.to_levels(cross_book.depth);

        // throttle TUI updates to every 100ms
        if last_draw.elapsed() > TICK_RATE {
            last_draw = Instant::now();

            // render combined orderbook in terminal
            terminal
                .draw(|f| render_orderbook(f, &cross_book.symbol, levels))
                .expect("error rendering TUI");
        }
    }
}