Skip to main content

bybit_rust_api/ws/public/
orderbook.rs

1//! Real-time orderbook stream with snapshot/delta processing.
2//!
3//! Bybit pushes a full `snapshot` on subscription, then incremental `delta`
4//! updates. This module provides a simple consumer that yields each update
5//! as-is — local orderbook reconstruction is left to the caller.
6//!
7//! # Topic format
8//! `orderbook.{depth}.{symbol}` — e.g. `orderbook.1.BTCUSDT`
9//!
10//! # Depths
11//! - Linear/Inverse: 1, 50, 200, 1000
12//! - Spot: 1, 50, 200, 1000
13//! - Option: 25, 100
14
15use serde::Deserialize;
16
17/// A single price level in the orderbook.
18#[derive(Debug, Clone, Deserialize)]
19pub struct OrderBookLevel {
20    /// Price as string (to preserve precision)
21    #[serde(rename = "0")]
22    pub price: String,
23    /// Size/quantity as string
24    #[serde(rename = "1")]
25    pub size: String,
26}
27
28/// Orderbook snapshot or delta data from Bybit.
29#[derive(Debug, Clone, Deserialize)]
30pub struct OrderBookData {
31    /// Symbol (e.g. "BTCUSDT")
32    #[serde(rename = "s")]
33    pub symbol: String,
34    /// Bids: array of [price, size] pairs
35    #[serde(rename = "b")]
36    pub bids: Vec<OrderBookLevel>,
37    /// Asks: array of [price, size] pairs
38    #[serde(rename = "a")]
39    pub asks: Vec<OrderBookLevel>,
40    /// Update ID (monotonically increasing)
41    #[serde(rename = "u")]
42    pub update_id: u64,
43    /// Sequence number
44    #[serde(rename = "seq")]
45    #[serde(default)]
46    pub seq: Option<u64>,
47    /// Cross sequence (for snapshot)
48    #[serde(rename = "cts")]
49    #[serde(default)]
50    pub cts: Option<u64>,
51    /// Message type: "snapshot" or "delta"
52    #[serde(rename = "type")]
53    pub msg_type: String,
54}
55
56/// High-level typed wrapper around raw WsMessage for orderbook.
57///
58/// Callers should:
59/// 1. Filter by topic matching `orderbook.{depth}.{symbol}`
60/// 2. Deserialize `data` field into `OrderBookData`
61/// 3. On first message (type="snapshot"), initialize local OB
62/// 4. On subsequent messages (type="delta"), apply updates
63pub struct OrderBookStream;
64
65impl OrderBookStream {
66    /// Parse raw WS data into typed OrderBookData.
67    pub fn parse(data: &serde_json::Value) -> serde_json::Result<OrderBookData> {
68        serde_json::from_value(data.clone())
69    }
70
71    /// Check if the given topic matches an orderbook channel.
72    pub fn matches_topic(topic: &str) -> bool {
73        topic.starts_with("orderbook.")
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    #[test]
82    fn test_parse_snapshot() {
83        let json = serde_json::json!({
84            "s": "BTCUSDT",
85            "b": [["50000.00", "1.5"], ["49900.00", "2.0"]],
86            "a": [["50100.00", "1.0"], ["50200.00", "0.5"]],
87            "u": 1,
88            "seq": 100,
89            "type": "snapshot"
90        });
91
92        let data: OrderBookData = serde_json::from_value(json).unwrap();
93        assert_eq!(data.symbol, "BTCUSDT");
94        assert_eq!(data.bids.len(), 2);
95        assert_eq!(data.asks.len(), 2);
96        assert_eq!(data.bids[0].price, "50000.00");
97        assert_eq!(data.bids[0].size, "1.5");
98        assert_eq!(data.msg_type, "snapshot");
99    }
100
101    #[test]
102    fn test_parse_delta() {
103        let json = serde_json::json!({
104            "s": "ETHUSDT",
105            "b": [],
106            "a": [["3000.00", "0.1"]],
107            "u": 105,
108            "seq": 105,
109            "type": "delta"
110        });
111
112        let data: OrderBookData = serde_json::from_value(json).unwrap();
113        assert_eq!(data.symbol, "ETHUSDT");
114        assert_eq!(data.asks.len(), 1);
115        assert_eq!(data.msg_type, "delta");
116    }
117
118    #[test]
119    fn test_matches_topic() {
120        assert!(OrderBookStream::matches_topic("orderbook.1.BTCUSDT"));
121        assert!(OrderBookStream::matches_topic("orderbook.50.ETHUSDT"));
122        assert!(!OrderBookStream::matches_topic("publicTrade.BTCUSDT"));
123    }
124}