//! Risk Data Repository //! //! Production-ready risk management data layer for high-frequency trading systems. //! Provides repositories for VaR calculations, compliance logging, position limits, //! and risk data models with PostgreSQL and Redis integration. use std::sync::Arc; pub mod compliance; pub mod limits; pub mod models; pub mod var; // Re-export key types and traits pub use compliance::{ComplianceRepository, ComplianceRepositoryImpl}; pub use limits::{LimitsRepository, LimitsRepositoryImpl}; pub use models::*; pub use var::{VarRepository, VarRepositoryImpl}; /// Configuration for the risk data repository #[derive(Debug, Clone)] pub struct RiskDataConfig { /// PostgreSQL database URL pub database_url: String, /// Redis connection URL pub redis_url: String, /// Maximum database connections pub max_connections: u32, /// Connection timeout in seconds pub connection_timeout_secs: u64, } impl Default for RiskDataConfig { fn default() -> Self { Self { database_url: "postgresql://localhost/foxhunt".to_string(), redis_url: "redis://localhost:6379".to_string(), max_connections: 10, connection_timeout_secs: 30, } } } /// Main risk data repository facade providing access to all risk data operations #[derive(Debug, Clone)] pub struct RiskDataRepository { var_repo: Arc, compliance_repo: Arc, limits_repo: Arc, } impl RiskDataRepository { /// Create a new risk data repository with the given configuration pub async fn new(config: RiskDataConfig) -> Result { let pool = sqlx::postgres::PgPoolOptions::new() .max_connections(config.max_connections) .acquire_timeout(std::time::Duration::from_secs( config.connection_timeout_secs, )) .connect(&config.database_url) .await?; let redis_client = redis::Client::open(config.redis_url)?; let redis_conn = redis::aio::ConnectionManager::new(redis_client).await?; let var_repo = Arc::new(VarRepositoryImpl::new(pool.clone(), redis_conn.clone())); let compliance_repo = Arc::new(ComplianceRepositoryImpl::new( pool.clone(), redis_conn.clone(), )); let limits_repo = Arc::new(LimitsRepositoryImpl::new(pool.clone(), redis_conn.clone())); Ok(Self { var_repo, compliance_repo, limits_repo, }) } /// Get VaR repository pub fn var(&self) -> Arc { self.var_repo.clone() } /// Get compliance repository pub fn compliance(&self) -> Arc { self.compliance_repo.clone() } /// Get limits repository pub fn limits(&self) -> Arc { self.limits_repo.clone() } } /// Common error types for risk data operations #[derive(Debug, thiserror::Error)] pub enum RiskDataError { #[error("Database error: {0}")] Database(#[from] sqlx::Error), #[error("Redis error: {0}")] Redis(#[from] redis::RedisError), #[error("Serialization error: {0}")] Serialization(#[from] serde_json::Error), #[error("VaR calculation error: {0}")] VarCalculation(String), #[error("Compliance validation error: {0}")] ComplianceValidation(String), #[error("Position limits validation error: {0}")] LimitsValidation(String), #[error("Configuration error: {0}")] Configuration(String), #[error("Invalid data: {0}")] InvalidData(String), } /// Result type for risk data operations pub type RiskDataResult = Result; #[cfg(test)] mod tests { use super::*; #[test] fn test_risk_data_config_default() { let config = RiskDataConfig::default(); assert_eq!(config.database_url, "postgresql://localhost/foxhunt"); assert_eq!(config.redis_url, "redis://localhost:6379"); assert_eq!(config.max_connections, 10); assert_eq!(config.connection_timeout_secs, 30); } #[test] fn test_risk_data_error_display() { let error = RiskDataError::VarCalculation("Test error".to_string()); assert_eq!(error.to_string(), "VaR calculation error: Test error"); } }