1pub mod dual_mode_features;
9pub mod engine;
11pub mod microstructure;
13pub mod signals;
15pub mod strategy;
17pub mod utils;
19pub mod vectorized_features;
21
22pub use microstructure::{MicrostructureCalculator, TradeFeatures};
24pub use vectorized_features::{
25 PriceFeatures, VectorizedFeatures, VolumeFeatures, WeightedFeatures,
26};
27
28#[cfg(test)]
29mod simd_integration_tests {
30 use super::*;
31 use rust_decimal::Decimal;
32 use rust_decimal_macros::dec;
33
34 const ASK_QTY_100: Decimal = dec!(100.0);
36 const ASK_QTY_150: Decimal = dec!(150.0);
37 const ASK_QTY_200: Decimal = dec!(200.0);
38 const ASK_QTY_250: Decimal = dec!(250.0);
39 const ASK_QTY_300: Decimal = dec!(300.0);
40
41 const BID_QTY_120: Decimal = dec!(120.0);
42 const BID_QTY_180: Decimal = dec!(180.0);
43 const BID_QTY_240: Decimal = dec!(240.0);
44 const BID_QTY_300: Decimal = dec!(300.0);
45 const BID_QTY_360: Decimal = dec!(360.0);
46
47 const ASK_PRICE_50010: Decimal = dec!(50010.0);
49 const ASK_PRICE_50020: Decimal = dec!(50020.0);
50 const ASK_PRICE_50030: Decimal = dec!(50030.0);
51 const ASK_PRICE_50040: Decimal = dec!(50040.0);
52 const ASK_PRICE_50050: Decimal = dec!(50050.0);
53
54 const BID_PRICE_49990: Decimal = dec!(49990.0);
55 const BID_PRICE_49980: Decimal = dec!(49980.0);
56 const BID_PRICE_49970: Decimal = dec!(49970.0);
57 const BID_PRICE_49960: Decimal = dec!(49960.0);
58 const BID_PRICE_49950: Decimal = dec!(49950.0);
59
60 const TRADE_QTY_50: Decimal = dec!(50.0);
62 const TRADE_QTY_75: Decimal = dec!(75.0);
63 const TRADE_QTY_60: Decimal = dec!(60.0);
64 const TOLERANCE: Decimal = dec!(0.0001);
65
66 #[test]
67 fn test_simd_integration_basic() {
68 let calc = MicrostructureCalculator::<128>::new(100);
69
70 let ask_qty = vec![
72 ASK_QTY_100,
73 ASK_QTY_150,
74 ASK_QTY_200,
75 ASK_QTY_250,
76 ASK_QTY_300,
77 ];
78
79 let bid_qty = vec![
80 BID_QTY_120,
81 BID_QTY_180,
82 BID_QTY_240,
83 BID_QTY_300,
84 BID_QTY_360,
85 ];
86
87 let imbalance = calc.calc_order_imbalance(&ask_qty, &bid_qty);
89 assert!(
90 !imbalance.is_zero(),
91 "SIMD order imbalance should return a non-zero value"
92 );
93
94 let queue_imbalance = calc.calc_queue_imbalance(&ask_qty, &bid_qty);
96 assert!(
97 !queue_imbalance.is_zero(),
98 "SIMD queue imbalance should return a non-zero value"
99 );
100
101 let pressure = calc.calc_order_book_pressure(&ask_qty, &bid_qty, 5);
103 assert!(
104 !pressure.is_zero(),
105 "SIMD order book pressure should return a non-zero value"
106 );
107
108 println!("✅ SIMD integration test passed!");
109 println!("Order imbalance: {imbalance}");
110 println!("Queue imbalance: {queue_imbalance}");
111 println!("Order book pressure: {pressure}");
112 }
113
114 #[test]
115 fn test_simd_fallback_for_small_arrays() {
116 let calc = MicrostructureCalculator::<128>::new(100);
117
118 let ask_qty = vec![ASK_QTY_100, ASK_QTY_150];
120
121 let bid_qty = vec![BID_QTY_120, BID_QTY_180];
122
123 let imbalance = calc.calc_order_imbalance(&ask_qty, &bid_qty);
125 assert!(
126 !imbalance.is_zero(),
127 "Scalar fallback should work for small arrays"
128 );
129
130 println!("✅ SIMD fallback test passed!");
131 println!("Small array imbalance: {imbalance}");
132 }
133
134 #[test]
135 fn test_ml_features_simd_vs_scalar_correctness() {
136 use microstructure::{OrderSide, TradeFeatures};
137
138 let calc = MicrostructureCalculator::<128>::new(100);
139
140 let ask_prices = vec![
142 ASK_PRICE_50010,
143 ASK_PRICE_50020,
144 ASK_PRICE_50030,
145 ASK_PRICE_50040,
146 ASK_PRICE_50050,
147 ];
148
149 let bid_prices = vec![
150 BID_PRICE_49990,
151 BID_PRICE_49980,
152 BID_PRICE_49970,
153 BID_PRICE_49960,
154 BID_PRICE_49950,
155 ];
156
157 let ask_volumes = vec![
158 ASK_QTY_100,
159 ASK_QTY_150,
160 ASK_QTY_200,
161 ASK_QTY_250,
162 ASK_QTY_300,
163 ];
164
165 let bid_volumes = vec![
166 BID_QTY_120,
167 BID_QTY_180,
168 BID_QTY_240,
169 BID_QTY_300,
170 BID_QTY_360,
171 ];
172
173 let trades = vec![
174 TradeFeatures::new(ask_prices[0], TRADE_QTY_50, OrderSide::Buy),
175 TradeFeatures::new(bid_prices[0], TRADE_QTY_75, OrderSide::Sell),
176 TradeFeatures::new(ask_prices[1], TRADE_QTY_60, OrderSide::Buy),
177 ];
178
179 let window = 2;
180
181 let scalar_features = calc.calc_ml_features(
183 &ask_prices,
184 &ask_volumes,
185 &bid_prices,
186 &bid_volumes,
187 &trades,
188 window,
189 );
190
191 let simd_features = calc.calc_ml_features_simd(
192 &ask_prices,
193 &ask_volumes,
194 &bid_prices,
195 &bid_volumes,
196 &trades,
197 window,
198 );
199
200 let tolerance = TOLERANCE;
202
203 assert!(
205 (scalar_features.spread - simd_features.spread).abs() < tolerance,
206 "Spread mismatch: scalar={}, simd={}",
207 scalar_features.spread,
208 simd_features.spread
209 );
210
211 assert!(
212 (scalar_features.mid_price - simd_features.mid_price).abs() < tolerance,
213 "Mid price mismatch: scalar={}, simd={}",
214 scalar_features.mid_price,
215 simd_features.mid_price
216 );
217
218 assert!(
219 (scalar_features.order_imbalance - simd_features.order_imbalance).abs() < tolerance,
220 "Order imbalance mismatch: scalar={}, simd={}",
221 scalar_features.order_imbalance,
222 simd_features.order_imbalance
223 );
224
225 assert!(
226 (scalar_features.order_book_depth - simd_features.order_book_depth).abs() < tolerance,
227 "Order book depth mismatch: scalar={}, simd={}",
228 scalar_features.order_book_depth,
229 simd_features.order_book_depth
230 );
231
232 assert!(
233 (scalar_features.liquidity_shocks - simd_features.liquidity_shocks).abs() < tolerance,
234 "Liquidity shocks mismatch: scalar={}, simd={}",
235 scalar_features.liquidity_shocks,
236 simd_features.liquidity_shocks
237 );
238
239 println!("✅ SIMD ML features correctness test passed!");
240 println!(
241 "Scalar spread: {}, SIMD spread: {}",
242 scalar_features.spread, simd_features.spread
243 );
244 println!(
245 "Scalar order imbalance: {}, SIMD order imbalance: {}",
246 scalar_features.order_imbalance, simd_features.order_imbalance
247 );
248 println!(
249 "Scalar depth: {}, SIMD depth: {}",
250 scalar_features.order_book_depth, simd_features.order_book_depth
251 );
252 }
253
254 #[test]
255 fn test_volume_features_batch_correctness() {
256 use vectorized_features::VectorizedFeatures;
257
258 let mut vectorized = VectorizedFeatures::<64>::new();
259
260 let ask_volumes = vec![ASK_QTY_100, ASK_QTY_150, ASK_QTY_200, ASK_QTY_250];
261
262 let bid_volumes = vec![BID_QTY_120, BID_QTY_180, BID_QTY_240, BID_QTY_300];
263
264 let batch_features = vectorized.calc_volume_features_batch(&ask_volumes, &bid_volumes);
265
266 let ask_total: f64 = 100.0 + 150.0 + 200.0 + 250.0; let bid_total: f64 = 120.0 + 180.0 + 240.0 + 300.0; let total_depth = ask_total + bid_total; let expected_order_imbalance = (bid_total - ask_total) / total_depth; let expected_order_book_depth = total_depth; let tolerance = 0.0001;
275
276 assert!(
277 (batch_features.order_imbalance - expected_order_imbalance).abs() < tolerance,
278 "Order imbalance mismatch: batch={}, expected={}",
279 batch_features.order_imbalance,
280 expected_order_imbalance
281 );
282
283 assert!(
284 (batch_features.order_book_depth - expected_order_book_depth).abs() < tolerance,
285 "Order book depth mismatch: batch={}, expected={}",
286 batch_features.order_book_depth,
287 expected_order_book_depth
288 );
289
290 println!("✅ Volume features batch correctness test passed!");
291 println!("Batch order imbalance: {}", batch_features.order_imbalance);
292 println!(
293 "Batch order book depth: {}",
294 batch_features.order_book_depth
295 );
296 }
297}