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