Skip to main content

bybit/models/
rpi_orderbook_update.rs

1use crate::prelude::*;
2
3/// Structure for WebSocket RPI (Real-time Price Improvement) order book update events.
4///
5/// Contains real-time updates to the RPI order book for a trading pair, including bids, asks,
6/// RPI sizes, and sequence numbers. RPI orders can provide price improvement for takers.
7/// Bots use this for market depth analysis with RPI information and liquidity monitoring.
8#[derive(Serialize, Deserialize, Debug, Clone)]
9#[serde(rename_all = "camelCase")]
10pub struct RPIOrderbookUpdate {
11    /// The WebSocket topic for the event (e.g., "orderbook.rpi.BTCUSDT").
12    ///
13    /// Specifies the data stream for the RPI order book update, including depth and symbol.
14    /// Bots use this to verify the correct market and RPI depth level.
15    #[serde(rename = "topic")]
16    pub topic: String,
17
18    /// The event type (e.g., "snapshot", "delta").
19    ///
20    /// Indicates whether the update is a full snapshot or incremental delta.
21    /// Bots use this to initialize or update their RPI order book state.
22    #[serde(rename = "type")]
23    pub event_type: String,
24
25    /// The timestamp of the event in milliseconds.
26    ///
27    /// Indicates when the RPI order book update was generated.
28    /// Bots use this to ensure data freshness and align with other market data.
29    #[serde(rename = "ts")]
30    pub timestamp: u64,
31
32    /// The RPI order book data.
33    ///
34    /// Contains the bids, asks with RPI information, and sequence numbers for the order book.
35    /// Bots use this to update their internal RPI order book representation.
36    pub data: RPIOrderbook,
37
38    /// The creation timestamp in milliseconds.
39    ///
40    /// Indicates when the RPI order book update was created by Bybit’s matching engine.
41    /// Bots use this to measure latency and ensure data consistency.
42    pub cts: u64,
43}
44
45impl RPIOrderbookUpdate {
46    /// Returns the symbol from the topic.
47    ///
48    /// Extracts the trading pair symbol from the WebSocket topic.
49    /// Example: "orderbook.rpi.BTCUSDT" -> "BTCUSDT"
50    pub fn symbol_from_topic(&self) -> Option<&str> {
51        self.topic.split('.').last()
52    }
53
54    /// Returns true if this is a snapshot update.
55    ///
56    /// Snapshot updates contain the full order book state and should replace the local order book.
57    pub fn is_snapshot(&self) -> bool {
58        self.event_type == "snapshot"
59    }
60
61    /// Returns true if this is a delta update.
62    ///
63    /// Delta updates contain incremental changes and should be applied to the local order book.
64    pub fn is_delta(&self) -> bool {
65        self.event_type == "delta"
66    }
67
68    /// Returns the processing latency in milliseconds.
69    ///
70    /// Calculates the difference between the matching engine timestamp (cts) and
71    /// the system generation timestamp (ts).
72    pub fn processing_latency_ms(&self) -> i64 {
73        if self.cts > self.timestamp {
74            (self.cts - self.timestamp) as i64
75        } else {
76            (self.timestamp - self.cts) as i64
77        }
78    }
79
80    /// Returns the timestamp as a chrono DateTime.
81    pub fn timestamp_datetime(&self) -> chrono::DateTime<chrono::Utc> {
82        chrono::DateTime::from_timestamp((self.timestamp / 1000) as i64, 0)
83            .unwrap_or_else(chrono::Utc::now)
84    }
85
86    /// Returns the creation timestamp as a chrono DateTime.
87    pub fn creation_datetime(&self) -> chrono::DateTime<chrono::Utc> {
88        chrono::DateTime::from_timestamp((self.cts / 1000) as i64, 0)
89            .unwrap_or_else(chrono::Utc::now)
90    }
91
92    /// Returns the best ask price (lowest ask).
93    pub fn best_ask(&self) -> Option<f64> {
94        self.data.best_ask()
95    }
96
97    /// Returns the best bid price (highest bid).
98    pub fn best_bid(&self) -> Option<f64> {
99        self.data.best_bid()
100    }
101
102    /// Returns the best ask with RPI information.
103    pub fn best_ask_with_rpi(&self) -> Option<&RPIOrderbookLevel> {
104        self.data.best_ask_with_rpi()
105    }
106
107    /// Returns the best bid with RPI information.
108    pub fn best_bid_with_rpi(&self) -> Option<&RPIOrderbookLevel> {
109        self.data.best_bid_with_rpi()
110    }
111
112    /// Returns the bid-ask spread.
113    pub fn spread(&self) -> Option<f64> {
114        self.data.spread()
115    }
116
117    /// Returns the mid price (average of best bid and ask).
118    pub fn mid_price(&self) -> Option<f64> {
119        self.data.mid_price()
120    }
121
122    /// Returns the spread as a percentage of mid price.
123    pub fn spread_percentage(&self) -> Option<f64> {
124        self.data.spread_percentage()
125    }
126
127    /// Returns the total RPI size on the ask side.
128    pub fn total_ask_rpi_size(&self) -> f64 {
129        self.data.total_ask_rpi_size()
130    }
131
132    /// Returns the total non-RPI size on the ask side.
133    pub fn total_ask_non_rpi_size(&self) -> f64 {
134        self.data.total_ask_non_rpi_size()
135    }
136
137    /// Returns the total RPI size on the bid side.
138    pub fn total_bid_rpi_size(&self) -> f64 {
139        self.data.total_bid_rpi_size()
140    }
141
142    /// Returns the total non-RPI size on the bid side.
143    pub fn total_bid_non_rpi_size(&self) -> f64 {
144        self.data.total_bid_non_rpi_size()
145    }
146
147    /// Returns the average RPI ratio on the ask side.
148    pub fn average_ask_rpi_ratio(&self) -> f64 {
149        self.data.average_ask_rpi_ratio()
150    }
151
152    /// Returns the average RPI ratio on the bid side.
153    pub fn average_bid_rpi_ratio(&self) -> f64 {
154        self.data.average_bid_rpi_ratio()
155    }
156
157    /// Returns the bid-ask RPI ratio difference.
158    pub fn rpi_ratio_imbalance(&self) -> f64 {
159        self.data.rpi_ratio_imbalance()
160    }
161
162    /// Returns the order book imbalance considering RPI sizes.
163    pub fn order_book_imbalance_with_rpi(&self) -> f64 {
164        self.data.order_book_imbalance_with_rpi()
165    }
166
167    /// Returns the liquidity score considering RPI availability.
168    pub fn liquidity_score_with_rpi(&self) -> f64 {
169        self.data.liquidity_score_with_rpi()
170    }
171
172    /// Returns the expected price improvement for takers.
173    pub fn expected_taker_improvement(&self, is_buy: bool, quantity: f64) -> Option<f64> {
174        self.data.expected_taker_improvement(is_buy, quantity)
175    }
176
177    /// Returns the price impact for a given quantity considering RPI.
178    pub fn ask_price_impact_with_rpi(&self, quantity: f64) -> Option<f64> {
179        self.data.ask_price_impact_with_rpi(quantity)
180    }
181
182    /// Returns the price impact for a given quantity considering RPI.
183    pub fn bid_price_impact_with_rpi(&self, quantity: f64) -> Option<f64> {
184        self.data.bid_price_impact_with_rpi(quantity)
185    }
186
187    /// Returns the weighted average ask price considering RPI improvement.
188    pub fn weighted_average_ask_price_with_rpi(&self, target_quantity: f64) -> Option<f64> {
189        self.data
190            .weighted_average_ask_price_with_rpi(target_quantity)
191    }
192
193    /// Returns the weighted average bid price considering RPI improvement.
194    pub fn weighted_average_bid_price_with_rpi(&self, target_quantity: f64) -> Option<f64> {
195        self.data
196            .weighted_average_bid_price_with_rpi(target_quantity)
197    }
198}