rusty_oms/
order_manager.rs

1//! Order management module for handling order lifecycle
2//!
3//! This module provides the main interface for submitting orders,
4//! managing their lifecycle, and processing execution events.
5
6use crate::execution_engine::{Exchange, ExecutionEngine, ExecutionEvent};
7use crate::risk_manager::RiskManager;
8use rust_decimal::Decimal;
9use rusty_model::trading_order::Order;
10// use smartstring::alias::String; // Using std::string::String instead
11use tokio::sync::mpsc;
12
13/// High-level order manager that coordinates between risk management and execution
14pub struct OrderManager<T: Exchange> {
15    /// Execution engine for processing orders
16    execution_engine: ExecutionEngine<T>,
17    /// Channel receiver for execution events
18    event_receiver: mpsc::Receiver<ExecutionEvent>,
19}
20
21impl<T: Exchange> OrderManager<T> {
22    /// Create a new order manager with risk limits
23    #[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    /// Submit an order for processing
40    ///
41    /// The order will be validated by the risk manager before being sent to the exchange.
42    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    /// Start processing execution events
50    ///
51    /// This method runs a loop that processes execution events from the exchange.
52    /// It should be run in a separate task.
53    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    // Mock Exchange implementation for testing
85    struct MockExchange {
86        // Track calls to send_order
87        send_order_calls: Arc<Mutex<Vec<Order>>>,
88        // Control whether send_order succeeds or fails
89        should_fail: bool,
90        // Error message to return when should_fail is true
91        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            // Record the call
114            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            // Not used in these tests
126            Ok(())
127        }
128
129        async fn get_order_status(
130            &self,
131            _order_id: std::string::String,
132        ) -> crate::Result<std::string::String> {
133            // Not used in these tests
134            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        // Just testing that it can be created without panicking
159    }
160
161    #[tokio::test]
162    async fn test_submit_order_success() {
163        // Create a mock exchange that succeeds
164        let mock_exchange = MockExchange::new(false, std::string::String::new());
165        let send_order_calls = mock_exchange.send_order_calls.clone();
166
167        // Create an order manager with generous risk limits
168        let mut order_manager =
169            OrderManager::new(dec!(100.0), dec!(1.0), dec!(1000000.0), mock_exchange);
170
171        // Submit an order
172        let order = create_test_order();
173        let result = order_manager.submit_order(order.clone()).await;
174
175        // Verify the result
176        assert!(result.is_ok());
177
178        // Verify the order was sent to the exchange
179        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        // Create a mock exchange that fails
187        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        // Create an order manager with generous risk limits
192        let mut order_manager =
193            OrderManager::new(dec!(100.0), dec!(1.0), dec!(1000000.0), mock_exchange);
194
195        // Submit an order
196        let order = create_test_order();
197        let result = order_manager.submit_order(order.clone()).await;
198
199        // Verify the result - should still be Ok since we handle exchange errors in the execution engine
200        assert!(result.is_ok());
201
202        // Verify the order was sent to the exchange
203        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        // Create a mock exchange
211        let mock_exchange = MockExchange::new(false, std::string::String::new());
212
213        // Create an order manager with strict risk limits that will reject the order
214        let mut order_manager = OrderManager::new(
215            dec!(0.5), // Max quantity is 0.5
216            dec!(1.0),
217            dec!(1000000.0),
218            mock_exchange,
219        );
220
221        // Submit an order with quantity that exceeds the risk limit
222        let order = create_test_order(); // Quantity is 1.0, which exceeds the limit of 0.5
223        let result = order_manager.submit_order(order).await;
224
225        // Verify the result - should be an error
226        assert!(result.is_err());
227        assert!(
228            matches!(result.unwrap_err(), crate::OmsError::RiskViolation(msg) if msg.contains("QuantityTooLarge"))
229        );
230    }
231}