Skip to main content

bybit_client/api/
account.rs

1//! Account API endpoints for wallet and account management.
2
3use crate::error::BybitError;
4use crate::http::HttpClient;
5use crate::types::account::*;
6
7/// Account service for wallet and account management endpoints.
8#[derive(Debug, Clone)]
9pub struct AccountService {
10    http: HttpClient,
11}
12
13impl AccountService {
14    /// Create a new account service.
15    pub fn new(http: HttpClient) -> Self {
16        Self { http }
17    }
18
19    /// Get wallet balance.
20    ///
21    /// # Example
22    ///
23    /// ```no_run
24    /// # use bybit_client::{BybitClient, AccountType};
25    /// # use bybit_client::types::account::GetWalletBalanceParams;
26    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
27    /// let client = BybitClient::new("api_key", "api_secret")?;
28    ///
29    /// let params = GetWalletBalanceParams::new(AccountType::Unified);
30    /// let result = client.account().get_wallet_balance(&params).await?;
31    /// for wallet in &result.list {
32    ///     println!("Total equity: {}", wallet.total_equity);
33    ///     for coin in &wallet.coin {
34    ///         println!("  {}: {}", coin.coin, coin.wallet_balance);
35    ///     }
36    /// }
37    /// # Ok(())
38    /// # }
39    /// ```
40    pub async fn get_wallet_balance(
41        &self,
42        params: &GetWalletBalanceParams,
43    ) -> Result<WalletBalanceResult, BybitError> {
44        self.http
45            .get_signed("/v5/account/wallet-balance", Some(params))
46            .await
47    }
48
49    /// Get account information.
50    ///
51    /// # Example
52    ///
53    /// ```no_run
54    /// # use bybit_client::BybitClient;
55    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
56    /// let client = BybitClient::new("api_key", "api_secret")?;
57    ///
58    /// let info = client.account().get_account_info().await?;
59    /// println!("Margin mode: {}", info.margin_mode);
60    /// # Ok(())
61    /// # }
62    /// ```
63    pub async fn get_account_info(&self) -> Result<AccountInfo, BybitError> {
64        self.http
65            .get_signed("/v5/account/info", None::<&()>)
66            .await
67    }
68
69    /// Get fee rates for trading.
70    ///
71    /// # Example
72    ///
73    /// ```no_run
74    /// # use bybit_client::{BybitClient, Category};
75    /// # use bybit_client::types::account::GetFeeRatesParams;
76    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
77    /// let client = BybitClient::new("api_key", "api_secret")?;
78    ///
79    /// let params = GetFeeRatesParams::new(Category::Linear)
80    ///     .symbol("BTCUSDT");
81    /// let result = client.account().get_fee_rates(&params).await?;
82    /// for fee in &result.list {
83    ///     println!("{}: maker={}, taker={}",
84    ///         fee.symbol, fee.maker_fee_rate, fee.taker_fee_rate);
85    /// }
86    /// # Ok(())
87    /// # }
88    /// ```
89    pub async fn get_fee_rates(
90        &self,
91        params: &GetFeeRatesParams,
92    ) -> Result<FeeRateResult, BybitError> {
93        self.http
94            .get_signed("/v5/account/fee-rate", Some(params))
95            .await
96    }
97
98    /// Get borrow history.
99    ///
100    /// # Example
101    ///
102    /// ```no_run
103    /// # use bybit_client::BybitClient;
104    /// # use bybit_client::types::account::GetBorrowHistoryParams;
105    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
106    /// let client = BybitClient::new("api_key", "api_secret")?;
107    ///
108    /// let params = GetBorrowHistoryParams::new()
109    ///     .currency("USDT")
110    ///     .limit(20);
111    /// let result = client.account().get_borrow_history(&params).await?;
112    /// # Ok(())
113    /// # }
114    /// ```
115    pub async fn get_borrow_history(
116        &self,
117        params: &GetBorrowHistoryParams,
118    ) -> Result<BorrowHistoryResult, BybitError> {
119        self.http
120            .get_signed("/v5/account/borrow-history", Some(params))
121            .await
122    }
123
124    /// Get collateral information.
125    ///
126    /// # Example
127    ///
128    /// ```no_run
129    /// # use bybit_client::BybitClient;
130    /// # use bybit_client::types::account::GetCollateralInfoParams;
131    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
132    /// let client = BybitClient::new("api_key", "api_secret")?;
133    ///
134    /// let params = GetCollateralInfoParams::new();
135    /// let result = client.account().get_collateral_info(&params).await?;
136    /// for info in &result.list {
137    ///     println!("{}: borrowable={}", info.currency, info.borrowable);
138    /// }
139    /// # Ok(())
140    /// # }
141    /// ```
142    pub async fn get_collateral_info(
143        &self,
144        params: &GetCollateralInfoParams,
145    ) -> Result<CollateralInfoResult, BybitError> {
146        self.http
147            .get_signed("/v5/account/collateral-info", Some(params))
148            .await
149    }
150
151    /// Set collateral coin switch.
152    ///
153    /// # Example
154    ///
155    /// ```no_run
156    /// # use bybit_client::BybitClient;
157    /// # use bybit_client::types::account::SetCollateralCoinParams;
158    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
159    /// let client = BybitClient::new("api_key", "api_secret")?;
160    ///
161    /// // Enable BTC as collateral
162    /// let params = SetCollateralCoinParams::enable("BTC");
163    /// client.account().set_collateral_coin(&params).await?;
164    /// # Ok(())
165    /// # }
166    /// ```
167    pub async fn set_collateral_coin(
168        &self,
169        params: &SetCollateralCoinParams,
170    ) -> Result<(), BybitError> {
171        let _: serde_json::Value = self
172            .http
173            .post_signed("/v5/account/set-collateral-switch", Some(params))
174            .await?;
175        Ok(())
176    }
177
178    /// Get coin greeks (for options).
179    ///
180    /// # Example
181    ///
182    /// ```no_run
183    /// # use bybit_client::BybitClient;
184    /// # use bybit_client::types::account::GetCoinGreeksParams;
185    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
186    /// let client = BybitClient::new("api_key", "api_secret")?;
187    ///
188    /// let params = GetCoinGreeksParams::new().base_coin("BTC");
189    /// let result = client.account().get_coin_greeks(&params).await?;
190    /// for greeks in &result.list {
191    ///     println!("{}: delta={}", greeks.base_coin, greeks.total_delta);
192    /// }
193    /// # Ok(())
194    /// # }
195    /// ```
196    pub async fn get_coin_greeks(
197        &self,
198        params: &GetCoinGreeksParams,
199    ) -> Result<CoinGreeksResult, BybitError> {
200        self.http
201            .get_signed("/v5/asset/coin-greeks", Some(params))
202            .await
203    }
204
205    /// Get transaction log.
206    ///
207    /// # Example
208    ///
209    /// ```no_run
210    /// # use bybit_client::BybitClient;
211    /// # use bybit_client::types::account::GetTransactionLogParams;
212    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
213    /// let client = BybitClient::new("api_key", "api_secret")?;
214    ///
215    /// let params = GetTransactionLogParams::new()
216    ///     .currency("USDT")
217    ///     .limit(50);
218    /// let result = client.account().get_transaction_log(&params).await?;
219    /// for log in &result.list {
220    ///     println!("{}: {} - {}", log.transaction_time, log.transaction_type, log.change);
221    /// }
222    /// # Ok(())
223    /// # }
224    /// ```
225    pub async fn get_transaction_log(
226        &self,
227        params: &GetTransactionLogParams,
228    ) -> Result<TransactionLogResult, BybitError> {
229        self.http
230            .get_signed("/v5/account/transaction-log", Some(params))
231            .await
232    }
233
234    /// Set margin mode (regular or portfolio margin).
235    ///
236    /// # Example
237    ///
238    /// ```no_run
239    /// # use bybit_client::BybitClient;
240    /// # use bybit_client::types::account::SetMarginModeParams;
241    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
242    /// let client = BybitClient::new("api_key", "api_secret")?;
243    ///
244    /// let params = SetMarginModeParams::portfolio_margin();
245    /// client.account().set_margin_mode(&params).await?;
246    /// # Ok(())
247    /// # }
248    /// ```
249    pub async fn set_margin_mode(
250        &self,
251        params: &SetMarginModeParams,
252    ) -> Result<MarginModeResult, BybitError> {
253        self.http
254            .post_signed("/v5/account/set-margin-mode", Some(params))
255            .await
256    }
257}
258
259#[cfg(test)]
260mod tests {
261    use super::*;
262    use crate::types::{AccountType, Category};
263
264    #[test]
265    fn test_get_wallet_balance_params_serialization() {
266        let params = GetWalletBalanceParams::new(AccountType::Unified).coin("BTC");
267
268        let query = match serde_urlencoded::to_string(&params) {
269            Ok(query) => query,
270            Err(err) => panic!("Failed to serialize wallet balance params: {}", err),
271        };
272        assert!(query.contains("accountType=UNIFIED"));
273        assert!(query.contains("coin=BTC"));
274    }
275
276    #[test]
277    fn test_get_fee_rates_params_serialization() {
278        let params = GetFeeRatesParams::new(Category::Linear).symbol("BTCUSDT");
279
280        let query = match serde_urlencoded::to_string(&params) {
281            Ok(query) => query,
282            Err(err) => panic!("Failed to serialize fee rates params: {}", err),
283        };
284        assert!(query.contains("category=linear"));
285        assert!(query.contains("symbol=BTCUSDT"));
286    }
287
288    #[test]
289    fn test_set_collateral_coin_params_serialization() {
290        let params = SetCollateralCoinParams::enable("BTC");
291        let json = match serde_json::to_string(&params) {
292            Ok(json) => json,
293            Err(err) => panic!("Failed to serialize collateral params: {}", err),
294        };
295        assert!(json.contains("\"coin\":\"BTC\""));
296        assert!(json.contains("\"collateralSwitch\":\"ON\""));
297    }
298
299    #[test]
300    fn test_set_margin_mode_params_serialization() {
301        let params = SetMarginModeParams::portfolio_margin();
302        let json = match serde_json::to_string(&params) {
303            Ok(json) => json,
304            Err(err) => panic!("Failed to serialize margin mode params: {}", err),
305        };
306        assert!(json.contains("\"setMarginMode\":\"PORTFOLIO_MARGIN\""));
307    }
308}