//! Risk Engine Position Validation Latency Benchmarks //! //! Measures risk calculation and validation latencies: //! - Position risk check: <20μs target //! - VaR calculation: <50μs target //! - Portfolio Greeks: <30μs target //! - Compliance checks: <10μs target //! //! Uses HDR histograms for statistical accuracy #![allow( dead_code, unused_crate_dependencies, clippy::doc_markdown, clippy::integer_division, clippy::non_ascii_literal, clippy::str_to_string, clippy::unnecessary_cast, clippy::unseparated_literal_suffix, clippy::unwrap_used )] use criterion::{black_box, criterion_group, criterion_main, Criterion}; use hdrhistogram::Histogram; use rust_decimal::Decimal; use std::collections::HashMap; use std::time::{Duration, Instant}; /// Latency metrics with HDR histogram struct LatencyMetrics { histogram: Histogram, samples: Vec, } impl LatencyMetrics { fn new() -> Self { Self { histogram: Histogram::::new(5).unwrap(), samples: Vec::new(), } } fn record_nanos(&mut self, nanos: u64) { self.histogram.record(nanos / 1000).ok(); // μs self.samples.push(nanos); } fn report(&self, label: &str, target_us: f64) { let p50 = self.histogram.value_at_percentile(50.0) as f64; let p95 = self.histogram.value_at_percentile(95.0) as f64; let p99 = self.histogram.value_at_percentile(99.0) as f64; let p999 = self.histogram.value_at_percentile(99.9) as f64; println!("\n=== {} ===", label); println!("P50: {:.3}μs", p50); println!("P95: {:.3}μs", p95); println!("P99: {:.3}μs", p99); println!("P999: {:.3}μs", p999); if p99 < target_us { println!("✅ TARGET MET: P99 {:.3}μs < {:.1}μs", p99, target_us); } else { println!("❌ TARGET MISSED: P99 {:.3}μs >= {:.1}μs", p99, target_us); } } } /// Position data struct Position { symbol: String, quantity: Decimal, entry_price: Decimal, current_price: Decimal, } /// Risk limits struct RiskLimits { max_position_size: Decimal, max_portfolio_value: Decimal, max_single_order: Decimal, max_leverage: Decimal, } /// Risk calculator struct RiskEngine { limits: RiskLimits, positions: HashMap, } impl RiskEngine { fn new() -> Self { let mut positions = HashMap::new(); // Pre-populate with test positions positions.insert( "BTC-USD".to_string(), Position { symbol: "BTC-USD".to_string(), quantity: Decimal::new(5, 0), entry_price: Decimal::new(64000, 0), current_price: Decimal::new(65000, 0), }, ); positions.insert( "ETH-USD".to_string(), Position { symbol: "ETH-USD".to_string(), quantity: Decimal::new(50, 0), entry_price: Decimal::new(3200, 0), current_price: Decimal::new(3300, 0), }, ); Self { limits: RiskLimits { max_position_size: Decimal::new(100, 0), max_portfolio_value: Decimal::new(10000000, 0), max_single_order: Decimal::new(50, 0), max_leverage: Decimal::new(3, 0), }, positions, } } fn check_position_limit(&self, symbol: &str, new_quantity: Decimal) -> bool { let current = self .positions .get(symbol) .map(|p| p.quantity) .unwrap_or(Decimal::ZERO); (current + new_quantity).abs() <= self.limits.max_position_size } fn calculate_var(&self, confidence: Decimal) -> Decimal { let mut total_risk = Decimal::ZERO; for position in self.positions.values() { let notional = position.quantity * position.current_price; let risk = notional * confidence / Decimal::new(100, 0); total_risk += risk.abs(); } total_risk } fn calculate_portfolio_value(&self) -> Decimal { self.positions .values() .map(|p| p.quantity * p.current_price) .sum() } fn check_leverage(&self, new_position_value: Decimal) -> bool { let current_value = self.calculate_portfolio_value(); let total_exposure = current_value + new_position_value; // Simplified leverage check (would use equity in production) total_exposure <= current_value * self.limits.max_leverage } } // // ==================== BENCHMARK 1: Position Risk Check (<20μs) ==================== // fn bench_position_risk_check(c: &mut Criterion) { let engine = RiskEngine::new(); c.bench_function("position_risk_check", |b| { b.iter_custom(|iters| { let mut metrics = LatencyMetrics::new(); for i in 0..iters { let symbol = if i % 2 == 0 { "BTC-USD" } else { "ETH-USD" }; let quantity = Decimal::new((i % 10) as i64, 0); let start = Instant::now(); black_box(engine.check_position_limit(symbol, quantity)); metrics.record_nanos(start.elapsed().as_nanos() as u64); } metrics.report("Position Risk Check", 20.0); Duration::from_nanos((metrics.samples.iter().sum::() / iters.max(1)) as u64) }); }); } // // ==================== BENCHMARK 2: VaR Calculation (<50μs) ==================== // fn bench_var_calculation(c: &mut Criterion) { let engine = RiskEngine::new(); c.bench_function("var_calculation", |b| { b.iter_custom(|iters| { let mut metrics = LatencyMetrics::new(); for i in 0..iters { let confidence = Decimal::new(95 + (i % 5) as i64, 0); let start = Instant::now(); black_box(engine.calculate_var(confidence)); metrics.record_nanos(start.elapsed().as_nanos() as u64); } metrics.report("VaR Calculation", 50.0); Duration::from_nanos((metrics.samples.iter().sum::() / iters.max(1)) as u64) }); }); } // // ==================== BENCHMARK 3: Portfolio Value Calculation (<30μs) ==================== // fn bench_portfolio_value(c: &mut Criterion) { let engine = RiskEngine::new(); c.bench_function("portfolio_value_calculation", |b| { b.iter_custom(|iters| { let mut metrics = LatencyMetrics::new(); for _ in 0..iters { let start = Instant::now(); black_box(engine.calculate_portfolio_value()); metrics.record_nanos(start.elapsed().as_nanos() as u64); } metrics.report("Portfolio Value Calculation", 30.0); Duration::from_nanos((metrics.samples.iter().sum::() / iters.max(1)) as u64) }); }); } // // ==================== BENCHMARK 4: Leverage Check (<10μs) ==================== // fn bench_leverage_check(c: &mut Criterion) { let engine = RiskEngine::new(); c.bench_function("leverage_check", |b| { b.iter_custom(|iters| { let mut metrics = LatencyMetrics::new(); for i in 0..iters { let new_position_value = Decimal::new((100000 + i * 1000) as i64, 0); let start = Instant::now(); black_box(engine.check_leverage(new_position_value)); metrics.record_nanos(start.elapsed().as_nanos() as u64); } metrics.report("Leverage Check", 10.0); Duration::from_nanos((metrics.samples.iter().sum::() / iters.max(1)) as u64) }); }); } // // ==================== BENCHMARK 5: Full Risk Validation (<50μs) ==================== // fn bench_full_risk_validation(c: &mut Criterion) { let engine = RiskEngine::new(); c.bench_function("full_risk_validation", |b| { b.iter_custom(|iters| { let mut metrics = LatencyMetrics::new(); for i in 0..iters { let symbol = if i % 2 == 0 { "BTC-USD" } else { "ETH-USD" }; let quantity = Decimal::new((i % 10) as i64, 0); let price = Decimal::new(65000, 0); let start = Instant::now(); // Step 1: Position limit check let position_ok = engine.check_position_limit(symbol, quantity); // Step 2: Leverage check let new_value = quantity * price; let leverage_ok = engine.check_leverage(new_value); // Step 3: VaR calculation let var = engine.calculate_var(Decimal::new(95, 0)); black_box((position_ok, leverage_ok, var)); metrics.record_nanos(start.elapsed().as_nanos() as u64); } metrics.report("Full Risk Validation", 50.0); Duration::from_nanos((metrics.samples.iter().sum::() / iters.max(1)) as u64) }); }); } // // ==================== BENCHMARK 6: Multi-Position Risk Aggregation ==================== // fn bench_multi_position_risk(c: &mut Criterion) { c.bench_function("multi_position_risk_aggregation", |b| { b.iter_custom(|iters| { let mut metrics = LatencyMetrics::new(); for _ in 0..iters { // Create engine with multiple positions let mut engine = RiskEngine::new(); // Add more positions for j in 0..5 { engine.positions.insert( format!("SYMBOL-{}", j), Position { symbol: format!("SYMBOL-{}", j), quantity: Decimal::new(10 + j as i64, 0), entry_price: Decimal::new(1000, 0), current_price: Decimal::new(1050, 0), }, ); } let start = Instant::now(); // Calculate aggregate risk across all positions let portfolio_value = engine.calculate_portfolio_value(); let var_95 = engine.calculate_var(Decimal::new(95, 0)); let var_99 = engine.calculate_var(Decimal::new(99, 0)); black_box((portfolio_value, var_95, var_99)); metrics.record_nanos(start.elapsed().as_nanos() as u64); } metrics.report("Multi-Position Risk Aggregation", 100.0); Duration::from_nanos((metrics.samples.iter().sum::() / iters.max(1)) as u64) }); }); } criterion_group!( risk_benches, bench_position_risk_check, bench_var_calculation, bench_portfolio_value, bench_leverage_check, bench_full_risk_validation, bench_multi_position_risk, ); criterion_main!(risk_benches);