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}