//! Risk Management Module //! //! This module provides comprehensive risk management functionality for HFT trading systems. //! It includes Value at Risk (`VaR`) calculations, position tracking, stress testing, circuit breakers, //! safety systems, and compliance monitoring. //! //! # Features //! //! - **`VaR` Calculation Engine**: Multiple methodologies (Historical Simulation, Monte Carlo, Parametric, Expected Shortfall) //! - **Real-time Position Tracking**: Concentration risk monitoring with HHI calculations //! - **Safety Systems**: Atomic kill switches, emergency response, position limiters //! - **Circuit Breakers**: Dynamic portfolio protection with Redis coordination //! - **Stress Testing**: Scenario analysis with Monte Carlo simulations //! - **Compliance Monitoring**: Regulatory position limits and risk validation //! - **Risk Engine**: Real-time risk validation and monitoring //! //! # Quick Start //! //! ```rust,no_run //! use risk::prelude::*; //! //! #[tokio::main] //! async fn main() -> Result<(), RiskError> { //! // Initialize risk engine //! let config = RiskConfig::default(); //! let mut risk_engine = RiskEngine::new(config).await?; //! //! // Create a position tracker //! let position_tracker = PositionTracker::new(); //! //! // Initialize VaR calculator //! let var_engine = RealVaREngine::new(); //! //! // Perform risk check on an order //! let order_info = OrderInfo { //! symbol: Symbol::from("AAPL"), //! side: OrderSide::Buy, //! quantity: Quantity::new(100.0)?, //! price: Price::new(150.0)?, //! }; //! //! let risk_result = risk_engine.validate_order(&order_info).await?; //! println!("Risk check result: {:?}", risk_result); //! //! Ok(()) //! } //! ``` //! //! # Architecture //! //! The risk module is structured around several core components: //! //! ## Core Components //! //! - **Risk Engine**: Central coordinator for all risk calculations and validations //! - **Position Tracker**: Real-time position monitoring with concentration limits //! - **`VaR` Calculator**: Multiple methodologies for portfolio risk assessment //! - **Safety Systems**: Emergency controls and automated risk responses //! - **Circuit Breakers**: Dynamic protection against market anomalies //! - **Stress Tester**: Scenario analysis and portfolio stress testing //! - **Compliance Monitor**: Regulatory compliance and position validation //! //! ## Safety Architecture //! //! The safety systems provide multiple layers of protection: //! //! 1. **Position Limits**: Hard limits on position sizes and concentrations //! 2. **Kill Switches**: Atomic emergency stops with Redis broadcasting //! 3. **Circuit Breakers**: Dynamic portfolio-based protection //! 4. **Emergency Response**: Automated incident response and escalation //! 5. **Compliance Checks**: Regulatory position limits and validation //! //! # Configuration //! //! The risk module can be configured via environment variables or configuration files: //! //! ```rust //! use risk::RiskConfig; //! //! let config = RiskConfig { //! max_position_size: Price::new(1_000_000.0).unwrap(), //! max_daily_loss: Price::new(100_000.0).unwrap(), //! var_confidence_level: 0.95, //! var_lookback_days: 252, //! enable_kill_switch: true, //! enable_circuit_breakers: true, //! redis_url: "redis://localhost:6379".to_string(), //! }; //! ``` #![warn(missing_docs)] #![warn(clippy::all)] #![warn(clippy::pedantic)] #![warn(clippy::cargo)] #![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic)] // Core modules pub mod error; // pub mod risk_types; // DELETED - duplicate types eliminated pub mod operations; // Risk calculation engines pub mod kelly_sizing; pub mod position_tracker; pub mod risk_engine; pub mod stress_tester; pub mod var_calculator; // Risk type definitions pub mod risk_types; // Safety and protection systems pub mod circuit_breaker; pub mod compliance; pub mod drawdown_monitor; pub mod safety; // ELIMINATED: Prelude module removed to force explicit imports /// Library version pub const VERSION: &str = env!("CARGO_PKG_VERSION"); /// Library name pub const NAME: &str = env!("CARGO_PKG_NAME"); /// Get risk module information #[must_use] pub fn info() -> RiskModuleInfo { RiskModuleInfo { name: NAME.to_owned(), version: VERSION.to_owned(), description: "Enterprise Risk Management for HFT Trading Systems".to_owned(), features: vec![ "Value at Risk Calculations (Multiple Methodologies)".to_owned(), "Real-time Position Tracking".to_owned(), "Concentration Risk Monitoring".to_owned(), "Atomic Kill Switch Systems".to_owned(), "Dynamic Circuit Breakers".to_owned(), "Stress Testing and Scenario Analysis".to_owned(), "Compliance Monitoring".to_owned(), "Emergency Response Systems".to_owned(), "Kelly Criterion Position Sizing".to_owned(), "Drawdown Protection".to_owned(), ], methodologies: vec![ "Historical Simulation VaR".to_owned(), "Monte Carlo VaR".to_owned(), "Parametric VaR".to_owned(), "Expected Shortfall (CVaR)".to_owned(), ], } } /// Risk module information structure #[derive(Debug, Clone)] pub struct RiskModuleInfo { /// Module name pub name: String, /// Version string pub version: String, /// Description pub description: String, /// Feature list pub features: Vec, /// Risk methodologies supported pub methodologies: Vec, } impl std::fmt::Display for RiskModuleInfo { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { writeln!(f, "{} v{}", self.name, self.version)?; writeln!(f, "{}", self.description)?; writeln!(f, "\nFeatures:")?; for feature in &self.features { writeln!(f, " \u{2022} {}", feature)?; } writeln!(f, "\nRisk Methodologies:")?; for methodology in &self.methodologies { writeln!(f, " \u{2022} {}", methodology)?; } Ok(()) } } /// Initialize the risk module with logging pub fn init() -> Result<(), Box> { // Initialize tracing subscriber if not already initialized if std::env::var("RUST_LOG").is_err() { std::env::set_var("RUST_LOG", "info"); } tracing_subscriber::fmt::try_init().map_err(|_| "Failed to initialize logging")?; tracing::info!("Initialized Risk Management Module {} v{}", NAME, VERSION); Ok(()) } /// Validate risk configuration pub fn validate_risk_config(config: &SafetyConfig) -> Result<(), String> { // Validate basic configuration if !config.enabled { tracing::warn!("Risk management is disabled - this should only be used in testing"); } // Validate kill switch configuration if config.kill_switch.enabled { if config.kill_switch.global_channel.is_empty() { return Err("Kill switch global channel cannot be empty".to_owned()); } if config.kill_switch.strategy_channel_prefix.is_empty() { return Err("Kill switch strategy channel prefix cannot be empty".to_owned()); } } // Validate position limits if config.position_limits.enabled { if config.position_limits.max_position_per_symbol <= 0.0 { return Err("Maximum position per symbol must be positive".to_owned()); } if config.position_limits.max_order_value <= 0.0 { return Err("Maximum order value must be positive".to_owned()); } if config.position_limits.max_daily_loss <= 0.0 { return Err("Maximum daily loss must be positive".to_owned()); } } // Validate Redis URL if config.redis_url.is_empty() { return Err("Redis URL cannot be empty".to_owned()); } // Validate emergency response if config.emergency_response.enabled { if config.emergency_response.emergency_contacts.is_empty() { tracing::warn!("No emergency contacts configured for incident response"); } if config.emergency_response.max_consecutive_violations == 0 { return Err("Max consecutive violations must be greater than 0".to_owned()); } } Ok(()) } use common::Price; /// Get default configuration for development/testing #[must_use] pub fn development_config() -> SafetyConfig { SafetyConfig { enabled: true, kill_switch: KillSwitchConfig { enabled: true, global_channel: "foxhunt:dev:kill_switch:global".to_owned(), strategy_channel_prefix: "foxhunt:dev:kill_switch:strategy".to_owned(), symbol_channel_prefix: "foxhunt:dev:kill_switch:symbol".to_owned(), auto_recovery_enabled: true, auto_recovery_delay: std::time::Duration::from_secs(60), // 1 minute in dev }, position_limits: PositionLimiterConfig { enabled: true, cache_ttl: std::time::Duration::from_secs(30), rpc_check_threshold_percent: 0.5, // Lower threshold for development max_position_per_symbol: 10_000.0, // $10K max per symbol in dev max_order_value: 5_000.0, // $5K max per order in dev max_daily_loss: 1_000.0, // $1K daily loss limit in dev }, emergency_response: EmergencyResponseConfig { enabled: true, loss_check_interval: std::time::Duration::from_secs(30), position_check_interval: std::time::Duration::from_secs(15), max_consecutive_violations: 3, emergency_contacts: vec!["dev@foxhunt.com".to_owned()], max_daily_loss: Price::new(1000.0).unwrap_or(Price::ZERO), max_drawdown: Price::new(2000.0).unwrap_or(Price::ZERO), }, redis_url: "redis://localhost:6379".to_owned(), safety_check_timeout: std::time::Duration::from_millis(50), // Longer timeout for dev } } /// Get configuration for production deployment #[must_use] pub fn production_config() -> SafetyConfig { SafetyConfig { enabled: true, kill_switch: KillSwitchConfig { enabled: true, global_channel: "foxhunt:prod:kill_switch:global".to_owned(), strategy_channel_prefix: "foxhunt:prod:kill_switch:strategy".to_owned(), symbol_channel_prefix: "foxhunt:prod:kill_switch:symbol".to_owned(), auto_recovery_enabled: false, // Manual recovery in production auto_recovery_delay: std::time::Duration::from_secs(1800), // 30 minutes }, position_limits: PositionLimiterConfig { enabled: true, cache_ttl: std::time::Duration::from_secs(10), // Shorter cache in production rpc_check_threshold_percent: 0.9, // Higher threshold for production max_position_per_symbol: 100_000.0, // $100K max per symbol max_order_value: 50_000.0, // $50K max per order max_daily_loss: 10_000.0, // $10K daily loss limit }, emergency_response: EmergencyResponseConfig { enabled: true, loss_check_interval: std::time::Duration::from_secs(5), position_check_interval: std::time::Duration::from_secs(2), max_consecutive_violations: 5, emergency_contacts: vec![ "risk@foxhunt.com".to_owned(), "trading@foxhunt.com".to_owned(), "alerts@foxhunt.com".to_owned(), ], max_daily_loss: Price::new(10_000.0).unwrap_or(Price::ZERO), max_drawdown: Price::new(25_000.0).unwrap_or(Price::ZERO), }, redis_url: std::env::var("REDIS_URL") .unwrap_or_else(|_| "redis://redis-cluster:6379".to_owned()), safety_check_timeout: std::time::Duration::from_millis(5), // Very tight timeout in production } } #[cfg(test)] mod tests { use super::*; #[test] fn test_module_info() { let info = info(); assert_eq!(info.name, "risk"); assert!(!info.version.is_empty()); assert!(!info.description.is_empty()); assert!(!info.features.is_empty()); assert!(!info.methodologies.is_empty()); } #[test] fn test_development_config_validation() { let config = development_config(); assert!(validate_risk_config(&config).is_ok()); assert!(config.enabled); assert!(config.kill_switch.enabled); assert!(config.position_limits.enabled); assert!(config.emergency_response.enabled); } #[test] fn test_production_config_validation() { let config = production_config(); assert!(validate_risk_config(&config).is_ok()); assert!(config.enabled); assert!(!config.kill_switch.auto_recovery_enabled); // Manual recovery in prod assert!(config.position_limits.max_position_per_symbol > 0.0); assert!(!config.emergency_response.emergency_contacts.is_empty()); } #[test] fn test_invalid_config_validation() { let mut config = development_config(); // Test empty kill switch channel config.kill_switch.global_channel = String::new(); assert!(validate_risk_config(&config).is_err()); // Reset and test invalid position limits config = development_config(); config.position_limits.max_position_per_symbol = 0.0; assert!(validate_risk_config(&config).is_err()); // Reset and test empty Redis URL config = development_config(); config.redis_url = String::new(); assert!(validate_risk_config(&config).is_err()); } }