bybit_rust_api/rest/account/
account_client.rs1use crate::rest::account::dto::account_info::AccountInfoResult;
2use crate::rest::account::dto::account_wallet::{GetWalletBalanceParams, WalletBalanceResult};
3use crate::rest::account::dto::collateral::{BorrowHistoryResult, CollateralInfoResult};
4use crate::rest::account::dto::contract_transaction_log::{
5 ContractTransactionLogResult, GetContractTransactionLogParams,
6};
7use crate::rest::account::dto::fee_rate::FeeRateResult;
8use crate::rest::account::dto::mmp::{MmpStateResult, ModifyMmpParams};
9use crate::rest::account::dto::transaction_log::{GetTransactionLogParams, TransactionLogResult};
10use crate::rest::client::{RestClient, SecType, ServerResponse};
11use crate::rest::BybitResult as Result;
12use serde_json::{json, to_value};
13
14#[derive(Clone)]
15pub struct AccountClient {
16 client: RestClient,
17}
18
19impl AccountClient {
20 pub fn new(client: RestClient) -> Self {
21 AccountClient { client }
22 }
23
24 pub async fn get_wallet_balance(
29 &self,
30 params: GetWalletBalanceParams,
31 ) -> Result<ServerResponse<WalletBalanceResult>> {
32 let endpoint = "v5/account/wallet-balance";
33 let query = to_value(¶ms)?;
34 let response = self.client.get(endpoint, query, SecType::Signed).await?;
35 Ok(response)
36 }
37
38 pub async fn get_fee_rate(
43 &self,
44 category: &str,
45 symbol: Option<&str>,
46 base_coin: Option<&str>,
47 ) -> Result<ServerResponse<FeeRateResult>> {
48 let endpoint = "v5/account/fee-rate";
49 let mut params = json!({
50 "category": category,
51 });
52
53 if let Some(symbol) = symbol {
54 params["symbol"] = json!(symbol);
55 }
56 if let Some(base_coin) = base_coin {
57 params["baseCoin"] = json!(base_coin);
58 }
59
60 let response = self.client.get(endpoint, params, SecType::Signed).await?;
61 Ok(response)
62 }
63
64 pub async fn get_account_info(&self) -> Result<ServerResponse<AccountInfoResult>> {
69 let endpoint = "v5/account/info";
70 let response = self
71 .client
72 .get(endpoint, json!({}), SecType::Signed)
73 .await?;
74 Ok(response)
75 }
76
77 pub async fn get_transaction_log(
82 &self,
83 params: GetTransactionLogParams,
84 ) -> Result<ServerResponse<TransactionLogResult>> {
85 let endpoint = "v5/account/transaction-log";
86 let query = to_value(¶ms)?;
87 let response = self.client.get(endpoint, query, SecType::Signed).await?;
88 Ok(response)
89 }
90
91 pub async fn set_margin_mode(
96 &self,
97 margin_mode: &str,
98 ) -> Result<ServerResponse<serde_json::Value>> {
99 let endpoint = "v5/account/set-margin-mode";
100 let body = json!({
101 "setMarginMode": margin_mode,
102 });
103
104 let response = self.client.post(endpoint, body, SecType::Signed).await?;
105 Ok(response)
106 }
107
108 pub async fn set_mmp(
113 &self,
114 params: ModifyMmpParams,
115 ) -> Result<ServerResponse<serde_json::Value>> {
116 let endpoint = "v5/account/mmp-modify";
117 let body = to_value(¶ms)?;
118 let response = self.client.post(endpoint, body, SecType::Signed).await?;
119 Ok(response)
120 }
121
122 pub async fn reset_mmp(&self, base_coin: &str) -> Result<ServerResponse<serde_json::Value>> {
127 let endpoint = "v5/account/mmp-reset";
128 let body = json!({
129 "baseCoin": base_coin,
130 });
131
132 let response = self.client.post(endpoint, body, SecType::Signed).await?;
133 Ok(response)
134 }
135
136 pub async fn get_mmp_state(&self, base_coin: &str) -> Result<ServerResponse<MmpStateResult>> {
141 let endpoint = "v5/account/mmp-state";
142 let params = json!({
143 "baseCoin": base_coin,
144 });
145
146 let response = self.client.get(endpoint, params, SecType::Signed).await?;
147 Ok(response)
148 }
149
150 pub async fn get_smp_group_list(&self) -> Result<ServerResponse<serde_json::Value>> {
155 let endpoint = "v5/account/smp-group";
156 let response = self
157 .client
158 .get(endpoint, json!({}), SecType::Signed)
159 .await?;
160 Ok(response)
161 }
162
163 pub async fn get_coin_greeks(
168 &self,
169 base_coin: Option<&str>,
170 ) -> Result<ServerResponse<serde_json::Value>> {
171 let endpoint = "v5/asset/coin-greeks";
172 let mut params = json!({});
173
174 if let Some(base_coin) = base_coin {
175 params["baseCoin"] = json!(base_coin);
176 }
177
178 let response = self.client.get(endpoint, params, SecType::Signed).await?;
179 Ok(response)
180 }
181
182 pub async fn get_collateral_info(
187 &self,
188 currency: Option<&str>,
189 ) -> Result<ServerResponse<CollateralInfoResult>> {
190 let endpoint = "v5/account/collateral-info";
191 let mut params = json!({});
192
193 if let Some(currency) = currency {
194 params["currency"] = json!(currency);
195 }
196
197 let response = self.client.get(endpoint, params, SecType::Signed).await?;
198 Ok(response)
199 }
200
201 pub async fn get_borrow_history(
206 &self,
207 currency: Option<&str>,
208 start_time: Option<i64>,
209 end_time: Option<i64>,
210 limit: Option<i32>,
211 cursor: Option<&str>,
212 ) -> Result<ServerResponse<BorrowHistoryResult>> {
213 let endpoint = "v5/account/borrow-history";
214 let mut params = json!({});
215
216 if let Some(currency) = currency {
217 params["currency"] = json!(currency);
218 }
219 if let Some(start_time) = start_time {
220 params["startTime"] = json!(start_time);
221 }
222 if let Some(end_time) = end_time {
223 params["endTime"] = json!(end_time);
224 }
225 if let Some(limit) = limit {
226 params["limit"] = json!(limit);
227 }
228 if let Some(cursor) = cursor {
229 params["cursor"] = json!(cursor);
230 }
231
232 let response = self.client.get(endpoint, params, SecType::Signed).await?;
233 Ok(response)
234 }
235
236 pub async fn set_disconnect_cancel_all(
241 &self,
242 time_window: i32,
243 ) -> Result<ServerResponse<serde_json::Value>> {
244 let endpoint = "v5/order/disconnected-cancel-all";
245 let body = json!({
246 "timeWindow": time_window,
247 });
248
249 let response = self.client.post(endpoint, body, SecType::Signed).await?;
250 Ok(response)
251 }
252
253 pub async fn upgrade_to_unified_account(&self) -> Result<ServerResponse<serde_json::Value>> {
258 let endpoint = "v5/account/upgrade-to-uta";
259 let body = json!({});
260
261 let response = self.client.post(endpoint, body, SecType::Signed).await?;
262 Ok(response)
263 }
264
265 pub async fn get_contract_transaction_log(
270 &self,
271 params: GetContractTransactionLogParams,
272 ) -> Result<ServerResponse<ContractTransactionLogResult>> {
273 let endpoint = "v5/account/contract-transaction-log";
274 let query = to_value(¶ms)?;
275 let response = self.client.get(endpoint, query, SecType::Signed).await?;
276 Ok(response)
277 }
278
279 pub async fn query_dcp_info(&self) -> Result<ServerResponse<serde_json::Value>> {
284 let endpoint = "v5/account/query-dcp-info";
285 let response = self
286 .client
287 .get(endpoint, json!({}), SecType::Signed)
288 .await?;
289 Ok(response)
290 }
291}
292
293#[cfg(test)]
294mod tests {
295 use super::*;
296 use crate::rest::enums::account_type::AccountType;
297 use crate::rest::enums::category::Category;
298 use crate::rest::ApiKeyPair;
299
300 fn create_test_client() -> AccountClient {
301 let api_key_pair = ApiKeyPair::new(
302 "test".to_string(),
303 "test_key".to_string(),
304 "test_secret".to_string(),
305 );
306 let rest_client =
307 RestClient::new(api_key_pair, "https://api-testnet.bybit.com".to_string());
308 AccountClient::new(rest_client)
309 }
310
311 #[test]
312 fn test_account_client_creation() {
313 let _client = create_test_client();
314 }
315
316 #[tokio::test]
317 async fn test_get_wallet_balance_params() {
318 let _client = create_test_client();
319 let params = GetWalletBalanceParams {
320 account_type: AccountType::UNIFIED,
321 coin: Some("USDT".to_string()),
322 };
323
324 assert_eq!(params.account_type, AccountType::UNIFIED);
325 assert_eq!(params.coin, Some("USDT".to_string()));
326 }
327
328 #[tokio::test]
329 async fn test_get_fee_rate_params() {
330 let category = "spot";
331 let symbol = Some("BTCUSDT");
332 let base_coin: Option<&str> = None;
333
334 assert_eq!(category, "spot");
335 assert_eq!(symbol, Some("BTCUSDT"));
336 assert_eq!(base_coin, None);
337 }
338
339 #[tokio::test]
340 async fn test_transaction_log_params() {
341 let params = GetTransactionLogParams {
342 account_type: Some(AccountType::UNIFIED),
343 category: Some(Category::Spot),
344 currency: Some("USDT".to_string()),
345 log_type: Some("TRADE".to_string()),
346 limit: Some(50),
347 ..Default::default()
348 };
349
350 assert_eq!(params.account_type, Some(AccountType::UNIFIED));
351 assert_eq!(params.category, Some(Category::Spot));
352 assert_eq!(params.currency, Some("USDT".to_string()));
353 assert_eq!(params.log_type, Some("TRADE".to_string()));
354 assert_eq!(params.limit, Some(50));
355 }
356
357 #[tokio::test]
358 async fn test_set_margin_mode_params() {
359 let set_margin_mode = "PORTFOLIO_MARGIN";
360 assert_eq!(set_margin_mode, "PORTFOLIO_MARGIN");
361 }
362
363 #[tokio::test]
364 async fn test_set_mmp_params() {
365 let params = ModifyMmpParams {
366 base_coin: "BTC".to_string(),
367 window: 5000,
368 frozen_period: 100000,
369 qty_limit: "100".to_string(),
370 delta_limit: "10".to_string(),
371 };
372
373 assert_eq!(params.base_coin, "BTC");
374 assert_eq!(params.window, 5000);
375 assert_eq!(params.frozen_period, 100000);
376 assert_eq!(params.qty_limit, "100");
377 assert_eq!(params.delta_limit, "10");
378 }
379
380 #[tokio::test]
381 async fn test_borrow_history_params() {
382 let currency = Some("USDT");
383 let start_time = Some(1234567890i64);
384 let end_time = Some(1234567899i64);
385 let limit = Some(100);
386 let cursor = Some("next_page");
387
388 assert_eq!(currency, Some("USDT"));
389 assert_eq!(start_time, Some(1234567890));
390 assert_eq!(end_time, Some(1234567899));
391 assert_eq!(limit, Some(100));
392 assert_eq!(cursor, Some("next_page"));
393 }
394
395 #[tokio::test]
396 async fn test_set_disconnect_cancel_all_params() {
397 let time_window = 10;
398 assert_eq!(time_window, 10);
399 }
400
401 #[tokio::test]
402 async fn test_contract_transaction_log_params() {
403 let params = GetContractTransactionLogParams {
404 category: Some(Category::Linear),
405 base_coin: Some("BTC".to_string()),
406 log_type: Some("SETTLEMENT".to_string()),
407 limit: Some(50),
408 ..Default::default()
409 };
410
411 assert_eq!(params.category, Some(Category::Linear));
412 assert_eq!(params.base_coin, Some("BTC".to_string()));
413 assert_eq!(params.log_type, Some("SETTLEMENT".to_string()));
414 assert_eq!(params.limit, Some(50));
415 }
416}