Skip to main content

ccxt_exchanges/okx/rest/
account.rs

1//! Account operations for OKX REST API.
2
3use super::super::{Okx, parser};
4use ccxt_core::{
5    Error, ParseError, Result,
6    types::{Balance, Trade},
7};
8use std::collections::HashMap;
9use tracing::warn;
10
11impl Okx {
12    /// Fetch account balances.
13    ///
14    /// # Returns
15    ///
16    /// Returns a [`Balance`] structure with all currency balances.
17    ///
18    /// # Errors
19    ///
20    /// Returns an error if authentication fails or the API request fails.
21    pub async fn fetch_balance(&self) -> Result<Balance> {
22        let path = Self::build_api_path("/account/balance");
23        let response = self.signed_request(&path).execute().await?;
24
25        let data = response
26            .get("data")
27            .ok_or_else(|| Error::from(ParseError::missing_field("data")))?;
28
29        let balances = data.as_array().ok_or_else(|| {
30            Error::from(ParseError::invalid_format(
31                "data",
32                "Expected array of balances",
33            ))
34        })?;
35
36        if balances.is_empty() {
37            return Ok(Balance {
38                balances: HashMap::new(),
39                info: HashMap::new(),
40            });
41        }
42
43        parser::parse_balance(&balances[0])
44    }
45
46    /// Fetch user's trade history.
47    ///
48    /// # Arguments
49    ///
50    /// * `symbol` - Trading pair symbol.
51    /// * `since` - Optional start timestamp in milliseconds.
52    /// * `limit` - Optional limit on number of trades (maximum: 100).
53    ///
54    /// # Returns
55    ///
56    /// Returns a vector of [`Trade`] structures representing user's trade history.
57    pub async fn fetch_my_trades(
58        &self,
59        symbol: &str,
60        since: Option<i64>,
61        limit: Option<u32>,
62    ) -> Result<Vec<Trade>> {
63        let market = self.base().market(symbol).await?;
64
65        let path = Self::build_api_path("/trade/fills");
66
67        let actual_limit = limit.map_or(100, |l| l.min(100));
68
69        let mut builder = self
70            .signed_request(&path)
71            .param("instId", &market.id)
72            .param("instType", self.get_inst_type())
73            .param("limit", actual_limit);
74
75        if let Some(start_time) = since {
76            builder = builder.param("begin", start_time);
77        }
78
79        let response = builder.execute().await?;
80
81        let data = response
82            .get("data")
83            .ok_or_else(|| Error::from(ParseError::missing_field("data")))?;
84
85        let trades_array = data.as_array().ok_or_else(|| {
86            Error::from(ParseError::invalid_format(
87                "data",
88                "Expected array of trades",
89            ))
90        })?;
91
92        let mut trades = Vec::new();
93        for trade_data in trades_array {
94            match parser::parse_trade(trade_data, Some(&market)) {
95                Ok(trade) => trades.push(trade),
96                Err(e) => {
97                    warn!(error = %e, "Failed to parse my trade");
98                }
99            }
100        }
101
102        Ok(trades)
103    }
104}