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(¶ms).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(¶ms).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(¶ms).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(¶ms).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(¶ms).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(¶ms).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(¶ms).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(¶ms).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(¶ms) {
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(¶ms) {
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(¶ms) {
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(¶ms) {
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}