bybit/general.rs
1use crate::prelude::*;
2use chrono::{DateTime, Utc};
3
4#[derive(Clone)]
5pub struct General {
6 pub client: Client,
7}
8
9/// The `General` struct provides general API functionality for the Bybit exchange.
10///
11/// This module includes methods for checking connectivity, retrieving server time,
12/// and getting system status information. These endpoints are essential for
13/// synchronizing trading operations with Bybit's servers and monitoring platform health.
14impl General {
15 /// Tests connectivity to the Bybit API server.
16 ///
17 /// This method sends a request to the server time endpoint to verify that
18 /// the API is accessible and responsive. It's useful for health checks
19 /// and connection monitoring in trading applications.
20 ///
21 /// # Returns
22 ///
23 /// Returns `Ok(true)` if the server responds successfully, or `Ok(false)` if
24 /// the server responds with an error. Returns `Err(BybitError)` for network
25 /// or other critical failures.
26 ///
27 /// # Examples
28 ///
29 /// ```no_run
30 /// use bybit::prelude::*;
31 ///
32 /// #[tokio::main]
33 /// async fn main() {
34 /// let general = General::new(None, None);
35 /// match general.ping().await {
36 /// Ok(true) => println!("Connected to Bybit API"),
37 /// Ok(false) => println!("Bybit API responded with an error"),
38 /// Err(e) => println!("Connection failed: {:?}", e),
39 /// }
40 /// }
41 /// ```
42 pub async fn ping(&self) -> Result<bool, BybitError> {
43 match self
44 .client
45 .get::<ServerTimeResponse>(API::Market(Market::Time), None)
46 .await
47 {
48 Ok(_) => Ok(true),
49 Err(BybitError::BybitError(content_error)) => {
50 // Server responded but with an error code
51 log::debug!(
52 "Server responded with error: code={}, msg={}",
53 content_error.code,
54 content_error.msg
55 );
56 Ok(false)
57 }
58 Err(e) => Err(e),
59 }
60 }
61
62 /// Retrieves the current server time from Bybit with high precision.
63 ///
64 /// This endpoint returns the server time in seconds and nanoseconds since
65 /// the Unix epoch. Accurate server time is critical for synchronizing
66 /// trading bot operations and avoiding timestamp-related errors in API requests.
67 ///
68 /// # Returns
69 ///
70 /// Returns a `Result` containing a `ServerTimeResponse` if successful,
71 /// or a `BybitError` if an error occurs.
72 ///
73 /// # Examples
74 ///
75 /// ```no_run
76 /// use bybit::prelude::*;
77 ///
78 /// #[tokio::main]
79 /// async fn main() {
80 /// let general = General::new(None, None);
81 /// match general.get_server_time().await {
82 /// Ok(response) => {
83 /// println!("Server time: {} seconds", response.result.time_second);
84 /// println!("Nanosecond component: {}", response.result.time_nano);
85 /// }
86 /// Err(e) => println!("Failed to get server time: {:?}", e),
87 /// }
88 /// }
89 /// ```
90 pub async fn get_server_time(&self) -> Result<ServerTimeResponse, BybitError> {
91 self.client.get(API::Market(Market::Time), None).await
92 }
93
94 /// Retrieves the server time as a `chrono::DateTime<Utc>` object.
95 ///
96 /// This is a convenience method that converts the server time response
97 /// into a more usable DateTime format for time calculations and comparisons.
98 ///
99 /// # Returns
100 ///
101 /// Returns a `Result` containing a `DateTime<Utc>` if successful,
102 /// or a `BybitError` if an error occurs.
103 ///
104 /// # Examples
105 ///
106 /// ```no_run
107 /// use bybit::prelude::*;
108 /// use chrono::{DateTime, Utc};
109 ///
110 /// #[tokio::main]
111 /// async fn main() {
112 /// let general = General::new(None, None);
113 /// match general.get_server_datetime().await {
114 /// Ok(dt) => println!("Server datetime: {}", dt),
115 /// Err(e) => println!("Failed to get server datetime: {:?}", e),
116 /// }
117 /// }
118 /// ```
119 pub async fn get_server_datetime(&self) -> Result<DateTime<Utc>, BybitError> {
120 let response = self.get_server_time().await?;
121
122 // Convert seconds to DateTime
123 let secs = response.result.time_second as i64;
124 let nanos = (response.result.time_nano % 1_000_000_000) as u32;
125
126 DateTime::<Utc>::from_timestamp(secs, nanos)
127 .ok_or_else(|| BybitError::Base("Invalid timestamp from server".to_string()))
128 }
129
130 /// Retrieves the server time in milliseconds since the Unix epoch.
131 ///
132 /// This is a convenience method that returns the server time in milliseconds,
133 /// which is commonly used for API request timestamps and performance measurements.
134 ///
135 /// # Returns
136 ///
137 /// Returns a `Result` containing milliseconds as `u64` if successful,
138 /// or a `BybitError` if an error occurs.
139 ///
140 /// # Examples
141 ///
142 /// ```no_run
143 /// use bybit::prelude::*;
144 ///
145 /// #[tokio::main]
146 /// async fn main() {
147 /// let general = General::new(None, None);
148 /// match general.get_server_time_millis().await {
149 /// Ok(ms) => println!("Server time in milliseconds: {}", ms),
150 /// Err(e) => println!("Failed to get server time: {:?}", e),
151 /// }
152 /// }
153 /// ```
154 pub async fn get_server_time_millis(&self) -> Result<u64, BybitError> {
155 let response = self.get_server_time().await?;
156
157 // Calculate milliseconds: seconds * 1000 + nanoseconds / 1_000_000
158 let millis = response.result.time_second * 1000 + response.result.time_nano / 1_000_000;
159 Ok(millis)
160 }
161
162 /// Retrieves the current timestamp for API requests.
163 ///
164 /// Bybit requires request timestamps to be within ±5 seconds of server time.
165 /// This method returns the current server time in the format expected by
166 /// Bybit API endpoints (milliseconds as string).
167 ///
168 /// # Returns
169 ///
170 /// Returns a `Result` containing the timestamp as a `String` if successful,
171 /// or a `BybitError` if an error occurs.
172 ///
173 /// # Examples
174 ///
175 /// ```no_run
176 /// use bybit::prelude::*;
177 ///
178 /// #[tokio::main]
179 /// async fn main() {
180 /// let general = General::new(None, None);
181 /// match general.get_api_timestamp().await {
182 /// Ok(timestamp) => println!("API timestamp: {}", timestamp),
183 /// Err(e) => println!("Failed to get API timestamp: {:?}", e),
184 /// }
185 /// }
186 /// ```
187 pub async fn get_api_timestamp(&self) -> Result<String, BybitError> {
188 let millis = self.get_server_time_millis().await?;
189 Ok(millis.to_string())
190 }
191
192 /// Retrieves the system status from the Bybit API.
193 ///
194 /// This endpoint returns information about platform maintenance or service incidents.
195 /// It's useful for monitoring platform health and scheduling maintenance windows.
196 ///
197 /// # Parameters
198 ///
199 /// * `id` - Optional unique identifier for filtering system status records
200 /// * `state` - Optional system state for filtering (e.g., "completed", "in_progress", "scheduled")
201 ///
202 /// # Returns
203 ///
204 /// Returns a `Result` containing a `SystemStatusResponse` if successful,
205 /// or a `BybitError` if an error occurs.
206 ///
207 /// # Examples
208 ///
209 /// ```no_run
210 /// use bybit::prelude::*;
211 ///
212 /// #[tokio::main]
213 /// async fn main() {
214 /// let general = General::new(None, None);
215 ///
216 /// // Get all system status records
217 /// match general.get_system_status(None, None).await {
218 /// Ok(response) => println!("System status: {:?}", response),
219 /// Err(e) => println!("Failed to get system status: {:?}", e),
220 /// }
221 ///
222 /// // Get only completed incidents
223 /// match general.get_system_status(None, Some("completed".to_string())).await {
224 /// Ok(response) => println!("Completed incidents: {:?}", response),
225 /// Err(e) => println!("Failed to get completed incidents: {:?}", e),
226 /// }
227 /// }
228 /// ```
229 pub async fn get_system_status(
230 &self,
231 id: Option<String>,
232 state: Option<String>,
233 ) -> Result<SystemStatusResponse, BybitError> {
234 // Build query parameters
235 let mut params = BTreeMap::new();
236 if let Some(id_value) = id {
237 params.insert("id".to_string(), id_value);
238 }
239 if let Some(state_value) = state {
240 params.insert("state".to_string(), state_value);
241 }
242
243 // Build request string from parameters
244 let request = build_request(¶ms);
245
246 // Call the get method on the client field of self
247 self.client
248 .get(API::Market(Market::SystemStatus), Some(request))
249 .await
250 }
251}