// Enable pedantic warnings FIRST so individual allows below override them #![warn(clippy::all)] #![warn(clippy::pedantic)] #![warn(clippy::cargo)] #![allow(clippy::multiple_crate_versions)] // Workspace-level dependency concern #![allow(clippy::cargo_common_metadata)] // Metadata managed at workspace level // Safety denials and test overrides #![deny(clippy::unwrap_used, clippy::expect_used)] #![cfg_attr(test, allow(clippy::unwrap_used, clippy::expect_used))] #![allow(unused_extern_crates)] #![allow(unused_crate_dependencies)] #![allow(missing_docs)] #![allow(missing_debug_implementations)] // Clippy pedantic lints that are acceptable in financial/risk code #![allow(clippy::default_numeric_fallback)] // Float literals are contextually typed in financial code #![allow(clippy::float_arithmetic)] // Financial calculations require floating-point arithmetic #![allow(clippy::arithmetic_side_effects)] // Risk calculations use saturating/checked arithmetic where needed #![allow(clippy::cast_precision_loss)] // Acceptable in statistical/risk calculations with proper validation #![allow(clippy::missing_errors_doc)] // Error documentation is in module-level docs #![allow(clippy::cast_possible_truncation)] // Type conversions validated in context #![allow(clippy::cast_sign_loss)] // Sign loss is validated in conversion functions #![allow(clippy::cast_possible_wrap)] // Wrap-around is validated in context #![allow(clippy::as_conversions)] // Type conversions are carefully managed in risk code #![allow(clippy::map_err_ignore)] // Error context preserved in error types #![allow(clippy::unused_async)] // Async needed for trait implementations and future expansion #![allow(clippy::module_name_repetitions)] // Module prefixes provide clarity in risk domain #![allow(clippy::similar_names)] // Financial variables often have similar names (var, cvar, etc.) #![allow(clippy::shadow_reuse)] // Variable shadowing is intentional for transformations #![allow(clippy::indexing_slicing)] // Bounds checked in context #![allow(clippy::wildcard_enum_match_arm)] // Exhaustive matching not required for all enums #![allow(clippy::cognitive_complexity)] // Risk calculations are inherently complex #![allow(clippy::too_many_lines)] // Complex risk functions need many lines #![allow(clippy::must_use_candidate)] // Not all functions need must_use #![allow(clippy::used_underscore_binding)] // Underscore bindings used for partial pattern matches #![allow(clippy::unused_self)] // Self parameter needed for trait consistency #![allow(clippy::unreadable_literal)] // Large numbers are clear in financial context #![allow(clippy::inline_always)] // Performance-critical code needs inlining hints #![allow(clippy::else_if_without_else)] // Exhaustive else not always needed #![allow(clippy::partial_pub_fields)] // Intentional mixed visibility for safety #![allow(clippy::unnecessary_safety_doc)] // Safety docs retained for clarity #![allow(clippy::let_underscore_must_use)] // Intentional discarding of must_use #![allow(clippy::redundant_clone)] // Clones needed for ownership #![allow(clippy::shadow_unrelated)] // Shadowing is intentional #![allow(clippy::empty_structs_with_brackets)] // Explicit struct syntax preferred #![allow(clippy::to_string_trait_impl)] // String conversion is intentional #![allow(clippy::infinite_loop)] // Infinite loops are intentional (servers, event loops) #![allow(clippy::multiple_inherent_impl)] // Multiple impl blocks for organization #![allow(clippy::unnecessary_safety_comment)] // Safety comments retained for code clarity #![allow(clippy::string_to_string)] // String cloning is intentional for ownership // Additional pedantic allows needed by this crate #![allow(clippy::missing_const_for_fn)] // const fn not needed for risk calculations #![allow(clippy::unnecessary_wraps)] #![allow(clippy::match_same_arms)] #![allow(clippy::manual_let_else)] #![allow(clippy::needless_pass_by_value)] #![allow(clippy::map_unwrap_or)] #![allow(clippy::doc_markdown)] #![allow(clippy::clone_on_ref_ptr)] #![allow(clippy::uninlined_format_args)] #![allow(clippy::unnecessary_literal_bound)] #![allow(clippy::single_match_else)] #![allow(clippy::should_implement_trait)] #![allow(clippy::derivable_impls)] #![allow(clippy::doc_lazy_continuation)] #![allow(clippy::cast_lossless)] #![allow(clippy::trivially_copy_pass_by_ref)] #![allow(clippy::same_item_push)] #![allow(clippy::no_effect_underscore_binding)] #![allow(clippy::iter_without_into_iter)] #![allow(clippy::assigning_clones)] #![allow(clippy::manual_clamp)] #![allow(clippy::if_same_then_else)] // Explicit arms for clarity #![allow(clippy::new_without_default)] #![allow(clippy::redundant_closure)] #![allow(clippy::io_other_error)] // Additional allows for risk-specific patterns #![allow(clippy::too_many_arguments)] // Risk functions need many parameters #![allow(clippy::struct_excessive_bools)] // Boolean flags for risk state #![allow(clippy::needless_range_loop)] // Index loops in Monte Carlo simulations #![allow(clippy::manual_flatten)] // Explicit iteration preferred #![allow(clippy::field_reassign_with_default)] // Default then override pattern #![allow(clippy::declare_interior_mutable_const)] // Intentional const patterns #![allow(clippy::inherent_to_string)] // Custom Display implementations #![allow(clippy::vec_init_then_push)] // Sequential construction preferred #![allow(clippy::type_complexity)] // Complex types needed for risk calculations #![allow(clippy::incompatible_msrv)] // MSRV not strictly enforced #![allow(clippy::negative_feature_names)] // Feature naming is intentional #![allow(clippy::redundant_feature_names)] // Feature naming conventions //! 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(), //! }; //! ``` // 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 portfolio_optimization; 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; // Risk enforcement and correlation monitoring pub mod enforcement; pub mod correlation_monitor; // RE-EXPORTS FOR TEST COMPATIBILITY // The following re-exports are required for test suite compilation // Tests import these types directly from the risk crate // Export key types from submodules for test compatibility pub use kelly_sizing::KellySizer; pub use risk_engine::RiskEngine; pub use safety::kill_switch::AtomicKillSwitch; pub use stress_tester::StressTester; pub use var_calculator::var_engine::RealVaREngine; // Export compliance types first pub use compliance::ComplianceValidator; // Type aliases for backward compatibility with tests pub use ComplianceValidator as ComplianceEngine; pub use RealVaREngine as VaRCalculator; // 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, } use std::fmt; impl fmt::Display for RiskModuleInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> 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 /// /// # Errors /// /// Returns error if: /// - Logging initialization fails /// - Environment variables are invalid 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 /// /// # Errors /// /// Returns error if: /// - Kill switch configuration is invalid (empty channels) /// - Position limits are non-positive /// - Maximum order value is zero or negative /// - Daily loss limit is invalid /// - Redis URL is empty /// - Emergency response configuration is invalid 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 crate::safety::{ EmergencyResponseConfig, KillSwitchConfig, PositionLimiterConfig, SafetyConfig, }; use common::types::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)] #[allow(clippy::assertions_on_result_states)] 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()); } }