rusty_oms/
risk_manager.rs1use rust_decimal::Decimal;
7use rusty_model::trading_order::Order;
8use thiserror::Error;
9
10#[derive(Error, Debug)]
12pub enum RiskError {
13 #[error("Order quantity exceeds maximum allowed")]
15 QuantityTooLarge,
16 #[error("Order price outside allowed range")]
18 PriceOutOfRange,
19}
20
21pub struct RiskManager {
23 max_order_quantity: Decimal,
25 min_price: Decimal,
27 max_price: Decimal,
29}
30
31impl RiskManager {
32 #[must_use]
34 pub const fn new(max_order_quantity: Decimal, min_price: Decimal, max_price: Decimal) -> Self {
35 Self {
36 max_order_quantity,
37 min_price,
38 max_price,
39 }
40 }
41
42 pub fn validate_order(&self, order: &Order) -> Result<(), RiskError> {
49 if order.quantity > self.max_order_quantity {
51 return Err(RiskError::QuantityTooLarge);
52 }
53
54 if let Some(price) = order.price
56 && (price < self.min_price || price > self.max_price)
57 {
58 return Err(RiskError::PriceOutOfRange);
59 }
60
61 Ok(())
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68 use rust_decimal_macros::dec;
69 use rusty_model::{
70 enums::{OrderSide, OrderType},
71 venues::Venue,
72 };
73
74 fn create_test_order(quantity: Decimal, price: Decimal) -> Order {
75 Order::new(
76 Venue::Test,
77 "BTCUSDT",
78 OrderSide::Buy,
79 OrderType::Limit,
80 quantity,
81 Some(price),
82 rusty_model::types::ClientId::new("test_client"),
83 )
84 }
85
86 #[test]
87 fn test_risk_manager_new() {
88 let max_quantity = dec!(10.0);
89 let min_price = dec!(1000.0);
90 let max_price = dec!(100000.0);
91
92 let risk_manager = RiskManager::new(max_quantity, min_price, max_price);
93
94 assert_eq!(risk_manager.max_order_quantity, max_quantity);
95 assert_eq!(risk_manager.min_price, min_price);
96 assert_eq!(risk_manager.max_price, max_price);
97 }
98
99 #[test]
100 fn test_validate_order_valid() {
101 let risk_manager = RiskManager::new(dec!(10.0), dec!(1000.0), dec!(100000.0));
102
103 let order = create_test_order(dec!(5.0), dec!(50000.0));
105 let result = risk_manager.validate_order(&order);
106 assert!(result.is_ok());
107 }
108
109 #[test]
110 fn test_validate_order_quantity_too_large() {
111 let risk_manager = RiskManager::new(dec!(10.0), dec!(1000.0), dec!(100000.0));
112
113 let order = create_test_order(dec!(15.0), dec!(50000.0));
115 let result = risk_manager.validate_order(&order);
116 assert!(result.is_err());
117 match result {
118 Err(RiskError::QuantityTooLarge) => (),
119 _ => panic!("Expected QuantityTooLarge error"),
120 }
121 }
122
123 #[test]
124 fn test_validate_order_price_too_low() {
125 let risk_manager = RiskManager::new(dec!(10.0), dec!(1000.0), dec!(100000.0));
126
127 let order = create_test_order(dec!(5.0), dec!(500.0));
129 let result = risk_manager.validate_order(&order);
130 assert!(result.is_err());
131 match result {
132 Err(RiskError::PriceOutOfRange) => (),
133 _ => panic!("Expected PriceOutOfRange error"),
134 }
135 }
136
137 #[test]
138 fn test_validate_order_price_too_high() {
139 let risk_manager = RiskManager::new(dec!(10.0), dec!(1000.0), dec!(100000.0));
140
141 let order = create_test_order(dec!(5.0), dec!(150000.0));
143 let result = risk_manager.validate_order(&order);
144 assert!(result.is_err());
145 match result {
146 Err(RiskError::PriceOutOfRange) => (),
147 _ => panic!("Expected PriceOutOfRange error"),
148 }
149 }
150
151 #[test]
152 fn test_validate_order_edge_cases() {
153 let risk_manager = RiskManager::new(dec!(10.0), dec!(1000.0), dec!(100000.0));
154
155 let order = create_test_order(dec!(10.0), dec!(50000.0));
157 let result = risk_manager.validate_order(&order);
158 assert!(result.is_ok());
159
160 let order = create_test_order(dec!(5.0), dec!(1000.0));
162 let result = risk_manager.validate_order(&order);
163 assert!(result.is_ok());
164
165 let order = create_test_order(dec!(5.0), dec!(100000.0));
167 let result = risk_manager.validate_order(&order);
168 assert!(result.is_ok());
169 }
170}