ig_client/application/services/
order_service.rs

1use crate::application::models::account::WorkingOrders;
2use crate::application::models::order::{
3    ClosePositionRequest, ClosePositionResponse, CreateOrderRequest, CreateOrderResponse,
4    OrderConfirmation, UpdatePositionRequest, UpdatePositionResponse,
5};
6use crate::application::models::working_order::{
7    CreateWorkingOrderRequest, CreateWorkingOrderResponse,
8};
9use crate::application::services::interfaces::order::OrderService;
10use crate::config::Config;
11use crate::error::AppError;
12use crate::session::interface::IgSession;
13use crate::transport::http_client::IgHttpClient;
14use async_trait::async_trait;
15use reqwest::Method;
16use std::sync::Arc;
17use tracing::{debug, info};
18
19/// Implementation of the order service
20pub struct OrderServiceImpl<T: IgHttpClient> {
21    config: Arc<Config>,
22    client: Arc<T>,
23}
24
25impl<T: IgHttpClient> OrderServiceImpl<T> {
26    /// Creates a new instance of the order service
27    pub fn new(config: Arc<Config>, client: Arc<T>) -> Self {
28        Self { config, client }
29    }
30
31    /// Gets the current configuration
32    ///
33    /// # Returns
34    /// * The current configuration as an `Arc<Config>`
35    pub fn get_config(&self) -> Arc<Config> {
36        self.config.clone()
37    }
38
39    /// Sets a new configuration
40    ///
41    /// # Arguments
42    /// * `config` - The new configuration to use
43    pub fn set_config(&mut self, config: Arc<Config>) {
44        self.config = config;
45    }
46}
47
48#[async_trait]
49impl<T: IgHttpClient + 'static> OrderService for OrderServiceImpl<T> {
50    async fn create_order(
51        &self,
52        session: &IgSession,
53        order: &CreateOrderRequest,
54    ) -> Result<CreateOrderResponse, AppError> {
55        info!("Creating order for: {}", order.epic);
56
57        let result = self
58            .client
59            .request::<CreateOrderRequest, CreateOrderResponse>(
60                Method::POST,
61                "positions/otc",
62                session,
63                Some(order),
64                "2",
65            )
66            .await?;
67
68        debug!("Order created with reference: {}", result.deal_reference);
69        Ok(result)
70    }
71
72    async fn get_order_confirmation(
73        &self,
74        session: &IgSession,
75        deal_reference: &str,
76    ) -> Result<OrderConfirmation, AppError> {
77        let path = format!("confirms/{}", deal_reference);
78        info!("Getting confirmation for order: {}", deal_reference);
79
80        let result = self
81            .client
82            .request::<(), OrderConfirmation>(Method::GET, &path, session, None, "1")
83            .await?;
84
85        debug!("Confirmation obtained for order: {}", deal_reference);
86        Ok(result)
87    }
88
89    async fn update_position(
90        &self,
91        session: &IgSession,
92        deal_id: &str,
93        update: &UpdatePositionRequest,
94    ) -> Result<UpdatePositionResponse, AppError> {
95        let path = format!("positions/otc/{}", deal_id);
96        info!("Updating position: {}", deal_id);
97
98        let result = self
99            .client
100            .request::<UpdatePositionRequest, UpdatePositionResponse>(
101                Method::PUT,
102                &path,
103                session,
104                Some(update),
105                "2",
106            )
107            .await?;
108
109        debug!(
110            "Position updated: {} with deal reference: {}",
111            deal_id, result.deal_reference
112        );
113        Ok(result)
114    }
115
116    async fn close_position(
117        &self,
118        session: &IgSession,
119        close_request: &ClosePositionRequest,
120    ) -> Result<ClosePositionResponse, AppError> {
121        info!("Closing position: {}", close_request.deal_id);
122
123        let result = self
124            .client
125            .request::<ClosePositionRequest, ClosePositionResponse>(
126                Method::POST,
127                "positions/otc",
128                session,
129                Some(close_request),
130                "1",
131            )
132            .await?;
133
134        debug!("Position closed with reference: {}", result.deal_reference);
135        Ok(result)
136    }
137
138    async fn get_working_orders(&self, session: &IgSession) -> Result<WorkingOrders, AppError> {
139        info!("Getting all working orders");
140
141        let result = self
142            .client
143            .request::<(), WorkingOrders>(Method::GET, "workingorders", session, None, "2")
144            .await?;
145
146        debug!("Retrieved {} working orders", result.working_orders.len());
147        Ok(result)
148    }
149
150    async fn create_working_order(
151        &self,
152        session: &IgSession,
153        order: &CreateWorkingOrderRequest,
154    ) -> Result<CreateWorkingOrderResponse, AppError> {
155        info!("Creating working order for: {}", order.epic);
156
157        let result = self
158            .client
159            .request::<CreateWorkingOrderRequest, CreateWorkingOrderResponse>(
160                Method::POST,
161                "workingorders/otc",
162                session,
163                Some(order),
164                "2",
165            )
166            .await?;
167
168        debug!(
169            "Working order created with reference: {}",
170            result.deal_reference
171        );
172        Ok(result)
173    }
174}
175
176#[cfg(test)]
177mod tests {
178    use super::*;
179    use crate::config::Config;
180    use crate::transport::http_client::IgHttpClientImpl;
181    use std::sync::Arc;
182
183    #[test]
184    fn test_get_and_set_config() {
185        let config = Arc::new(Config::new());
186        let client = Arc::new(IgHttpClientImpl::new(config.clone()));
187        let mut service = OrderServiceImpl::new(config.clone(), client.clone());
188
189        let cfg1 = service.get_config();
190        assert!(Arc::ptr_eq(&cfg1, &config));
191
192        let new_cfg = Arc::new(Config::default());
193        service.set_config(new_cfg.clone());
194        assert!(Arc::ptr_eq(&service.get_config(), &new_cfg));
195    }
196}