//! # Kyle's Lambda Estimator //! //! Implementation of Kyle's Lambda for measuring price impact and //! information asymmetry in financial markets. //! //! ## Algorithm //! //! Kyle's Lambda (λ) measures the price impact per unit of signed order flow: //! - Returns = λ × SignedOrderFlow + ε //! - λ is estimated via regression of returns on signed square-root dollar volume //! - Higher λ indicates greater price impact (lower liquidity) //! //! ## Performance //! //! - Target latency: <25μs per calculation //! - Rolling regression with fixed-point arithmetic //! - Efficient covariance calculation updates use std::collections::VecDeque; use std::sync::atomic::{AtomicI64, AtomicU64, Ordering}; use serde::{Deserialize, Serialize}; use super::*; use super::{ #[test] fn test_kyle_lambda_estimator_creation() { let estimator = KyleLambdaEstimator::default(); assert_eq!(estimator.get_lambda(), 0.0); assert_eq!(estimator.get_interval_count(), 0); assert_eq!(estimator.get_r_squared(), 0.0); } #[test] fn test_trading_interval() { let mut interval = TradingInterval::new(0, 1000000, 2000000); let update = MarketDataUpdate { timestamp: 1500000, symbol: "AAPL".to_string(), price: 150000, volume: 1000, bid: 149000, ask: 151000, bid_size: 100, ask_size: 100, direction: Some(TradeDirection::Buy), }; interval.add_trade(&update); assert_eq!(interval.trade_count, 1); assert_eq!(interval.open_price, 150000); assert_eq!(interval.close_price, 150000); assert!(interval.signed_sqrt_dollar_volume > 0); // Buy trade interval.finalize(); assert!(interval.is_valid()); } #[test] fn test_lambda_calculation() { let config = KyleLambdaConfig { interval_duration_ns: 1000000, // 1ms for testing min_trades_per_interval: 1, regression_window: 5, ..Default::default() }; let mut estimator = KyleLambdaEstimator::new(config); // Add trades with price impact pattern for i in 0..20 { let price_impact = if i % 2 == 0 { 100 } else { -100 }; let direction = if i % 2 == 0 { TradeDirection::Buy } else { TradeDirection::Sell }; let update = MarketDataUpdate { timestamp: (i * 2000000) as u64, // 2ms intervals symbol: "AAPL".to_string(), price: 150000 + price_impact, volume: 1000, bid: 149000, ask: 151000, bid_size: 100, ask_size: 100, direction: Some(direction), }; estimator.update(&update)?; } // Should have calculated lambda let result = estimator.get_result(); assert!(result.interval_count > 0); // Lambda should be non-zero if there's a price impact pattern // (exact value depends on the specific pattern) println!("Lambda: {}, R²: {}", result.lambda, result.r_squared); } #[test] fn test_information_asymmetry() { let mut estimator = KyleLambdaEstimator::default(); // Add persistent positive returns (trend) for i in 0..10 { let update = MarketDataUpdate { timestamp: (i * 300_000_000_000) as u64, // 5 min intervals symbol: "AAPL".to_string(), price: 150000 + (i * 100), // Trending up volume: 1000, bid: 149000, ask: 151000, bid_size: 100, ask_size: 100, direction: Some(TradeDirection::Buy), }; estimator.update(&update)?; } let info_asymmetry = estimator.get_information_asymmetry(); assert!(info_asymmetry >= 0.0); // Should detect some persistence } }