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