Skip to main content

rust_okx/api/finance/
api.rs

1use crate::api::finance::internal::CancelRedeemBody;
2use crate::client::OkxClient;
3use crate::error::Error;
4use crate::model::ValidateRequest;
5use crate::transport::Transport;
6
7use super::endpoints::*;
8use super::internal::{AmountBody, DaysQuery, NoParams, SetLendingRateBody, optional_ccy};
9use super::requests::*;
10use super::responses::*;
11/// Accessor for OKX finance endpoint groups.
12///
13/// Obtain one via [`OkxClient::finance`](crate::OkxClient::finance).
14pub struct Finance<'a, T> {
15    client: &'a OkxClient<T>,
16}
17
18impl<'a, T: Transport> Finance<'a, T> {
19    pub(crate) fn new(client: &'a OkxClient<T>) -> Self {
20        Self { client }
21    }
22
23    /// Access Savings endpoints.
24    pub fn savings(&self) -> Savings<'_, T> {
25        Savings {
26            client: self.client,
27        }
28    }
29
30    /// Access Staking/DeFi endpoints.
31    pub fn staking_defi(&self) -> StakingDefi<'_, T> {
32        StakingDefi {
33            client: self.client,
34        }
35    }
36
37    /// Access ETH staking endpoints.
38    pub fn eth_staking(&self) -> EthStaking<'_, T> {
39        EthStaking {
40            client: self.client,
41        }
42    }
43
44    /// Access SOL staking endpoints.
45    pub fn sol_staking(&self) -> SolStaking<'_, T> {
46        SolStaking {
47            client: self.client,
48        }
49    }
50
51    /// Access Flexible Loan endpoints.
52    pub fn flexible_loan(&self) -> FlexibleLoan<'_, T> {
53        FlexibleLoan {
54            client: self.client,
55        }
56    }
57}
58
59/// Accessor for Savings endpoints.
60pub struct Savings<'a, T> {
61    client: &'a OkxClient<T>,
62}
63
64impl<T: Transport> Savings<'_, T> {
65    /// Retrieve savings balances.
66    ///
67    /// `GET /api/v5/finance/savings/balance`. Authenticated.
68    ///
69    /// # Errors
70    ///
71    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero
72    /// OKX code, or transport/decode errors.
73    pub async fn get_saving_balance(&self, ccy: Option<&str>) -> Result<Vec<SavingBalance>, Error> {
74        let query = optional_ccy(ccy);
75        self.client.get(SAVINGS_BALANCE, &query, true).await
76    }
77
78    /// Purchase or redeem savings.
79    ///
80    /// `POST /api/v5/finance/savings/purchase-redempt`. Authenticated.
81    ///
82    /// # Errors
83    ///
84    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero
85    /// OKX code, or transport/decode errors.
86    pub async fn purchase_redemption(
87        &self,
88        request: &SavingsPurchaseRedemptionRequest,
89    ) -> Result<Vec<SavingsPurchaseRedemptionResult>, Error> {
90        request.validate()?;
91        self.client
92            .post(SAVINGS_PURCHASE_REDEMPT, request, true)
93            .await
94    }
95
96    /// Set the savings lending rate.
97    ///
98    /// `POST /api/v5/finance/savings/set-lending-rate`. Authenticated.
99    ///
100    /// # Errors
101    ///
102    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero
103    /// OKX code, or transport/decode errors.
104    pub async fn set_lending_rate(
105        &self,
106        ccy: &str,
107        rate: &str,
108    ) -> Result<Vec<SetLendingRateResult>, Error> {
109        let body = SetLendingRateBody { ccy, rate };
110        self.client
111            .post(SAVINGS_SET_LENDING_RATE, &body, true)
112            .await
113    }
114
115    /// Retrieve lending history.
116    ///
117    /// `GET /api/v5/finance/savings/lending-history`. Authenticated.
118    ///
119    /// # Errors
120    ///
121    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero
122    /// OKX code, or transport/decode errors.
123    pub async fn get_lending_history(
124        &self,
125        request: &FinanceHistoryRequest,
126    ) -> Result<Vec<LendingHistory>, Error> {
127        request.validate()?;
128        self.client
129            .get(SAVINGS_LENDING_HISTORY, request, true)
130            .await
131    }
132
133    /// Retrieve public borrow history.
134    ///
135    /// `GET /api/v5/finance/savings/lending-rate-history`. Public.
136    ///
137    /// # Errors
138    ///
139    /// Returns [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
140    pub async fn get_public_borrow_history(
141        &self,
142        request: &FinanceHistoryRequest,
143    ) -> Result<Vec<PublicBorrowHistory>, Error> {
144        request.validate()?;
145        self.client
146            .get(SAVINGS_PUBLIC_BORROW_HISTORY, request, false)
147            .await
148    }
149
150    /// Retrieve public borrow info.
151    ///
152    /// `GET /api/v5/finance/savings/lending-rate-summary`. Public.
153    ///
154    /// # Errors
155    ///
156    /// Returns [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
157    pub async fn get_public_borrow_info(
158        &self,
159        ccy: Option<&str>,
160    ) -> Result<Vec<PublicBorrowInfo>, Error> {
161        let query = optional_ccy(ccy);
162        self.client
163            .get(SAVINGS_PUBLIC_BORROW_INFO, &query, false)
164            .await
165    }
166}
167
168/// Accessor for Staking/DeFi endpoints.
169pub struct StakingDefi<'a, T> {
170    client: &'a OkxClient<T>,
171}
172
173impl<T: Transport> StakingDefi<'_, T> {
174    /// Retrieve Staking/DeFi offers.
175    ///
176    /// `GET /api/v5/finance/staking-defi/offers`. Authenticated.
177    ///
178    /// # Errors
179    ///
180    /// Returns [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
181    pub async fn get_offers(
182        &self,
183        request: &StakingDefiOffersRequest,
184    ) -> Result<Vec<StakingDefiOffer>, Error> {
185        request.validate()?;
186        self.client.get(STAKING_DEFI_OFFERS, request, true).await
187    }
188
189    /// Purchase a Staking/DeFi product.
190    ///
191    /// `POST /api/v5/finance/staking-defi/purchase`. Authenticated.
192    ///
193    /// # Errors
194    ///
195    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
196    pub async fn purchase(
197        &self,
198        request: &StakingDefiPurchaseRequest,
199    ) -> Result<Vec<StakingDefiOrder>, Error> {
200        request.validate()?;
201        self.client.post(STAKING_DEFI_PURCHASE, request, true).await
202    }
203
204    /// Redeem a Staking/DeFi order.
205    ///
206    /// `POST /api/v5/finance/staking-defi/redeem`. Authenticated.
207    ///
208    /// # Errors
209    ///
210    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
211    pub async fn redeem(
212        &self,
213        request: &StakingDefiRedeemRequest,
214    ) -> Result<Vec<StakingDefiOrder>, Error> {
215        request.validate()?;
216        self.client.post(STAKING_DEFI_REDEEM, request, true).await
217    }
218
219    /// Cancel a Staking/DeFi order.
220    ///
221    /// `POST /api/v5/finance/staking-defi/cancel`. Authenticated.
222    ///
223    /// # Errors
224    ///
225    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
226    pub async fn cancel(
227        &self,
228        request: &StakingDefiCancelRequest,
229    ) -> Result<Vec<StakingDefiOrder>, Error> {
230        request.validate()?;
231        self.client.post(STAKING_DEFI_CANCEL, request, true).await
232    }
233
234    /// Retrieve active Staking/DeFi orders.
235    ///
236    /// `GET /api/v5/finance/staking-defi/orders-active`. Authenticated.
237    ///
238    /// # Errors
239    ///
240    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
241    pub async fn get_active_orders(
242        &self,
243        request: &StakingDefiActiveOrdersRequest,
244    ) -> Result<Vec<StakingDefiOrder>, Error> {
245        request.validate()?;
246        self.client
247            .get(STAKING_DEFI_ACTIVE_ORDERS, request, true)
248            .await
249    }
250
251    /// Retrieve Staking/DeFi order history.
252    ///
253    /// `GET /api/v5/finance/staking-defi/orders-history`. Authenticated.
254    ///
255    /// # Errors
256    ///
257    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
258    pub async fn get_orders_history(
259        &self,
260        request: &StakingDefiOrderHistoryRequest,
261    ) -> Result<Vec<StakingDefiOrder>, Error> {
262        request.validate()?;
263        self.client
264            .get(STAKING_DEFI_ORDERS_HISTORY, request, true)
265            .await
266    }
267}
268
269/// Accessor for ETH staking endpoints.
270pub struct EthStaking<'a, T> {
271    client: &'a OkxClient<T>,
272}
273
274impl<T: Transport> EthStaking<'_, T> {
275    /// Retrieve ETH staking product info.
276    ///
277    /// `GET /api/v5/finance/staking-defi/eth/product-info`. Authenticated.
278    ///
279    /// # Errors
280    ///
281    /// Returns [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
282    pub async fn product_info(&self) -> Result<Vec<StakingProductInfo>, Error> {
283        self.client.get(ETH_PRODUCT_INFO, &NoParams {}, true).await
284    }
285
286    /// Purchase ETH staking.
287    ///
288    /// `POST /api/v5/finance/staking-defi/eth/purchase`. Authenticated.
289    ///
290    /// # Errors
291    ///
292    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
293    pub async fn purchase(&self, amt: &str) -> Result<Vec<StakingOrder>, Error> {
294        let body = AmountBody { amt };
295        self.client.post(ETH_PURCHASE, &body, true).await
296    }
297
298    /// Redeem ETH staking.
299    ///
300    /// `POST /api/v5/finance/staking-defi/eth/redeem`. Authenticated.
301    ///
302    /// # Errors
303    ///
304    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
305    pub async fn redeem(&self, amt: &str) -> Result<Vec<StakingOrder>, Error> {
306        let body = AmountBody { amt };
307        self.client.post(ETH_REDEEM, &body, true).await
308    }
309
310    /// Cancel redeem ETH staking.
311    ///
312    /// `POST /api/v5/finance/staking-defi/eth/cancel-redeem`. Authenticated.
313    ///
314    /// # Errors
315    ///
316    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
317    pub async fn cancel_redeem(&self, ord_id: &str) -> Result<Vec<CancelRedeem>, Error> {
318        let body = CancelRedeemBody { ord_id };
319        self.client.post(ETH_CANCEL_REDEEM, &body, true).await
320    }
321
322    /// Retrieve ETH staking balance.
323    ///
324    /// `GET /api/v5/finance/staking-defi/eth/balance`. Authenticated.
325    ///
326    /// # Errors
327    ///
328    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
329    pub async fn balance(&self) -> Result<Vec<StakingBalance>, Error> {
330        self.client.get(ETH_BALANCE, &NoParams {}, true).await
331    }
332
333    /// Retrieve ETH staking purchase/redeem history.
334    ///
335    /// `GET /api/v5/finance/staking-defi/eth/purchase-redeem-history`. Authenticated.
336    ///
337    /// # Errors
338    ///
339    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
340    pub async fn purchase_redeem_history(
341        &self,
342        request: &FinanceHistoryRequest,
343    ) -> Result<Vec<StakingHistory>, Error> {
344        request.validate()?;
345        self.client.get(ETH_HISTORY, request, true).await
346    }
347
348    /// Retrieve ETH staking APY history.
349    ///
350    /// `GET /api/v5/finance/staking-defi/eth/apy-history`. Public.
351    ///
352    /// # Errors
353    ///
354    /// Returns [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
355    pub async fn apy_history(&self, days: &str) -> Result<Vec<StakingApyHistory>, Error> {
356        let query = DaysQuery { days };
357        self.client.get(ETH_APY_HISTORY, &query, false).await
358    }
359}
360
361/// Accessor for SOL staking endpoints.
362pub struct SolStaking<'a, T> {
363    client: &'a OkxClient<T>,
364}
365
366impl<T: Transport> SolStaking<'_, T> {
367    /// Retrieve SOL staking product info.
368    ///
369    /// `GET /api/v5/finance/staking-defi/sol/product-info`. Authenticated.
370    ///
371    /// # Errors
372    ///
373    /// Returns [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
374    pub async fn product_info(&self) -> Result<StakingProductInfo, Error> {
375        self.client.get(SOL_PRODUCT_INFO, &NoParams {}, true).await
376    }
377
378    /// Purchase SOL staking.
379    ///
380    /// `POST /api/v5/finance/staking-defi/sol/purchase`. Authenticated.
381    ///
382    /// # Errors
383    ///
384    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
385    pub async fn purchase(&self, amt: &str) -> Result<Vec<StakingOrder>, Error> {
386        let body = AmountBody { amt };
387        self.client.post(SOL_PURCHASE, &body, true).await
388    }
389
390    /// Redeem SOL staking.
391    ///
392    /// `POST /api/v5/finance/staking-defi/sol/redeem`. Authenticated.
393    ///
394    /// # Errors
395    ///
396    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
397    pub async fn redeem(&self, amt: &str) -> Result<Vec<StakingOrder>, Error> {
398        let body = AmountBody { amt };
399        self.client.post(SOL_REDEEM, &body, true).await
400    }
401
402    /// Retrieve SOL staking balance.
403    ///
404    /// `GET /api/v5/finance/staking-defi/sol/balance`. Authenticated.
405    ///
406    /// # Errors
407    ///
408    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
409    pub async fn balance(&self) -> Result<Vec<StakingBalance>, Error> {
410        self.client.get(SOL_BALANCE, &NoParams {}, true).await
411    }
412
413    /// Retrieve SOL staking purchase/redeem history.
414    ///
415    /// `GET /api/v5/finance/staking-defi/sol/purchase-redeem-history`. Authenticated.
416    ///
417    /// # Errors
418    ///
419    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
420    pub async fn purchase_redeem_history(
421        &self,
422        request: &FinanceHistoryRequest,
423    ) -> Result<Vec<StakingHistory>, Error> {
424        request.validate()?;
425        self.client.get(SOL_HISTORY, request, true).await
426    }
427
428    /// Retrieve SOL staking APY history.
429    ///
430    /// `GET /api/v5/finance/staking-defi/sol/apy-history`. Public.
431    ///
432    /// # Errors
433    ///
434    /// Returns [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
435    pub async fn apy_history(&self, days: &str) -> Result<Vec<StakingApyHistory>, Error> {
436        let query = DaysQuery { days };
437        self.client.get(SOL_APY_HISTORY, &query, false).await
438    }
439}
440
441/// Accessor for Flexible Loan endpoints.
442pub struct FlexibleLoan<'a, T> {
443    client: &'a OkxClient<T>,
444}
445
446impl<T: Transport> FlexibleLoan<'_, T> {
447    /// Retrieve borrowable currencies.
448    ///
449    /// `GET /api/v5/finance/flexible-loan/borrow-currencies`. Authenticated.
450    ///
451    /// # Errors
452    ///
453    /// Returns [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
454    pub async fn borrow_currencies(&self) -> Result<Vec<FlexibleLoanCurrency>, Error> {
455        self.client
456            .get(FLEX_BORROW_CURRENCIES, &NoParams {}, true)
457            .await
458    }
459
460    /// Retrieve collateral assets.
461    ///
462    /// `GET /api/v5/finance/flexible-loan/collateral-assets`. Public.
463    ///
464    /// # Errors
465    ///
466    /// Returns [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
467    pub async fn collateral_assets(
468        &self,
469        request: &FlexibleLoanCollateralAssetsRequest,
470    ) -> Result<Vec<FlexibleLoanCollateralAsset>, Error> {
471        request.validate()?;
472        self.client
473            .get(FLEX_COLLATERAL_ASSETS, request, false)
474            .await
475    }
476
477    /// Estimate maximum flexible-loan amount.
478    ///
479    /// `POST /api/v5/finance/flexible-loan/max-loan`. Authenticated.
480    ///
481    /// # Errors
482    ///
483    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
484    pub async fn max_loan(
485        &self,
486        request: &FlexibleLoanMaxLoanRequest,
487    ) -> Result<Vec<FlexibleLoanMaxLoan>, Error> {
488        request.validate()?;
489        self.client.post(FLEX_MAX_LOAN, request, true).await
490    }
491
492    /// Retrieve maximum collateral redeem amount.
493    ///
494    /// `GET /api/v5/finance/flexible-loan/max-collateral-redeem-amount`. Authenticated.
495    ///
496    /// # Errors
497    ///
498    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
499    pub async fn max_collateral_redeem_amount(
500        &self,
501        request: &FlexibleLoanMaxRedeemRequest,
502    ) -> Result<Vec<FlexibleLoanMaxRedeem>, Error> {
503        request.validate()?;
504        self.client.get(FLEX_MAX_REDEEM, request, true).await
505    }
506
507    /// Adjust flexible-loan collateral.
508    ///
509    /// `POST /api/v5/finance/flexible-loan/adjust-collateral`. Authenticated.
510    ///
511    /// # Errors
512    ///
513    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
514    pub async fn adjust_collateral(
515        &self,
516        request: &FlexibleLoanAdjustCollateralRequest,
517    ) -> Result<Vec<FlexibleLoanOrder>, Error> {
518        request.validate()?;
519        self.client
520            .post(FLEX_ADJUST_COLLATERAL, request, true)
521            .await
522    }
523
524    /// Retrieve flexible-loan info.
525    ///
526    /// `GET /api/v5/finance/flexible-loan/loan-info`. Authenticated.
527    ///
528    /// # Errors
529    ///
530    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
531    pub async fn loan_info(
532        &self,
533        request: &FlexibleLoanInfoRequest,
534    ) -> Result<Vec<FlexibleLoanInfo>, Error> {
535        request.validate()?;
536        self.client.get(FLEX_LOAN_INFO, request, true).await
537    }
538
539    /// Retrieve flexible-loan history.
540    ///
541    /// `GET /api/v5/finance/flexible-loan/loan-history`. Authenticated.
542    ///
543    /// # Errors
544    ///
545    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
546    pub async fn loan_history(
547        &self,
548        request: &FlexibleLoanHistoryRequest,
549    ) -> Result<Vec<FlexibleLoanHistory>, Error> {
550        request.validate()?;
551        self.client.get(FLEX_LOAN_HISTORY, request, true).await
552    }
553
554    /// Retrieve flexible-loan accrued interest.
555    ///
556    /// `GET /api/v5/finance/flexible-loan/interest-accrued`. Authenticated.
557    ///
558    /// # Errors
559    ///
560    /// Returns [`Error::Configuration`] without credentials, [`Error::Api`] on a non-zero OKX code, or transport/decode errors.
561    pub async fn interest_accrued(
562        &self,
563        request: &FlexibleLoanInterestAccruedRequest,
564    ) -> Result<Vec<FlexibleLoanInterest>, Error> {
565        request.validate()?;
566        self.client.get(FLEX_INTEREST_ACCRUED, request, true).await
567    }
568}