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(¶meters);
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(¶meters);
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(¶meters);
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(¶meters);
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(¶meters);
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(¶meters);
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(¶meters);
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(¶meters);
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(¶meters);
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(¶meters);
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}