//! # Financial Feature Engineering for HFT Transformers //! //! This module implements state-of-the-art feature extraction for financial //! market microstructure data, optimized for transformer model input. //! //! ## Key Features //! //! - **Order Book Imbalance**: Bid/ask volume imbalances and pressure //! - **Trade Flow Analysis**: Aggressive vs passive order flow patterns //! - **Microstructure Signals**: Spread, volatility, intensity measures //! - **Temporal Features**: Time-of-day, volume clocks, event sequences //! - **Cross-Asset Signals**: Correlation and cointegration features //! //! ## Performance Optimizations //! //! - Pre-allocated feature vectors for zero-allocation extraction //! - SIMD-optimized mathematical operations //! - Incremental updates for streaming data //! - <20μs feature extraction from raw market data use common::types::{Price, Quantity, Symbol}; use std::collections::VecDeque; use candle_core::{Device, Result as CandleResult, Tensor}; use chrono::{DateTime, Datelike, Timelike, Utc}; use serde::{Deserialize, Serialize}; use super::*; // use crate::safe_operations; // DISABLED - module not found #[test] fn test_feature_config_default() { let config = FeatureConfig::default(); assert_eq!(config.lookback_window, 100); assert_eq!(config.book_levels, 5); assert!(config.use_order_book_features); assert!(config.use_trade_flow_features); } #[test] fn test_market_microstructure_from_tick() { let tick = MarketTick::new( Symbol::new("EURUSD")?, Price::from_f64(1.1000).unwrap(), // bid_price Price::from_f64(1.1002).unwrap(), // ask_price Price::from_f64(1.1001).unwrap(), // last_price Volume::new(1000.0), // volume Quantity::from(500), // bid_size Quantity::from(300), // ask_size 1234567890, // timestamp_us ); let micro = MarketMicrostructure::from_tick(&tick); assert_eq!(micro.bid_price, tick.bid_price); assert_eq!(micro.ask_price, tick.ask_price); assert!(micro.book_imbalance > 0.0); // More bid volume than ask } #[test] fn test_trade_flow_features() { let mut trades = Vec::new(); // Create sample trades for i in 0..10 { let mut micro = MarketMicrostructure { timestamp: 1234567890 + i as u64 * 1000, bid_price: Price::from_f64(1.1000).unwrap(), ask_price: Price::from_f64(1.1002).unwrap(), bid_volume: Volume::new(100.0), ask_volume: Volume::new(100.0), mid_price: Price::from_f64(1.1001).unwrap(), spread: Price::from_f64(0.0002).unwrap(), last_price: Some(Price::from_f64(1.1001).unwrap()), last_volume: Some(Volume::new(100 + i as u64 * 10)), trade_direction: if i % 2 == 0 { 1 } else { -1 }, book_imbalance: 0.0, vwap: None, trade_count: 1, }; trades.push(micro); } let features = TradeFlowFeatures::extract(&trades, 1.0); let vector = features.to_vector(); assert_eq!(vector.len(), 8); assert!(features.trade_intensity > 0.0); assert!(features.avg_trade_size > 0.0); } #[test] fn test_percentile_calculation() { let data = vec![1.0, 2.0, 3.0, 4.0, 5.0]; assert_eq!(percentile(&data, 0.0), 1.0); assert_eq!(percentile(&data, 0.5), 3.0); assert_eq!(percentile(&data, 1.0), 5.0); let empty_data = vec![]; assert_eq!(percentile(&empty_data, 0.5), 0.0); } #[tokio::test] async fn test_feature_extractor() { let config = FeatureConfig::default(); let device = Device::Cpu; let mut extractor = FinancialFeatureExtractor::new(config, device); let tick = MarketTick::new( Symbol::new("EURUSD")?, Price::from_f64(1.1000).unwrap(), // bid_price Price::from_f64(1.1002).unwrap(), // ask_price Price::from_f64(1.1001).unwrap(), // last_price Volume::new(1000.0), // volume Quantity::from(500), // bid_size Quantity::from(300), // ask_size 1234567890, // timestamp_us ); let features_tensor = extractor.extract_features(&tick)?; let shape = features_tensor.shape(); assert_eq!(shape.dims(), &[1, 32]); // Default output dimension assert!(extractor.average_extraction_time_us() > 0.0); } }