rust_okx/api/account/api.rs
1use crate::client::OkxClient;
2use crate::error::Error;
3use crate::model::{InstType, ValidateRequest};
4use crate::transport::Transport;
5
6use super::endpoints::*;
7use super::internal::*;
8use super::requests::*;
9use super::responses::*;
10
11/// Accessor for the authenticated account endpoints.
12///
13/// Obtain one via [`OkxClient::account`](crate::OkxClient::account). All methods
14/// require credentials; calling them without credentials returns
15/// [`Error::Configuration`].
16pub struct Account<'a, T> {
17 client: &'a OkxClient<T>,
18}
19
20impl<'a, T: Transport> Account<'a, T> {
21 pub(crate) fn new(client: &'a OkxClient<T>) -> Self {
22 Self { client }
23 }
24
25 /// Retrieve the trading-account balance.
26 ///
27 /// `GET /api/v5/account/balance`. Authenticated. Pass `ccy` to filter to one
28 /// or more comma-separated currencies (e.g. `Some("BTC,USDT")`). The result
29 /// is a single [`AccountBalance`].
30 ///
31 /// # Errors
32 ///
33 /// Returns [`Error::Configuration`] if no credentials are set,
34 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
35 pub async fn get_balance(&self, ccy: Option<&str>) -> Result<Vec<AccountBalance>, Error> {
36 let query = BalanceQuery { ccy };
37 self.client.get(BALANCE, &query, true).await
38 }
39
40 /// Retrieve open positions.
41 ///
42 /// `GET /api/v5/account/positions`. Authenticated. Both filters are
43 /// optional; omit them to return all positions.
44 ///
45 /// # Errors
46 ///
47 /// Returns [`Error::Configuration`] if no credentials are set,
48 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
49 pub async fn get_positions(
50 &self,
51 inst_type: Option<InstType>,
52 inst_id: Option<&str>,
53 ) -> Result<Vec<Position>, Error> {
54 let query = PositionsQuery {
55 inst_type: inst_type.as_ref(),
56 inst_id,
57 };
58 self.client.get(POSITIONS, &query, true).await
59 }
60
61 /// Retrieve account position risk.
62 ///
63 /// `GET /api/v5/account/account-position-risk`. Authenticated.
64 ///
65 /// # Errors
66 ///
67 /// Returns [`Error::Configuration`] if no credentials are set,
68 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
69 pub async fn get_position_risk(
70 &self,
71 inst_type: Option<InstType>,
72 ) -> Result<Vec<PositionRisk>, Error> {
73 let query = PositionRiskQuery {
74 inst_type: inst_type.as_ref(),
75 };
76 self.client.get(POSITION_RISK, &query, true).await
77 }
78
79 /// Retrieve account configuration.
80 ///
81 /// `GET /api/v5/account/config`. Authenticated.
82 ///
83 /// # Errors
84 ///
85 /// Returns [`Error::Configuration`] if no credentials are set,
86 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
87 pub async fn get_account_config(&self) -> Result<Vec<AccountConfig>, Error> {
88 self.client.get(ACCOUNT_CONFIG, &NoQuery, true).await
89 }
90
91 /// Retrieve recent account bills.
92 ///
93 /// `GET /api/v5/account/bills`. Authenticated.
94 ///
95 /// # Errors
96 ///
97 /// Returns [`Error::InvalidRequest`] on validation failure,
98 /// [`Error::Configuration`] if no credentials are set,
99 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
100 pub async fn get_account_bills(
101 &self,
102 request: &BillsRequest,
103 ) -> Result<Vec<AccountBill>, Error> {
104 request.validate()?;
105 self.client.get(BILLS, request, true).await
106 }
107
108 /// Retrieve archived account bills.
109 ///
110 /// `GET /api/v5/account/bills-archive`. Authenticated.
111 ///
112 /// # Errors
113 ///
114 /// Returns [`Error::InvalidRequest`] on validation failure,
115 /// [`Error::Configuration`] if no credentials are set,
116 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
117 pub async fn get_account_bills_archive(
118 &self,
119 request: &BillsArchiveRequest,
120 ) -> Result<Vec<AccountBill>, Error> {
121 request.validate()?;
122 self.client.get(BILLS_ARCHIVE, request, true).await
123 }
124
125 /// Set the account position mode.
126 ///
127 /// `POST /api/v5/account/set-position-mode`. Authenticated.
128 ///
129 /// # Errors
130 ///
131 /// Returns [`Error::Configuration`] if no credentials are set,
132 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
133 pub async fn set_position_mode(
134 &self,
135 pos_mode: &str,
136 ) -> Result<Vec<SetPositionModeResult>, Error> {
137 let body = SetPositionModeBody { pos_mode };
138 self.client.post(SET_POSITION_MODE, &body, true).await
139 }
140
141 /// Set leverage for an instrument or currency.
142 ///
143 /// `POST /api/v5/account/set-leverage`. Authenticated.
144 ///
145 /// # Errors
146 ///
147 /// Returns [`Error::InvalidRequest`] on validation failure,
148 /// [`Error::Configuration`] if no credentials are set,
149 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
150 pub async fn set_leverage(
151 &self,
152 request: &SetLeverageRequest,
153 ) -> Result<Vec<LeverageInfo>, Error> {
154 request.validate()?;
155 self.client.post(SET_LEVERAGE, request, true).await
156 }
157
158 /// Retrieve leverage settings.
159 ///
160 /// `GET /api/v5/account/leverage-info`. Authenticated.
161 ///
162 /// # Errors
163 ///
164 /// Returns [`Error::InvalidRequest`] on validation failure,
165 /// [`Error::Configuration`] if no credentials are set,
166 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
167 pub async fn get_leverage(
168 &self,
169 request: &LeverageRequest,
170 ) -> Result<Vec<LeverageInfo>, Error> {
171 request.validate()?;
172 self.client.get(GET_LEVERAGE, request, true).await
173 }
174
175 /// Retrieve maximum tradable size for an instrument.
176 ///
177 /// `GET /api/v5/account/max-size`. Authenticated.
178 ///
179 /// # Errors
180 ///
181 /// Returns [`Error::InvalidRequest`] on validation failure,
182 /// [`Error::Configuration`] if no credentials are set,
183 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
184 pub async fn get_max_order_size(
185 &self,
186 request: &MaxOrderSizeRequest,
187 ) -> Result<Vec<MaxOrderSize>, Error> {
188 request.validate()?;
189 self.client.get(MAX_ORDER_SIZE, request, true).await
190 }
191
192 /// Retrieve maximum available size for an instrument.
193 ///
194 /// `GET /api/v5/account/max-avail-size`. Authenticated.
195 ///
196 /// # Errors
197 ///
198 /// Returns [`Error::InvalidRequest`] on validation failure,
199 /// [`Error::Configuration`] if no credentials are set,
200 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
201 pub async fn get_max_avail_size(
202 &self,
203 request: &MaxAvailableSizeRequest,
204 ) -> Result<Vec<MaxAvailableSize>, Error> {
205 request.validate()?;
206 self.client.get(MAX_AVAILABLE_SIZE, request, true).await
207 }
208
209 /// Increase or decrease margin for a position.
210 ///
211 /// `POST /api/v5/account/position/margin-balance`. Authenticated.
212 ///
213 /// # Errors
214 ///
215 /// Returns [`Error::InvalidRequest`] on validation failure,
216 /// [`Error::Configuration`] if no credentials are set,
217 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
218 pub async fn adjust_margin(
219 &self,
220 request: &AdjustMarginRequest,
221 ) -> Result<Vec<AdjustMarginResult>, Error> {
222 request.validate()?;
223 self.client.post(ADJUST_MARGIN, request, true).await
224 }
225
226 /// Retrieve trade fee rates.
227 ///
228 /// `GET /api/v5/account/trade-fee`. Authenticated.
229 ///
230 /// # Errors
231 ///
232 /// Returns [`Error::InvalidRequest`] on validation failure,
233 /// [`Error::Configuration`] if no credentials are set,
234 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
235 pub async fn get_fee_rates(&self, request: &FeeRatesRequest) -> Result<Vec<FeeRate>, Error> {
236 request.validate()?;
237 self.client.get(FEE_RATES, request, true).await
238 }
239
240 /// Retrieve account-available instruments.
241 ///
242 /// `GET /api/v5/account/instruments`. Authenticated.
243 ///
244 /// # Errors
245 ///
246 /// Returns [`Error::InvalidRequest`] on validation failure,
247 /// [`Error::Configuration`] if no credentials are set,
248 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
249 pub async fn get_account_instruments(
250 &self,
251 request: &AccountInstrumentsRequest,
252 ) -> Result<Vec<AccountInstrument>, Error> {
253 request.validate()?;
254 self.client.get(ACCOUNT_INSTRUMENTS, request, true).await
255 }
256
257 /// Retrieve the maximum loan amount.
258 ///
259 /// `GET /api/v5/account/max-loan`. Authenticated.
260 ///
261 /// # Errors
262 ///
263 /// Returns [`Error::InvalidRequest`] on validation failure,
264 /// [`Error::Configuration`] if no credentials are set,
265 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
266 pub async fn get_max_loan(&self, request: &MaxLoanRequest) -> Result<Vec<MaxLoan>, Error> {
267 request.validate()?;
268 self.client.get(MAX_LOAN, request, true).await
269 }
270
271 /// Retrieve interest-accrued records.
272 ///
273 /// `GET /api/v5/account/interest-accrued`. Authenticated.
274 ///
275 /// # Errors
276 ///
277 /// Returns [`Error::InvalidRequest`] on validation failure,
278 /// [`Error::Configuration`] if no credentials are set,
279 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
280 pub async fn get_interest_accrued(
281 &self,
282 request: &InterestAccruedRequest,
283 ) -> Result<Vec<InterestAccrued>, Error> {
284 request.validate()?;
285 self.client.get(INTEREST_ACCRUED, request, true).await
286 }
287
288 /// Retrieve interest rates.
289 ///
290 /// `GET /api/v5/account/interest-rate`. Authenticated.
291 ///
292 /// # Errors
293 ///
294 /// Returns [`Error::Configuration`] if no credentials are set,
295 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
296 pub async fn get_interest_rate(&self, ccy: Option<&str>) -> Result<Vec<InterestRate>, Error> {
297 let query = BalanceQuery { ccy };
298 self.client.get(INTEREST_RATE, &query, true).await
299 }
300
301 /// Set the greeks display type.
302 ///
303 /// `POST /api/v5/account/set-greeks`. Authenticated.
304 ///
305 /// # Errors
306 ///
307 /// Returns [`Error::Configuration`] if no credentials are set,
308 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
309 pub async fn set_greeks(&self, greeks_type: &str) -> Result<Vec<SetGreeksResult>, Error> {
310 let body = SetGreeksBody { greeks_type };
311 self.client.post(SET_GREEKS, &body, true).await
312 }
313
314 /// Set isolated margin transfer mode.
315 ///
316 /// `POST /api/v5/account/set-isolated-mode`. Authenticated.
317 ///
318 /// # Errors
319 ///
320 /// Returns [`Error::Configuration`] if no credentials are set,
321 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
322 pub async fn set_isolated_mode(
323 &self,
324 iso_mode: &str,
325 mode_type: &str,
326 ) -> Result<Vec<SetIsolatedModeResult>, Error> {
327 let body = SetIsolatedModeBody {
328 iso_mode,
329 mode_type,
330 };
331 self.client.post(SET_ISOLATED_MODE, &body, true).await
332 }
333
334 /// Retrieve maximum withdrawal amounts.
335 ///
336 /// `GET /api/v5/account/max-withdrawal`. Authenticated.
337 ///
338 /// # Errors
339 ///
340 /// Returns [`Error::Configuration`] if no credentials are set,
341 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
342 pub async fn get_max_withdrawal(&self, ccy: Option<&str>) -> Result<Vec<MaxWithdrawal>, Error> {
343 let query = BalanceQuery { ccy };
344 self.client.get(MAX_WITHDRAWAL, &query, true).await
345 }
346
347 /// Retrieve borrowing rate and limit information.
348 ///
349 /// `GET /api/v5/account/interest-limits`. Authenticated.
350 ///
351 /// # Errors
352 ///
353 /// Returns [`Error::InvalidRequest`] on validation failure,
354 /// [`Error::Configuration`] if no credentials are set,
355 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
356 pub async fn get_interest_limits(
357 &self,
358 request: &InterestLimitsRequest,
359 ) -> Result<Vec<InterestLimit>, Error> {
360 request.validate()?;
361 self.client.get(INTEREST_LIMITS, request, true).await
362 }
363
364 /// Calculate simulated margin information.
365 ///
366 /// `POST /api/v5/account/simulated_margin`. Authenticated. This is separate
367 /// from [`OkxClientBuilder::demo_trading`](crate::OkxClientBuilder::demo_trading),
368 /// which only toggles the OKX simulated-trading header.
369 ///
370 /// # Errors
371 ///
372 /// Returns [`Error::InvalidRequest`] on validation failure,
373 /// [`Error::Configuration`] if no credentials are set,
374 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
375 pub async fn get_simulated_margin(
376 &self,
377 request: &SimulatedMarginRequest,
378 ) -> Result<Vec<SimulatedMargin>, Error> {
379 request.validate()?;
380 self.client.post(SIMULATED_MARGIN, request, true).await
381 }
382
383 /// Retrieve greeks.
384 ///
385 /// `GET /api/v5/account/greeks`. Authenticated.
386 ///
387 /// # Errors
388 ///
389 /// Returns [`Error::Configuration`] if no credentials are set,
390 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
391 pub async fn get_greeks(&self, ccy: Option<&str>) -> Result<Vec<Greek>, Error> {
392 let query = BalanceQuery { ccy };
393 self.client.get(GREEKS, &query, true).await
394 }
395
396 /// Retrieve position history.
397 ///
398 /// `GET /api/v5/account/positions-history`. Authenticated.
399 ///
400 /// # Errors
401 ///
402 /// Returns [`Error::InvalidRequest`] on validation failure,
403 /// [`Error::Configuration`] if no credentials are set,
404 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
405 pub async fn get_positions_history(
406 &self,
407 request: &PositionsHistoryRequest,
408 ) -> Result<Vec<PositionHistory>, Error> {
409 request.validate()?;
410 self.client.get(POSITIONS_HISTORY, request, true).await
411 }
412
413 /// Retrieve account position tiers.
414 ///
415 /// `GET /api/v5/account/position-tiers`. Authenticated.
416 ///
417 /// # Errors
418 ///
419 /// Returns [`Error::InvalidRequest`] on validation failure,
420 /// [`Error::Configuration`] if no credentials are set,
421 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
422 pub async fn get_account_position_tiers(
423 &self,
424 request: &AccountPositionTiersRequest,
425 ) -> Result<Vec<AccountPositionTier>, Error> {
426 request.validate()?;
427 self.client.get(ACCOUNT_POSITION_TIERS, request, true).await
428 }
429
430 /// Retrieve the account risk state.
431 ///
432 /// `GET /api/v5/account/risk-state`. Authenticated.
433 ///
434 /// # Errors
435 ///
436 /// Returns [`Error::Configuration`] if no credentials are set,
437 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
438 pub async fn get_risk_state(&self) -> Result<Vec<RiskState>, Error> {
439 self.client.get(RISK_STATE, &NoQuery, true).await
440 }
441
442 /// Set account auto-loan mode.
443 ///
444 /// `POST /api/v5/account/set-auto-loan`. Authenticated.
445 ///
446 /// # Errors
447 ///
448 /// Returns [`Error::Configuration`] if no credentials are set,
449 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
450 pub async fn set_auto_loan(&self, auto_loan: bool) -> Result<Vec<SetAutoLoanResult>, Error> {
451 let body = SetAutoLoanBody { auto_loan };
452 self.client.post(SET_AUTO_LOAN, &body, true).await
453 }
454
455 /// Set the account level.
456 ///
457 /// `POST /api/v5/account/set-account-level`. Authenticated.
458 ///
459 /// # Errors
460 ///
461 /// Returns [`Error::Configuration`] if no credentials are set,
462 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
463 pub async fn set_account_level(
464 &self,
465 acct_lv: &str,
466 ) -> Result<Vec<SetAccountLevelResult>, Error> {
467 let body = SetAccountLevelBody { acct_lv };
468 self.client.post(SET_ACCOUNT_LEVEL, &body, true).await
469 }
470
471 /// Activate option trading.
472 ///
473 /// `POST /api/v5/account/activate-option`. Authenticated.
474 ///
475 /// # Errors
476 ///
477 /// Returns [`Error::Configuration`] if no credentials are set,
478 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
479 pub async fn activate_option(&self) -> Result<Vec<ActivateOptionResult>, Error> {
480 self.client.post(ACTIVATE_OPTION, &EmptyBody {}, true).await
481 }
482
483 /// Build simulated positions and equity.
484 ///
485 /// `POST /api/v5/account/position-builder`. Authenticated.
486 ///
487 /// # Errors
488 ///
489 /// Returns [`Error::InvalidRequest`] on validation failure,
490 /// [`Error::Configuration`] if no credentials are set,
491 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
492 pub async fn position_builder(
493 &self,
494 request: &PositionBuilderRequest,
495 ) -> Result<Vec<PositionBuilderResult>, Error> {
496 request.validate()?;
497 self.client.post(POSITION_BUILDER, request, true).await
498 }
499
500 /// Manually borrow or repay spot liabilities.
501 ///
502 /// `POST /api/v5/account/spot-manual-borrow-repay`. Authenticated.
503 ///
504 /// # Errors
505 ///
506 /// Returns [`Error::InvalidRequest`] on validation failure,
507 /// [`Error::Configuration`] if no credentials are set,
508 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
509 pub async fn spot_manual_borrow_repay(
510 &self,
511 request: &SpotManualBorrowRepayRequest,
512 ) -> Result<Vec<SpotBorrowRepayResult>, Error> {
513 request.validate()?;
514 self.client
515 .post(SPOT_MANUAL_BORROW_REPAY, request, true)
516 .await
517 }
518
519 /// Set automatic repayment for spot borrow/repay.
520 ///
521 /// `POST /api/v5/account/set-auto-repay`. Authenticated.
522 ///
523 /// # Errors
524 ///
525 /// Returns [`Error::InvalidRequest`] on validation failure,
526 /// [`Error::Configuration`] if no credentials are set,
527 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
528 pub async fn set_auto_repay(
529 &self,
530 request: &SetAutoRepayRequest,
531 ) -> Result<Vec<SetAutoRepayResult>, Error> {
532 request.validate()?;
533 self.client.post(SET_AUTO_REPAY, request, true).await
534 }
535
536 /// Retrieve spot borrow/repay history.
537 ///
538 /// `GET /api/v5/account/spot-borrow-repay-history`. Authenticated.
539 ///
540 /// # Errors
541 ///
542 /// Returns [`Error::InvalidRequest`] on validation failure,
543 /// [`Error::Configuration`] if no credentials are set,
544 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
545 pub async fn get_spot_borrow_repay_history(
546 &self,
547 request: &SpotBorrowRepayHistoryRequest,
548 ) -> Result<Vec<SpotBorrowRepayHistory>, Error> {
549 request.validate()?;
550 self.client
551 .get(SPOT_BORROW_REPAY_HISTORY, request, true)
552 .await
553 }
554
555 /// Set automatic earn for the account.
556 ///
557 /// `POST /api/v5/account/set-auto-earn`. Authenticated.
558 ///
559 /// # Errors
560 ///
561 /// Returns [`Error::InvalidRequest`] on validation failure,
562 /// [`Error::Configuration`] if no credentials are set,
563 /// [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
564 pub async fn set_auto_earn(
565 &self,
566 request: &SetAutoEarnRequest,
567 ) -> Result<Vec<SetAutoEarnResult>, Error> {
568 request.validate()?;
569 self.client.post(SET_AUTO_EARN, request, true).await
570 }
571}