rusty_oms/
order_manager.rs1use crate::execution_engine::{Exchange, ExecutionEngine, ExecutionEvent};
7use crate::risk_manager::RiskManager;
8use rust_decimal::Decimal;
9use rusty_model::trading_order::Order;
10use tokio::sync::mpsc;
12
13pub struct OrderManager<T: Exchange> {
15 execution_engine: ExecutionEngine<T>,
17 event_receiver: mpsc::Receiver<ExecutionEvent>,
19}
20
21impl<T: Exchange> OrderManager<T> {
22 #[must_use]
24 pub fn new(
25 max_order_quantity: Decimal,
26 min_price: Decimal,
27 max_price: Decimal,
28 exchange: T,
29 ) -> Self {
30 let (event_sender, event_receiver) = mpsc::channel(100);
31 let risk_manager = RiskManager::new(max_order_quantity, min_price, max_price);
32
33 Self {
34 execution_engine: ExecutionEngine::<T>::new(risk_manager, event_sender, exchange),
35 event_receiver,
36 }
37 }
38
39 pub async fn submit_order(&mut self, order: Order) -> crate::Result<()> {
43 self.execution_engine
44 .process_order(order)
45 .await
46 .map_err(std::convert::Into::into)
47 }
48
49 pub async fn start_event_processing(&mut self) {
54 while let Some(event) = self.event_receiver.recv().await {
55 match event {
56 ExecutionEvent::OrderAccepted(order) => {
57 log::info!("Order accepted: {order:?}");
58 }
59 ExecutionEvent::OrderRejected(order, reason) => {
60 log::error!("Order rejected: {order:?}, Reason: {reason}");
61 }
62 ExecutionEvent::OrderFilled(order) => {
63 log::info!("Order fully filled: {order:?}");
64 }
65 ExecutionEvent::PartialFill(order, filled_quantity) => {
66 log::info!("Order partially filled: {order:?}, Filled: {filled_quantity}");
67 }
68 }
69 }
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76 use rust_decimal_macros::dec;
77 use rusty_model::{
78 enums::{OrderSide, OrderType},
79 venues::Venue,
80 };
81 use std::sync::Arc;
82 use tokio::sync::Mutex;
83
84 struct MockExchange {
86 send_order_calls: Arc<Mutex<Vec<Order>>>,
88 should_fail: bool,
90 error_message: std::string::String,
92 }
93
94 impl MockExchange {
95 fn new(should_fail: bool, error_message: std::string::String) -> Self {
96 Self {
97 send_order_calls: Arc::new(Mutex::new(Vec::new())),
98 should_fail,
99 error_message,
100 }
101 }
102
103 #[allow(dead_code)]
104 async fn get_send_order_calls(&self) -> Vec<Order> {
105 let calls = self.send_order_calls.lock().await;
106 calls.clone()
107 }
108 }
109
110 #[async_trait::async_trait]
111 impl Exchange for MockExchange {
112 async fn send_order(&self, order: Order) -> crate::Result<()> {
113 let mut calls = self.send_order_calls.lock().await;
115 calls.push(order);
116
117 if self.should_fail {
118 Err(crate::OmsError::Exchange(self.error_message.clone().into()))
119 } else {
120 Ok(())
121 }
122 }
123
124 async fn cancel_order(&self, _order_id: std::string::String) -> crate::Result<()> {
125 Ok(())
127 }
128
129 async fn get_order_status(
130 &self,
131 _order_id: std::string::String,
132 ) -> crate::Result<std::string::String> {
133 Ok("FILLED".into())
135 }
136 }
137
138 fn create_test_order() -> Order {
139 Order::new(
140 Venue::Test,
141 "BTCUSDT",
142 OrderSide::Buy,
143 OrderType::Limit,
144 dec!(1.0),
145 Some(dec!(50000.0)),
146 rusty_model::types::ClientId::new("test_client"),
147 )
148 }
149
150 #[tokio::test]
151 async fn test_order_manager_new() {
152 let max_quantity = dec!(10.0);
153 let min_price = dec!(1000.0);
154 let max_price = dec!(100000.0);
155 let exchange = MockExchange::new(false, std::string::String::new());
156
157 let _order_manager = OrderManager::new(max_quantity, min_price, max_price, exchange);
158 }
160
161 #[tokio::test]
162 async fn test_submit_order_success() {
163 let mock_exchange = MockExchange::new(false, std::string::String::new());
165 let send_order_calls = mock_exchange.send_order_calls.clone();
166
167 let mut order_manager =
169 OrderManager::new(dec!(100.0), dec!(1.0), dec!(1000000.0), mock_exchange);
170
171 let order = create_test_order();
173 let result = order_manager.submit_order(order.clone()).await;
174
175 assert!(result.is_ok());
177
178 let calls = send_order_calls.lock().await;
180 assert_eq!(calls.len(), 1);
181 assert_eq!(calls[0].id, order.id);
182 }
183
184 #[tokio::test]
185 async fn test_submit_order_exchange_failure() {
186 let error_message = "Exchange error".to_string();
188 let mock_exchange = MockExchange::new(true, error_message.clone());
189 let send_order_calls = mock_exchange.send_order_calls.clone();
190
191 let mut order_manager =
193 OrderManager::new(dec!(100.0), dec!(1.0), dec!(1000000.0), mock_exchange);
194
195 let order = create_test_order();
197 let result = order_manager.submit_order(order.clone()).await;
198
199 assert!(result.is_ok());
201
202 let calls = send_order_calls.lock().await;
204 assert_eq!(calls.len(), 1);
205 assert_eq!(calls[0].id, order.id);
206 }
207
208 #[tokio::test]
209 async fn test_submit_order_risk_failure() {
210 let mock_exchange = MockExchange::new(false, std::string::String::new());
212
213 let mut order_manager = OrderManager::new(
215 dec!(0.5), dec!(1.0),
217 dec!(1000000.0),
218 mock_exchange,
219 );
220
221 let order = create_test_order(); let result = order_manager.submit_order(order).await;
224
225 assert!(result.is_err());
227 assert!(
228 matches!(result.unwrap_err(), crate::OmsError::RiskViolation(msg) if msg.contains("QuantityTooLarge"))
229 );
230 }
231}