Skip to main content

Event-Driven Design

Havklo delivers all data through a channel-based event system. Your application receives events and reacts - no polling required.
let mut events = client.events();

while let Some(event) = events.recv().await {
    match event {
        Event::Market(market) => { /* price data */ }
        Event::Connection(conn) => { /* lifecycle */ }
        Event::Subscription(sub) => { /* channel status */ }
        Event::Private(priv_) => { /* account data */ }
        Event::L3(l3) => { /* order-level */ }
        Event::BufferOverflow { dropped_count } => { /* backpressure */ }
    }
}

Event Types

Real-time market data:
pub enum MarketEvent {
    OrderbookSnapshot {
        symbol: String,
        snapshot: OrderbookSnapshot,
    },
    OrderbookUpdate {
        symbol: String,
        snapshot: OrderbookSnapshot,
    },
    ChecksumMismatch {
        symbol: String,
        expected: u32,
        computed: u32,
    },
    Heartbeat,
}
Usage:
Event::Market(MarketEvent::OrderbookUpdate { symbol, snapshot }) => {
    let spread = snapshot.spread();
    let mid = snapshot.mid_price();
    println!("{}: spread={:?}, mid={:?}", symbol, spread, mid);
}

OrderbookSnapshot

The snapshot contains full orderbook state:
pub struct OrderbookSnapshot {
    pub symbol: String,
    pub timestamp: String,      // ISO 8601
    pub bids: Vec<Level>,       // High to low
    pub asks: Vec<Level>,       // Low to high
    pub checksum: u32,
    pub state: OrderbookState,
}

impl OrderbookSnapshot {
    pub fn best_bid(&self) -> Option<&Level>;
    pub fn best_ask(&self) -> Option<&Level>;
    pub fn spread(&self) -> Option<Decimal>;
    pub fn mid_price(&self) -> Option<Decimal>;
}
Event::Market(MarketEvent::OrderbookUpdate { symbol, snapshot }) => {
    // Access computed values
    let spread = snapshot.spread().unwrap_or_default();

    // Access raw levels
    for bid in snapshot.bids.iter().take(5) {
        println!("Bid: {} @ {}", bid.qty, bid.price);
    }
}

Backpressure

The event channel has bounded capacity (default 1024). If your handler is slow:
Event::BufferOverflow { dropped_count } => {
    log::warn!("Dropped {} events - handler too slow", dropped_count);
}
BufferOverflow means you’re not keeping up. Consider processing faster, increasing capacity, or filtering events.

Event Filtering

Reduce noise at subscription time:
let client = KrakenClient::builder(symbols)
    .with_event_filter(
        EventFilter::new()
            .only_market()        // No connection events
            .exclude_heartbeats() // No heartbeat spam
    )
    .connect()
    .await?;