rusty_strategy/
lib.rs

1//! # Rusty Strategy
2//!
3//! This crate contains the core trading strategy logic for the Rusty Trading System.
4//! It is responsible for analyzing market data, generating trading signals, and managing
5//! the overall trading strategy.
6
7/// Dual-mode feature calculation for both scalar and vectorized operations.
8pub mod dual_mode_features;
9/// The main trading strategy engine.
10pub mod engine;
11/// Calculates microstructure features from market data.
12pub mod microstructure;
13/// Generates trading signals based on market data and strategy logic.
14pub mod signals;
15/// Defines the core trading strategy trait and implementations.
16pub mod strategy;
17/// Utility functions for the strategy crate.
18pub mod utils;
19/// Vectorized feature calculation for high-performance analysis.
20pub mod vectorized_features;
21
22// Re-export key types for easier access
23pub 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 decimal values for compile-time evaluation
35    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    // Price constants for ML features test
48    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    // Additional test constants
61    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        // Test data with sufficient size to trigger SIMD path
71        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        // Test SIMD-optimized order imbalance calculation
88        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        // Test SIMD-optimized queue imbalance calculation
95        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        // Test SIMD-optimized order book pressure calculation
102        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        // Test data with small size to trigger scalar fallback
119        let ask_qty = vec![ASK_QTY_100, ASK_QTY_150];
120
121        let bid_qty = vec![BID_QTY_120, BID_QTY_180];
122
123        // Should fallback to scalar implementation for small arrays
124        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        // Create comprehensive test data
141        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        // Calculate using both methods
182        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        // Define tolerance for floating point comparisons
201        let tolerance = TOLERANCE;
202
203        // Compare key features that should be identical
204        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        // Manually calculate expected values for verification
267        let ask_total: f64 = 100.0 + 150.0 + 200.0 + 250.0; // 700.0
268        let bid_total: f64 = 120.0 + 180.0 + 240.0 + 300.0; // 840.0
269        let total_depth = ask_total + bid_total; // 1540.0
270
271        let expected_order_imbalance = (bid_total - ask_total) / total_depth; // (840-700)/1540 ≈ 0.0909
272        let expected_order_book_depth = total_depth; // 1540.0
273
274        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}