Skip to main content

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(&params);
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}