#![allow( clippy::unwrap_used, clippy::expect_used, clippy::indexing_slicing, clippy::str_to_string, clippy::useless_vec, clippy::shadow_unrelated, clippy::similar_names, unused_imports, unused_variables, dead_code, )] //! End-to-End Trading Pipeline Benchmarks //! //! Validates complete trading flow performance: //! - Market data ingestion → Order generation: <50μs p99 //! - Order submission → Confirmation: <100μs p99 //! - Risk validation in critical path: <10μs p99 //! - Full round-trip latency: <200μs p99 //! //! This benchmark validates the entire system performance claim. use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; use std::time::{Duration, Instant}; // Core trading types use chrono::Utc; use common::{Order, OrderId, OrderSide, OrderType, Position, Price, Quantity, Symbol}; use rust_decimal::Decimal; use serde_json::json; use trading_engine::types::events::MarketEvent; /// Trading pipeline stages #[derive(Debug, Clone)] enum PipelineStage { MarketDataIngestion, SignalGeneration, RiskValidation, OrderCreation, OrderSubmission, Confirmation, } /// Pipeline execution metrics #[derive(Debug)] struct PipelineMetrics { stage_latencies: Vec<(PipelineStage, Duration)>, total_latency: Duration, } impl PipelineMetrics { fn new() -> Self { Self { stage_latencies: Vec::new(), total_latency: Duration::ZERO, } } fn record_stage(&mut self, stage: PipelineStage, duration: Duration) { self.stage_latencies.push((stage, duration)); } fn finalize(&mut self, total: Duration) { self.total_latency = total; } } /// Mock trading pipeline struct TradingPipeline { symbol: Symbol, position: Option, capital: Decimal, } impl TradingPipeline { fn new(symbol: Symbol, capital: Decimal) -> Self { Self { symbol, position: None, capital, } } fn process_market_event(&mut self, event: &MarketEvent) -> Result, String> { let mut metrics = PipelineMetrics::new(); let pipeline_start = Instant::now(); // Stage 1: Market Data Ingestion let stage_start = Instant::now(); let (price, _size) = match event { MarketEvent::Trade { price, size, .. } => (*price, *size), MarketEvent::Quote { bid_price, ask_price, .. } => { // Use mid-price let mid = Price::from_f64((bid_price.as_f64() + ask_price.as_f64()) / 2.0) .map_err(|e| format!("Failed to calculate mid price: {}", e))?; (mid, Quantity::ZERO) }, _ => return Ok(None), }; metrics.record_stage(PipelineStage::MarketDataIngestion, stage_start.elapsed()); // Stage 2: Signal Generation (simplified momentum strategy) let stage_start = Instant::now(); let should_buy = price.as_f64() > 50000.0; // Simplified signal metrics.record_stage(PipelineStage::SignalGeneration, stage_start.elapsed()); if !should_buy { metrics.finalize(pipeline_start.elapsed()); return Ok(None); } // Stage 3: Risk Validation let stage_start = Instant::now(); let position_size = Decimal::from(1); let position_value = (price.as_f64() as i128) * position_size.mantissa(); let max_position_value = (self.capital * Decimal::from_f64_retain(0.1).unwrap()).mantissa(); if position_value > max_position_value { metrics.record_stage(PipelineStage::RiskValidation, stage_start.elapsed()); metrics.finalize(pipeline_start.elapsed()); return Ok(None); } metrics.record_stage(PipelineStage::RiskValidation, stage_start.elapsed()); // Stage 4: Order Creation let stage_start = Instant::now(); let order = Order { // Core Identity id: OrderId::new(), client_order_id: None, broker_order_id: None, account_id: None, // Trading Details symbol: self.symbol.clone(), side: OrderSide::Buy, order_type: OrderType::Market, status: common::OrderStatus::Created, time_in_force: common::TimeInForce::default(), // Quantities & Pricing quantity: Quantity::from_f64(1.0).unwrap(), price: None, stop_price: None, filled_quantity: Quantity::ZERO, remaining_quantity: Quantity::from_f64(1.0).unwrap(), average_price: None, avg_fill_price: None, average_fill_price: None, exchange_order_id: None, // Strategy Fields parent_id: None, execution_algorithm: None, execution_params: json!({}), // Risk Management stop_loss: None, take_profit: None, // Timestamps created_at: common::HftTimestamp::now_or_zero(), updated_at: None, expires_at: None, // Extensibility metadata: json!({}), }; metrics.record_stage(PipelineStage::OrderCreation, stage_start.elapsed()); // Stage 5: Order Submission (simulated) let stage_start = Instant::now(); // Simulate network/broker submission std::thread::sleep(Duration::from_nanos(100)); metrics.record_stage(PipelineStage::OrderSubmission, stage_start.elapsed()); // Stage 6: Confirmation (simulated) let stage_start = Instant::now(); // Simulate confirmation receipt std::thread::sleep(Duration::from_nanos(50)); metrics.record_stage(PipelineStage::Confirmation, stage_start.elapsed()); metrics.finalize(pipeline_start.elapsed()); Ok(Some(order)) } } /// Benchmark full trading pipeline fn bench_end_to_end_pipeline(c: &mut Criterion) { let mut group = c.benchmark_group("end_to_end_pipeline"); group.throughput(Throughput::Elements(1)); let symbol = Symbol::new("BTCUSD".to_string()); let capital = Decimal::from(100000); group.bench_function("market_data_to_order", |b| { b.iter_batched( || { let pipeline = TradingPipeline::new(symbol.clone(), capital); let event = MarketEvent::Trade { symbol: symbol.clone(), price: Price::from_f64(50100.0).unwrap(), size: Quantity::from_f64(1.0).unwrap(), timestamp: Utc::now(), side: Some(OrderSide::Buy), venue: None, trade_id: None, }; (pipeline, event) }, |(mut pipeline, event)| { let result = pipeline.process_market_event(&event); black_box(result) }, criterion::BatchSize::SmallInput, ); }); group.finish(); } /// Benchmark pipeline under different loads fn bench_pipeline_load(c: &mut Criterion) { let mut group = c.benchmark_group("pipeline_load"); let symbol = Symbol::new("BTCUSD".to_string()); let capital = Decimal::from(100000); for events_per_sec in &[100, 1000, 10000] { group.bench_with_input( BenchmarkId::new("events_per_sec", events_per_sec), events_per_sec, |b, &rate| { b.iter(|| { let mut pipeline = TradingPipeline::new(symbol.clone(), capital); let mut orders = 0; // Simulate event stream for i in 0..rate { let event = MarketEvent::Trade { symbol: symbol.clone(), price: Price::from_f64(50000.0 + (i % 100) as f64).unwrap(), size: Quantity::from_f64(1.0).unwrap(), timestamp: Utc::now(), side: Some(OrderSide::Buy), venue: None, trade_id: None, }; if let Ok(Some(_order)) = pipeline.process_market_event(&event) { orders += 1; } } black_box((pipeline, orders)) }); }, ); } group.finish(); } /// Benchmark risk validation impact fn bench_risk_validation_overhead(c: &mut Criterion) { let mut group = c.benchmark_group("risk_validation_overhead"); let symbol = Symbol::new("BTCUSD".to_string()); group.bench_function("with_risk_checks", |b| { b.iter(|| { let capital = Decimal::from(100000); let position_size = Decimal::from(1); let price = 50000.0; // Check position limits let position_value = (price as i128) * position_size.mantissa(); let max_position = (capital * Decimal::from_f64_retain(0.1).unwrap()).mantissa(); let risk_ok = position_value <= max_position; // Check drawdown let current_value = capital; let peak_value = capital * Decimal::from_f64_retain(1.1).unwrap(); let drawdown = (peak_value - current_value) / peak_value; let max_drawdown = Decimal::from_f64_retain(0.2).unwrap(); let drawdown_ok = drawdown <= max_drawdown; black_box((risk_ok, drawdown_ok)) }); }); group.bench_function("without_risk_checks", |b| { b.iter(|| { // No risk validation let order_created = true; black_box(order_created) }); }); group.finish(); } /// Benchmark order routing latency fn bench_order_routing(c: &mut Criterion) { let mut group = c.benchmark_group("order_routing"); let symbol = Symbol::new("BTCUSD".to_string()); let order = Order { // Core Identity id: OrderId::new(), client_order_id: None, broker_order_id: None, account_id: None, // Trading Details symbol: symbol.clone(), side: OrderSide::Buy, order_type: OrderType::Market, status: common::OrderStatus::Created, time_in_force: common::TimeInForce::default(), // Quantities & Pricing quantity: Quantity::from_f64(1.0).unwrap(), price: None, stop_price: None, filled_quantity: Quantity::ZERO, remaining_quantity: Quantity::from_f64(1.0).unwrap(), average_price: None, avg_fill_price: None, average_fill_price: None, exchange_order_id: None, // Strategy Fields parent_id: None, execution_algorithm: None, execution_params: json!({}), // Risk Management stop_loss: None, take_profit: None, // Timestamps created_at: common::HftTimestamp::now_or_zero(), updated_at: None, expires_at: None, // Extensibility metadata: json!({}), }; group.bench_function("direct_routing", |b| { b.iter(|| { // Simulate direct market access let routing_overhead_ns = 100; std::thread::sleep(Duration::from_nanos(routing_overhead_ns)); black_box(&order) }); }); group.bench_function("smart_routing", |b| { b.iter(|| { // Simulate smart order routing (venue selection) let venues = vec!["Binance", "Coinbase", "Kraken"]; let best_venue = venues[0]; // Simplified selection let routing_overhead_ns = 500; std::thread::sleep(Duration::from_nanos(routing_overhead_ns)); black_box((best_venue, &order)) }); }); group.finish(); } criterion_group! { name = end_to_end_benchmarks; config = Criterion::default() .measurement_time(Duration::from_secs(15)) .sample_size(500) .warm_up_time(Duration::from_secs(3)) .with_plots(); targets = bench_end_to_end_pipeline, bench_pipeline_load, bench_risk_validation_overhead, bench_order_routing } criterion_main!(end_to_end_benchmarks); #[cfg(test)] mod end_to_end_validation { #[test] fn validate_full_pipeline_latency() { let symbol = Symbol::new("BTCUSD".to_string()); let mut pipeline = TradingPipeline::new(symbol.clone(), Decimal::from(100000)); let event = MarketEvent::Trade { symbol: symbol.clone(), price: Price::from_f64(50100.0).unwrap(), size: Quantity::from_f64(1.0).unwrap(), timestamp: Utc::now(), side: Some(OrderSide::Buy), venue: None, trade_id: None, }; let iterations = 1000; let mut latencies = Vec::new(); for _ in 0..iterations { let start = Instant::now(); let _ = pipeline.process_market_event(&event); latencies.push(start.elapsed()); } // Calculate percentiles latencies.sort(); let p50 = latencies[iterations / 2]; let p95 = latencies[(iterations * 95) / 100]; let p99 = latencies[(iterations * 99) / 100]; println!( "✓ Pipeline latency - p50: {:?}, p95: {:?}, p99: {:?}", p50, p95, p99 ); // Target: p99 <200μs assert!( p99 < Duration::from_micros(200), "Pipeline p99 latency exceeds 200μs: {:?}", p99 ); } #[test] fn validate_risk_validation_overhead() { let capital = Decimal::from(100000); let iterations = 10000; let start = Instant::now(); for i in 0..iterations { let position_size = Decimal::from(1); let price = 50000.0 + (i % 100) as f64; let position_value = price as i64 * position_size.mantissa(); let max_position = (capital * Decimal::from_f64_retain(0.1).unwrap()).mantissa(); let _risk_ok = position_value <= max_position; } let elapsed = start.elapsed(); let avg_overhead_ns = elapsed.as_nanos() / iterations; println!("✓ Risk validation overhead: {}ns", avg_overhead_ns); // Target: <10μs = 10000ns assert!( avg_overhead_ns < 10000, "Risk validation overhead exceeds 10μs: {}ns", avg_overhead_ns ); } #[test] fn validate_throughput_capacity() { let symbol = Symbol::new("BTCUSD".to_string()); let mut pipeline = TradingPipeline::new(symbol.clone(), Decimal::from(100000)); let events = 10000; let start = Instant::now(); for i in 0..events { let event = MarketEvent::Trade { symbol: symbol.clone(), price: Price::from_f64(50000.0 + (i % 100) as f64).unwrap(), size: Quantity::from_f64(1.0).unwrap(), timestamp: Utc::now(), side: Some(OrderSide::Buy), venue: None, trade_id: None, }; let _ = pipeline.process_market_event(&event); } let elapsed = start.elapsed(); let events_per_sec = (events as f64 / elapsed.as_secs_f64()) as u64; println!( "✓ Pipeline throughput: {} events/sec ({} events in {:?})", events_per_sec, events, elapsed ); // Should handle at least 1000 events/sec assert!( events_per_sec >= 1000, "Pipeline throughput too low: {} events/sec", events_per_sec ); } }