bybit/
account.rs

1use crate::prelude::*;
2
3#[derive(Clone)]
4pub struct AccountManager {
5    pub client: Client,
6    pub recv_window: u16,
7}
8
9impl AccountManager {
10    /// Fetches the wallet balance for a specific account and optional coin.
11    ///
12    /// # Arguments
13    ///
14    /// * `account` - The account type.
15    /// * `coin` - The optional coin.
16    ///
17    /// # Returns
18    ///
19    /// A result containing the wallet balance response or an error.
20    pub async fn get_wallet_balance(
21        &self,
22        account: &str,
23        coin: Option<&str>,
24    ) -> Result<WalletResponse, BybitError> {
25        // Create a new BTreeMap to hold the request parameters.
26        let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
27
28        // Add the account type parameter.
29        parameters.insert("accountType".into(), account.into());
30
31        // Add the coin parameter if it is provided.
32        if let Some(c) = coin {
33            parameters.insert("coin".into(), c.into());
34        }
35
36        // Build the request using the parameters.
37        let request = build_request(&parameters);
38
39        // Send the signed request to the Bybit API and await the response.
40        let response: WalletResponse = self
41            .client
42            .get_signed(
43                API::Account(Account::Balance),
44                self.recv_window,
45                Some(request),
46            )
47            .await?;
48
49        // Return the response.
50        Ok(response)
51    }
52
53    /// Upgrades the current account to UTA.
54    ///
55    /// This function sends a POST request to the Bybit API to upgrade the current account to UTA
56    /// (Unified Trading Account). It awaits the response and returns the result.
57    ///
58    /// # Returns
59    ///
60    /// A result containing the UTA response or an error.
61    pub async fn upgrade_to_uta(&self) -> Result<UTAResponse, BybitError> {
62        // Send a signed POST request to the Bybit API to upgrade the account to UTA.
63        // The request does not require any additional parameters.
64        // The response is deserialized into the `UTAResponse` struct.
65        // The `await?` operator awaits the response and returns an error if the request fails.
66
67        // Send the request and await the response.
68        let response: UTAResponse = self
69            .client
70            .post_signed(API::Account(Account::UpgradetoUTA), self.recv_window, None)
71            .await?;
72
73        // Return the response.
74        Ok(response)
75    }
76
77    /// Retrieves the borrow history for the current account.
78    ///
79    /// This function sends a signed GET request to the Bybit API to retrieve the borrow history for
80    /// the current account. The request can be filtered by the `coin` and `start_time` parameters.
81    /// The response is deserialized into the `BorrowHistoryResponse` struct.
82    /// The `await?` operator awaits the response and returns an error if the request fails.
83    ///
84    /// # Arguments
85    ///
86    /// * `req` - A `BorrowHistoryRequest` struct containing the parameters for the request.
87    ///
88    /// # Returns
89    ///
90    /// A result containing the borrow history response or an error.
91    pub async fn get_borrow_history<'b>(
92        &self,
93        req: BorrowHistoryRequest<'_>,
94    ) -> Result<BorrowHistoryResponse, BybitError> {
95        let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
96        if let Some(c) = req.coin {
97            parameters.insert("coin".into(), c.into());
98        }
99
100        // If the start time is specified, convert it to milliseconds and insert it into the parameters.
101        if let Some(start_time) = req.start_time {
102            parameters
103                .entry("startTime".to_owned())
104                .or_insert_with(|| start_time.into());
105        }
106
107        // If the end time is specified, convert it to milliseconds and insert it into the parameters.
108        if let Some(end_time) = req.end_time {
109            parameters
110                .entry("endTime".to_owned())
111                .or_insert_with(|| end_time.into());
112        }
113
114        // If the limit is specified, insert it into the parameters.
115        if let Some(s) = req.limit {
116            parameters.insert("limit".into(), s.into());
117        }
118
119        let request = build_request(&parameters);
120        let response: BorrowHistoryResponse = self
121            .client
122            .get_signed(
123                API::Account(Account::BorrowHistory),
124                self.recv_window,
125                Some(request),
126            )
127            .await?;
128
129        Ok(response)
130    }
131
132    /// Repays liability for a specific coin.
133    ///
134    /// # Arguments
135    ///
136    /// * `coin` - The coin for which to repay liability. If not specified, all coins are repaid.
137    ///
138    /// # Returns
139    ///
140    /// A result containing a response object or an error.
141    pub async fn repay_liability(
142        &self,
143        coin: Option<&str>,
144    ) -> Result<RepayLiabilityResponse, BybitError> {
145        let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
146        if let Some(c) = coin {
147            parameters.insert("coin".into(), c.into());
148        }
149        let request = build_json_request(&parameters);
150        let response: RepayLiabilityResponse = self
151            .client
152            .post_signed(
153                API::Account(Account::RepayLiability),
154                self.recv_window,
155                Some(request),
156            )
157            .await?;
158        Ok(response)
159    }
160
161    /// Sets the collateral coin for a specific coin with the given switch value.
162    ///
163    /// # Arguments
164    ///
165    /// * `coin` - The coin for which to set the collateral.
166    /// * `switch` - The switch value indicating whether to turn collateral on or off.
167    ///
168    /// # Returns
169    ///
170    /// A result containing the set collateral response or an error.
171    pub async fn set_collateral_coin(
172        &self,
173        coin: &str,
174        switch: bool,
175    ) -> Result<SetCollateralCoinResponse, BybitError> {
176        // Create a new BTreeMap to hold the request parameters.
177        let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
178        // Insert the coin parameter.
179        parameters.insert("coin".into(), coin.into());
180        // Insert the collateral switch parameter based on the switch value.
181        parameters.insert(
182            "collateralSwitch".into(),
183            if switch { "ON".into() } else { "OFF".into() },
184        );
185        // Build the request using the parameters.
186        let request = build_json_request(&parameters);
187        // Send the signed request to the Bybit API and await the response.
188        let response: SetCollateralCoinResponse = self
189            .client
190            .post_signed(
191                API::Account(Account::SetCollateral),
192                self.recv_window,
193                Some(request),
194            )
195            .await?;
196        // Return the response.
197        Ok(response)
198    }
199
200    /// Sets the collateral coin for multiple coins in a single request.
201    ///
202    /// # Arguments
203    ///
204    /// * `requests` - A vector of tuples, where each tuple contains the coin and the switch value.
205    ///
206    /// # Returns
207    ///
208    /// A result containing the batch set collateral response or an error.
209    pub async fn batch_set_collateral(
210        &self,
211        requests: Vec<(&str, bool)>,
212    ) -> Result<BatchSetCollateralCoinResponse, BybitError> {
213        let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
214        let mut requests_array: Vec<Value> = Vec::new();
215        // Iterate over the requests and build the request array
216        for (coin, switch) in requests {
217            let mut build_switch: BTreeMap<String, Value> = BTreeMap::new();
218            build_switch.insert("coin".into(), coin.into());
219            build_switch.insert("collateralSwitch".into(), switch.into());
220            let build_switches = json!(&build_switch);
221            requests_array.push(build_switches);
222        }
223        // Add the request array to the parameters
224        parameters.insert("request".into(), Value::Array(requests_array));
225        // Build the request
226        let request = build_json_request(&parameters);
227        // Send the signed request to the Bybit API and await the response
228        let response: BatchSetCollateralCoinResponse = self
229            .client
230            .post_signed(
231                API::Account(Account::BatchSetCollateral),
232                self.recv_window,
233                Some(request),
234            )
235            .await?;
236        // Return the response
237        Ok(response)
238    }
239
240    /// Retrieves the collateral information for a specific coin.
241    ///
242    /// # Arguments
243    ///
244    /// * `coin` - The optional coin for which to retrieve the collateral information. If not specified,
245
246    /// information for all coins is returned.
247    ///
248    /// # Returns
249    ///
250    /// A result containing the collateral information response or an error.
251    pub async fn get_collateral_info(
252        &self,
253        coin: Option<&str>,
254    ) -> Result<CollateralInfoResponse, BybitError> {
255        // Create a new BTreeMap to hold the request parameters.
256        let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
257
258        // If a coin is specified, insert it into the parameters.
259        if let Some(v) = coin {
260            parameters.insert("currency".into(), v.into());
261        }
262
263        // Build the request using the parameters.
264        let req = build_request(&parameters);
265
266        // Send the signed request to the Bybit API and await the response.
267        let response: CollateralInfoResponse = self
268            .client
269            .get_signed(
270                API::Account(Account::CollateralInfo),
271                self.recv_window,
272                Some(req),
273            )
274            .await?;
275
276        // Return the response.
277        Ok(response)
278    }
279
280    /// Retrieves the fee rate for a given market category and symbol.
281    ///
282    /// # Arguments
283    ///
284    /// * `category` - The market category to fetch the fee rate from.
285    /// * `symbol` - The trading symbol to fetch the fee rate for. If not specified, the fee rate for all symbols in the category is returned.
286    ///
287    /// # Returns
288    ///
289    /// A result containing the fee rate response or an error.
290    pub async fn get_fee_rate(
291        &self,
292        category: Category,
293        symbol: Option<String>,
294    ) -> Result<FeeRateResponse, BybitError> {
295        let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
296
297        // Insert the category parameter.
298        parameters.insert("category".into(), category.as_str().into());
299
300        // If a symbol is specified, insert it into the parameters.
301        if let Some(s) = symbol {
302            parameters.insert("symbol".into(), s.into());
303        }
304
305        // Build the request using the parameters.
306        let req = build_request(&parameters);
307
308        // Send the signed request to the Bybit API and await the response.
309        let response: FeeRateResponse = self
310            .client
311            .post_signed(API::Account(Account::FeeRate), self.recv_window, Some(req))
312            .await?;
313
314        // Return the response.
315        Ok(response)
316    }
317
318    /// Retrieves the account information for the current account.
319    ///
320    /// This function sends a signed GET request to the Bybit API to retrieve the account information.
321    /// The response is deserialized into the `AccountInfoResponse` struct.
322    /// The `await?` operator awaits the response and returns an error if the request fails.
323    ///
324    /// # Returns
325    ///
326    /// A result containing the account information response or an error.
327    pub async fn get_account_info(&self) -> Result<AccountInfoResponse, BybitError> {
328        // Send the signed GET request to the Bybit API to retrieve the account information.
329        // The request does not require any additional parameters.
330        // The response is deserialized into the `AccountInfoResponse` struct.
331        // The `await?` operator awaits the response and returns an error if the request fails.
332
333        // Send the request and await the response.
334        let response: AccountInfoResponse = self
335            .client
336            .get_signed(API::Account(Account::Information), self.recv_window, None)
337            .await?;
338
339        // Return the response.
340        Ok(response)
341    }
342
343    /// Retrieves the transaction log for the current account.
344    ///
345    /// This function sends a signed GET request to the Bybit API to retrieve the transaction log.
346    /// The request parameters are serialized into a JSON object and sent in the request body.
347    /// The response is deserialized into the `TransactionLogResponse` struct.
348    /// The `await?` operator awaits the response and returns an error if the request fails.
349    ///
350    /// # Arguments
351    ///
352    /// * `req` - An instance of `TransactionLogRequest` containing the request parameters.
353    ///
354    /// # Returns
355    ///
356    /// A result containing the transaction log response or an error.
357    pub async fn get_transaction_log<'b>(
358        &self,
359        req: TransactionLogRequest<'_>,
360    ) -> Result<TransactionLogResponse, BybitError> {
361        // Create a mutable map to store the request parameters.
362        let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
363
364        // Add the account type to the request parameters if it is specified.
365        if let Some(v) = req.account_type {
366            parameters.insert("accountType".into(), v.into());
367        }
368
369        // Add the category to the request parameters if it is specified.
370        if let Some(v) = req.category {
371            parameters.insert("category".into(), v.as_str().into());
372        }
373
374        // Add the currency to the request parameters if it is specified.
375        if let Some(s) = req.currency {
376            parameters.insert("currency".into(), s.into());
377        }
378
379        // Add the base coin to the request parameters if it is specified.
380        if let Some(c) = req.base_coin {
381            parameters.insert("baseCoin".into(), c.into());
382        }
383
384        // Add the log type to the request parameters if it is specified.
385        if let Some(t) = req.log_type {
386            parameters.insert("type".into(), t.into());
387        }
388
389        // Add the start time to the request parameters if it is specified.
390        if let Some(start_time) = req.start_time {
391            parameters
392                .entry("startTime".to_owned())
393                .or_insert_with(|| start_time.into());
394        }
395
396        // Add the end time to the request parameters if it is specified.
397        if let Some(end_time) = req.end_time {
398            parameters
399                .entry("endTime".to_owned())
400                .or_insert_with(|| end_time.into());
401        }
402
403        // Add the limit to the request parameters if it is specified.
404        if let Some(s) = req.limit {
405            parameters.insert("limit".into(), s.into());
406        }
407
408        // Build the request from the parameters.
409        let request = build_request(&parameters);
410
411        // Send the signed GET request to the Bybit API to retrieve the transaction log.
412        let response: TransactionLogResponse = self
413            .client
414            .get_signed(
415                API::Account(Account::TransactionLog),
416                self.recv_window,
417                Some(request),
418            )
419            .await?;
420
421        // Return the response.
422        Ok(response)
423    }
424
425    /// Retrieves the Server-Market-Portfolio (SMP) group ID for the current user.
426    ///
427    /// # Returns
428    ///
429    /// A result containing the SMP response or an error.
430    pub async fn get_smp_id(&self) -> Result<SmpResponse, BybitError> {
431        // Send a signed GET request to the Bybit API to retrieve the SMP group ID.
432        // The request does not require any additional parameters.
433        let response: SmpResponse = self
434            .client
435            .get_signed(API::Account(Account::SMPGroupID), self.recv_window, None)
436            .await?;
437
438        // Return the response.
439        Ok(response)
440    }
441
442    /// Sets the margin mode for the current account.
443    ///
444    /// # Arguments
445    ///
446    /// * `margin_mode` - The desired margin mode to set. Can be "CROSS" or "FIXED".
447    ///
448    /// # Returns
449    ///
450    /// A result containing the set margin mode response or an error.
451    pub async fn set_margin_mode(
452        &self,
453        margin_mode: &str,
454    ) -> Result<SetMarginModeResponse, BybitError> {
455        let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
456        parameters.insert("setMarginMode".into(), margin_mode.into());
457        let request = build_json_request(&parameters);
458        let response: SetMarginModeResponse = self
459            .client
460            .post_signed(
461                API::Account(Account::SetMarginMode),
462                self.recv_window,
463                Some(request),
464            )
465            .await?;
466        Ok(response)
467    }
468
469    /// Sets the spot hedging mode for the current account.
470    ///
471    /// # Arguments
472    ///
473    /// * `spot_hedging` - The desired spot hedging mode. `true` sets the mode to "ON",
474
475    ///   `false` sets the mode to "OFF".
476    ///
477    /// # Returns
478    ///
479    /// A result containing the set spot hedging mode response or an error.
480    ///
481    pub async fn _set_spot_hedging(
482        &self,
483        spot_hedging: bool,
484    ) -> Result<SpotHedgingResponse, BybitError> {
485        let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
486        parameters.insert(
487            "setHedgingMode".into(),
488            if spot_hedging {
489                "ON".into()
490            } else {
491                "OFF".into()
492            },
493        );
494        let request = build_json_request(&parameters);
495        let response: SpotHedgingResponse = self
496            .client
497            .post_signed(
498                API::Account(Account::SetSpotHedging),
499                self.recv_window,
500                Some(request),
501            )
502            .await?;
503        Ok(response)
504    }
505}