ig_client/application/services/
account_service.rs

1use crate::application::services::AccountService;
2use crate::{
3    application::models::account::{
4        AccountActivity, AccountInfo, Positions, TransactionHistory, WorkingOrders,
5    },
6    config::Config,
7    error::AppError,
8    session::interface::IgSession,
9    transport::http_client::IgHttpClient,
10};
11use async_trait::async_trait;
12use reqwest::Method;
13use std::sync::Arc;
14use tracing::{debug, info};
15
16/// Implementation of the account service
17pub struct AccountServiceImpl<T: IgHttpClient> {
18    config: Arc<Config>,
19    client: Arc<T>,
20}
21
22impl<T: IgHttpClient> AccountServiceImpl<T> {
23    /// Creates a new instance of the account service
24    pub fn new(config: Arc<Config>, client: Arc<T>) -> Self {
25        Self { config, client }
26    }
27
28    /// Gets the current configuration
29    ///
30    /// # Returns
31    /// * The current configuration as an `Arc<Config>`
32    pub fn get_config(&self) -> Arc<Config> {
33        self.config.clone()
34    }
35
36    /// Sets a new configuration
37    ///
38    /// # Arguments
39    /// * `config` - The new configuration to use
40    pub fn set_config(&mut self, config: Arc<Config>) {
41        self.config = config;
42    }
43}
44
45#[async_trait]
46impl<T: IgHttpClient + 'static> AccountService for AccountServiceImpl<T> {
47    async fn get_accounts(&self, session: &IgSession) -> Result<AccountInfo, AppError> {
48        info!("Getting account information");
49
50        let result = self
51            .client
52            .request::<(), AccountInfo>(Method::GET, "accounts", session, None, "1")
53            .await?;
54
55        debug!(
56            "Account information obtained: {} accounts",
57            result.accounts.len()
58        );
59        Ok(result)
60    }
61
62    async fn get_positions(&self, session: &IgSession) -> Result<Positions, AppError> {
63        debug!("Getting open positions");
64
65        let result = self
66            .client
67            .request::<(), Positions>(Method::GET, "positions", session, None, "2")
68            .await?;
69
70        debug!("Positions obtained: {} positions", result.positions.len());
71        Ok(result)
72    }
73
74    async fn get_working_orders(&self, session: &IgSession) -> Result<WorkingOrders, AppError> {
75        info!("Getting working orders");
76
77        let result = self
78            .client
79            .request::<(), WorkingOrders>(Method::GET, "workingorders", session, None, "2")
80            .await?;
81
82        debug!(
83            "Working orders obtained: {} orders",
84            result.working_orders.len()
85        );
86        Ok(result)
87    }
88
89    async fn get_activity(
90        &self,
91        session: &IgSession,
92        from: &str,
93        to: &str,
94    ) -> Result<AccountActivity, AppError> {
95        let path = format!("history/activity?from={}&to={}&pageSize=500", from, to);
96        info!("Getting account activity");
97
98        let result = self
99            .client
100            .request::<(), AccountActivity>(Method::GET, &path, session, None, "3")
101            .await?;
102
103        debug!(
104            "Account activity obtained: {} activities",
105            result.activities.len()
106        );
107        Ok(result)
108    }
109
110    async fn get_activity_with_details(
111        &self,
112        session: &IgSession,
113        from: &str,
114        to: &str,
115    ) -> Result<AccountActivity, AppError> {
116        let path = format!(
117            "history/activity?from={}&to={}&detailed=true&pageSize=500",
118            from, to
119        );
120        info!("Getting detailed account activity");
121
122        let result = self
123            .client
124            .request::<(), AccountActivity>(Method::GET, &path, session, None, "3")
125            .await?;
126
127        debug!(
128            "Detailed account activity obtained: {} activities",
129            result.activities.len()
130        );
131        Ok(result)
132    }
133
134    async fn get_transactions(
135        &self,
136        session: &IgSession,
137        from: &str,
138        to: &str,
139        page_size: u32,
140        page_number: u32,
141    ) -> Result<TransactionHistory, AppError> {
142        let path = format!(
143            "history/transactions?from={}&to={}&pageSize={}&pageNumber={}",
144            from, to, page_size, page_number
145        );
146        info!("Getting transaction history");
147
148        let result = self
149            .client
150            .request::<(), TransactionHistory>(Method::GET, &path, session, None, "2")
151            .await?;
152
153        debug!(
154            "Transaction history obtained: {} transactions",
155            result.transactions.len()
156        );
157        Ok(result)
158    }
159}
160
161#[cfg(test)]
162mod tests {
163    use super::*;
164    use crate::config::Config;
165    use crate::transport::http_client::IgHttpClientImpl;
166    use crate::utils::rate_limiter::RateLimitType;
167    use std::sync::Arc;
168
169    #[test]
170    fn test_get_and_set_config() {
171        let config = Arc::new(Config::with_rate_limit_type(
172            RateLimitType::TradingAccount,
173            0.7,
174        ));
175        let client = Arc::new(IgHttpClientImpl::new(config.clone()));
176        let mut service = AccountServiceImpl::new(config.clone(), client.clone());
177
178        let cfg1 = service.get_config();
179        assert!(Arc::ptr_eq(&cfg1, &config));
180
181        let new_cfg = Arc::new(Config::default());
182        service.set_config(new_cfg.clone());
183        assert!(Arc::ptr_eq(&service.get_config(), &new_cfg));
184    }
185}