ig_client/application/services/
order_service.rs1use 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
19pub struct OrderServiceImpl<T: IgHttpClient> {
21 config: Arc<Config>,
22 client: Arc<T>,
23}
24
25impl<T: IgHttpClient> OrderServiceImpl<T> {
26 pub fn new(config: Arc<Config>, client: Arc<T>) -> Self {
28 Self { config, client }
29 }
30
31 pub fn get_config(&self) -> Arc<Config> {
36 self.config.clone()
37 }
38
39 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!("{}", serde_json::to_string(close_request)?);
122 let result = self
123 .client
124 .request::<ClosePositionRequest, ClosePositionResponse>(
125 Method::DELETE,
126 "positions/otc",
127 session,
128 Some(close_request),
129 "1",
130 )
131 .await?;
132
133 debug!("Position closed with reference: {}", result.deal_reference);
134 Ok(result)
135 }
136
137 async fn get_working_orders(&self, session: &IgSession) -> Result<WorkingOrders, AppError> {
138 info!("Getting all working orders");
139
140 let result = self
141 .client
142 .request::<(), WorkingOrders>(Method::GET, "workingorders", session, None, "2")
143 .await?;
144
145 debug!("Retrieved {} working orders", result.working_orders.len());
146 Ok(result)
147 }
148
149 async fn create_working_order(
150 &self,
151 session: &IgSession,
152 order: &CreateWorkingOrderRequest,
153 ) -> Result<CreateWorkingOrderResponse, AppError> {
154 info!("Creating working order for: {}", order.epic);
155
156 let result = self
157 .client
158 .request::<CreateWorkingOrderRequest, CreateWorkingOrderResponse>(
159 Method::POST,
160 "workingorders/otc",
161 session,
162 Some(order),
163 "2",
164 )
165 .await?;
166
167 debug!(
168 "Working order created with reference: {}",
169 result.deal_reference
170 );
171 Ok(result)
172 }
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178 use crate::config::Config;
179 use crate::transport::http_client::IgHttpClientImpl;
180 use crate::utils::rate_limiter::RateLimitType;
181 use std::sync::Arc;
182
183 #[test]
184 fn test_get_and_set_config() {
185 let config = Arc::new(Config::with_rate_limit_type(
186 RateLimitType::NonTradingAccount,
187 0.7,
188 ));
189 let client = Arc::new(IgHttpClientImpl::new(config.clone()));
190 let mut service = OrderServiceImpl::new(config.clone(), client.clone());
191
192 let cfg1 = service.get_config();
193 assert!(Arc::ptr_eq(&cfg1, &config));
194
195 let new_cfg = Arc::new(Config::default());
196 service.set_config(new_cfg.clone());
197 assert!(Arc::ptr_eq(&service.get_config(), &new_cfg));
198 }
199}