Move 17 library crates into crates/, CLI binary into bin/fxt, consolidate 10 test crates into testing/, split config crate from deployment config files. Root directory reduced from 38+ to ~17 directories. All Cargo.toml paths and build.rs proto refs updated. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
127 lines
4.1 KiB
Rust
127 lines
4.1 KiB
Rust
//! # 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_owned(),
|
||
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_owned(),
|
||
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_owned(),
|
||
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
|
||
}
|
||
} |