//! Best Execution Compliance Tests //! //! Comprehensive tests for MiFID II Best Execution requirements including: //! - Execution quality metrics calculation //! - Venue selection and analysis //! - Transaction cost breakdown //! - Best execution policy compliance //! - RTS 28 reporting requirements use trading_engine::compliance::best_execution::{ BestExecutionAnalyzer, BestExecutionConfig, VenueType, ExecutionFactors, VenueSelectionCriteria, ReportingIntervals, }; use trading_engine::compliance::{OrderInfo, MiFIDConfig}; use common::{OrderId, OrderSide, OrderType, Price, Quantity}; use rust_decimal::Decimal; use chrono::Utc; /// Test best execution analyzer initialization #[tokio::test] async fn test_best_execution_analyzer_initialization() { let config = MiFIDConfig { best_execution_enabled: true, transaction_reporting_endpoint: Some("https://test.endpoint.com".to_string()), client_categorization_enabled: true, product_governance_enabled: true, position_limit_monitoring: true, }; let analyzer = BestExecutionAnalyzer::new(&config); // Verify analyzer is properly initialized (no panic) assert!(true, "Analyzer initialized successfully"); } /// Test execution quality metrics calculation #[tokio::test] async fn test_execution_quality_metrics() { let config = MiFIDConfig::default(); let analyzer = BestExecutionAnalyzer::new(&config); let order_info = OrderInfo { order_id: OrderId::new(), side: OrderSide::Buy, order_type: OrderType::Limit, quantity: Quantity::from_shares(1000), price: Some(Price::from_f64(100.50).expect("Valid price")), symbol: "AAPL".to_string(), client_id: "CLIENT001".to_string(), timestamp: Utc::now(), }; let result = analyzer.analyze_best_execution(&order_info).await; assert!(result.is_ok(), "Best execution analysis should succeed"); let analysis = result.unwrap(); assert_eq!(analysis.order_id, order_info.order_id); assert!(analysis.execution_score >= 0.0 && analysis.execution_score <= 1.0, "Execution score should be between 0 and 1"); // Verify quality metrics are populated let metrics = &analysis.quality_metrics; assert!(metrics.fill_rate >= 0.0 && metrics.fill_rate <= 1.0, "Fill rate should be a valid percentage"); assert!(metrics.avg_execution_time_ms > 0, "Execution time should be positive"); } /// Test venue selection and scoring #[tokio::test] async fn test_venue_selection() { let config = MiFIDConfig::default(); let analyzer = BestExecutionAnalyzer::new(&config); let order_info = OrderInfo { order_id: OrderId::new(), side: OrderSide::Buy, order_type: OrderType::Market, quantity: Quantity::from_shares(5000), price: None, // Market order symbol: "MSFT".to_string(), client_id: "CLIENT002".to_string(), timestamp: Utc::now(), }; let analysis = analyzer.analyze_best_execution(&order_info).await .expect("Analysis should succeed"); // Verify venue was selected assert!(!analysis.execution_venue.is_empty(), "Venue should be selected"); // Verify alternative venues were evaluated assert!(!analysis.alternative_venues.is_empty(), "Alternative venues should be evaluated"); // Verify venue scores are valid for venue in &analysis.alternative_venues { assert!(venue.venue_score >= 0.0 && venue.venue_score <= 1.0, "Venue score should be between 0 and 1"); assert!(venue.execution_probability >= 0.0 && venue.execution_probability <= 1.0, "Execution probability should be valid percentage"); } } /// Test transaction cost breakdown #[tokio::test] async fn test_transaction_cost_breakdown() { let config = MiFIDConfig::default(); let analyzer = BestExecutionAnalyzer::new(&config); let order_info = OrderInfo { order_id: OrderId::new(), side: OrderSide::Sell, order_type: OrderType::Limit, quantity: Quantity::from_shares(2000), price: Some(Price::from_f64(50.25).expect("Valid price")), symbol: "GOOGL".to_string(), client_id: "CLIENT003".to_string(), timestamp: Utc::now(), }; let analysis = analyzer.analyze_best_execution(&order_info).await .expect("Analysis should succeed"); let costs = &analysis.cost_analysis; // Verify explicit costs are calculated assert!(costs.explicit_costs.commission >= Decimal::ZERO, "Commission should be non-negative"); assert!(costs.explicit_costs.exchange_fees >= Decimal::ZERO, "Exchange fees should be non-negative"); assert!(costs.explicit_costs.clearing_fees >= Decimal::ZERO, "Clearing fees should be non-negative"); // Verify implicit costs are calculated assert!(costs.implicit_costs.spread_cost_bps >= 0.0, "Spread cost should be non-negative"); assert!(costs.implicit_costs.market_impact_bps >= 0.0, "Market impact should be non-negative"); // Verify total costs assert!(costs.total_costs_bps > 0.0, "Total costs should be positive"); } /// Test best execution compliance assessment #[tokio::test] async fn test_best_execution_compliance() { let config = MiFIDConfig::default(); let analyzer = BestExecutionAnalyzer::new(&config); let order_info = OrderInfo { order_id: OrderId::new(), side: OrderSide::Buy, order_type: OrderType::Limit, quantity: Quantity::from_shares(500), price: Some(Price::from_f64(150.00).expect("Valid price")), symbol: "TSLA".to_string(), client_id: "CLIENT004".to_string(), timestamp: Utc::now(), }; let analysis = analyzer.analyze_best_execution(&order_info).await .expect("Analysis should succeed"); // For well-configured system, should be compliant assert!(analysis.is_compliant || !analysis.findings.is_empty(), "Should either be compliant or have findings explaining non-compliance"); // Verify execution score exists and is used for compliance assert_eq!(analysis.execution_score, analysis.execution_quality_score, "Execution score and quality score should match"); } /// Test price improvement detection #[tokio::test] async fn test_price_improvement() { let config = MiFIDConfig::default(); let analyzer = BestExecutionAnalyzer::new(&config); let order_info = OrderInfo { order_id: OrderId::new(), side: OrderSide::Buy, order_type: OrderType::Limit, quantity: Quantity::from_shares(1000), price: Some(Price::from_f64(100.00).expect("Valid price")), symbol: "NVDA".to_string(), client_id: "CLIENT005".to_string(), timestamp: Utc::now(), }; let analysis = analyzer.analyze_best_execution(&order_info).await .expect("Analysis should succeed"); let metrics = &analysis.quality_metrics; // Price improvement can be positive (better than NBBO) or negative (worse) assert!(metrics.price_improvement_bps.is_finite(), "Price improvement should be a valid number"); // Verify spread metrics assert!(metrics.effective_spread_bps >= 0.0, "Effective spread should be non-negative"); assert!(metrics.realized_spread_bps >= 0.0, "Realized spread should be non-negative"); } /// Test market impact calculation #[tokio::test] async fn test_market_impact() { let config = MiFIDConfig::default(); let analyzer = BestExecutionAnalyzer::new(&config); // Large order to test market impact let order_info = OrderInfo { order_id: OrderId::new(), side: OrderSide::Buy, order_type: OrderType::Market, quantity: Quantity::from_shares(100000), price: None, symbol: "AAPL".to_string(), client_id: "CLIENT006".to_string(), timestamp: Utc::now(), }; let analysis = analyzer.analyze_best_execution(&order_info).await .expect("Analysis should succeed"); let metrics = &analysis.quality_metrics; // Large orders should have measurable market impact assert!(metrics.market_impact_bps >= 0.0, "Market impact should be non-negative"); } /// Test execution venue types #[tokio::test] async fn test_venue_types() { let config = MiFIDConfig::default(); let analyzer = BestExecutionAnalyzer::new(&config); let order_info = OrderInfo { order_id: OrderId::new(), side: OrderSide::Buy, order_type: OrderType::Limit, quantity: Quantity::from_shares(1000), price: Some(Price::from_f64(50.00).expect("Valid price")), symbol: "AMZN".to_string(), client_id: "CLIENT007".to_string(), timestamp: Utc::now(), }; let analysis = analyzer.analyze_best_execution(&order_info).await .expect("Analysis should succeed"); // Verify venue types are properly classified for venue in &analysis.alternative_venues { match &venue.venue_type { VenueType::ReguLatedMarket | VenueType::MTF | VenueType::OTF | VenueType::SystematicInternaliser | VenueType::MarketMaker | VenueType::OtherLiquidityProvider => { // Valid venue type assert!(true); } } } } /// Test custom execution factors configuration #[tokio::test] async fn test_custom_execution_factors() { let custom_config = BestExecutionConfig { real_time_monitoring: true, execution_factors: ExecutionFactors { price_weight: 0.40, cost_weight: 0.30, speed_weight: 0.15, likelihood_weight: 0.10, size_weight: 0.03, market_impact_weight: 0.02, }, venue_criteria: VenueSelectionCriteria { min_volume_threshold: Decimal::from(5000), max_latency_tolerance: 500, // 500μs min_execution_probability: 0.90, max_price_deviation_bps: 10.0, }, reporting_intervals: ReportingIntervals { real_time_interval: 1, daily_reports: true, monthly_rts28_reports: true, annual_summary: true, }, min_analysis_period_days: 30, }; // Verify config is valid let total_weight = custom_config.execution_factors.price_weight + custom_config.execution_factors.cost_weight + custom_config.execution_factors.speed_weight + custom_config.execution_factors.likelihood_weight + custom_config.execution_factors.size_weight + custom_config.execution_factors.market_impact_weight; assert!((total_weight - 1.0).abs() < 0.01, "Execution factor weights should sum to ~1.0"); } /// Test execution findings generation #[tokio::test] async fn test_execution_findings() { let config = MiFIDConfig::default(); let analyzer = BestExecutionAnalyzer::new(&config); let order_info = OrderInfo { order_id: OrderId::new(), side: OrderSide::Buy, order_type: OrderType::Limit, quantity: Quantity::from_shares(1000), price: Some(Price::from_f64(100.00).expect("Valid price")), symbol: "META".to_string(), client_id: "CLIENT008".to_string(), timestamp: Utc::now(), }; let analysis = analyzer.analyze_best_execution(&order_info).await .expect("Analysis should succeed"); // Findings should be empty for compliant execution or contain valid issues for finding in &analysis.findings { assert!(!finding.description.is_empty(), "Finding description should not be empty"); assert!(!finding.remedial_action.is_empty(), "Remedial action should be specified"); } } /// Test execution documentation #[tokio::test] async fn test_execution_documentation() { let config = MiFIDConfig::default(); let analyzer = BestExecutionAnalyzer::new(&config); let order_info = OrderInfo { order_id: OrderId::new(), side: OrderSide::Sell, order_type: OrderType::Limit, quantity: Quantity::from_shares(2000), price: Some(Price::from_f64(75.50).expect("Valid price")), symbol: "NFLX".to_string(), client_id: "CLIENT009".to_string(), timestamp: Utc::now(), }; let analysis = analyzer.analyze_best_execution(&order_info).await .expect("Analysis should succeed"); let docs = &analysis.documentation; // Verify documentation is complete assert!(!docs.venue_evaluation.is_empty(), "Venue evaluation should be documented"); assert!(!docs.cost_benefit_analysis.is_empty(), "Cost-benefit analysis should be documented"); assert!(!docs.decision_rationale.is_empty(), "Decision rationale should be documented"); // Verify market conditions snapshot assert!(docs.market_conditions.volatility >= 0.0, "Volatility should be non-negative"); assert!(docs.market_conditions.liquidity_depth >= Decimal::ZERO, "Liquidity depth should be non-negative"); } /// Test high-frequency trading execution quality #[tokio::test] async fn test_hft_execution_quality() { let config = MiFIDConfig::default(); let analyzer = BestExecutionAnalyzer::new(&config); // Small HFT order let order_info = OrderInfo { order_id: OrderId::new(), side: OrderSide::Buy, order_type: OrderType::Market, quantity: Quantity::from_shares(100), price: None, symbol: "SPY".to_string(), client_id: "HFT_CLIENT".to_string(), timestamp: Utc::now(), }; let analysis = analyzer.analyze_best_execution(&order_info).await .expect("Analysis should succeed"); let metrics = &analysis.quality_metrics; // HFT orders should have low execution times assert!(metrics.avg_execution_time_ms < 1000, "HFT execution should be fast (< 1 second)"); // High fill rate expected for liquid instruments assert!(metrics.fill_rate > 0.90, "Fill rate should be high for liquid instruments"); } /// Test multi-venue execution analysis #[tokio::test] async fn test_multi_venue_analysis() { let config = MiFIDConfig::default(); let analyzer = BestExecutionAnalyzer::new(&config); let order_info = OrderInfo { order_id: OrderId::new(), side: OrderSide::Buy, order_type: OrderType::Limit, quantity: Quantity::from_shares(10000), price: Some(Price::from_f64(200.00).expect("Valid price")), symbol: "GOOG".to_string(), client_id: "CLIENT010".to_string(), timestamp: Utc::now(), }; let analysis = analyzer.analyze_best_execution(&order_info).await .expect("Analysis should succeed"); // Should evaluate multiple venues assert!(analysis.alternative_venues.len() >= 1, "Should evaluate at least one alternative venue"); // Verify venues have different characteristics let mut venue_ids: Vec = analysis.alternative_venues .iter() .map(|v| v.venue_id.clone()) .collect(); venue_ids.sort(); venue_ids.dedup(); assert_eq!(venue_ids.len(), analysis.alternative_venues.len(), "Venue IDs should be unique"); } /// Test cost methodology validation #[tokio::test] async fn test_cost_methodology() { let config = MiFIDConfig::default(); let analyzer = BestExecutionAnalyzer::new(&config); let order_info = OrderInfo { order_id: OrderId::new(), side: OrderSide::Buy, order_type: OrderType::Limit, quantity: Quantity::from_shares(1000), price: Some(Price::from_f64(100.00).expect("Valid price")), symbol: "AMD".to_string(), client_id: "CLIENT011".to_string(), timestamp: Utc::now(), }; let analysis = analyzer.analyze_best_execution(&order_info).await .expect("Analysis should succeed"); // Verify cost methodology is documented assert!(!analysis.cost_analysis.methodology.is_empty(), "Cost methodology should be documented"); assert!(analysis.cost_analysis.methodology.contains("MiFID II") || analysis.cost_analysis.methodology.contains("RTS 28"), "Should reference regulatory requirements"); } /// Test execution score calculation accuracy #[tokio::test] async fn test_execution_score_accuracy() { let config = MiFIDConfig::default(); let analyzer = BestExecutionAnalyzer::new(&config); let order_info = OrderInfo { order_id: OrderId::new(), side: OrderSide::Buy, order_type: OrderType::Limit, quantity: Quantity::from_shares(1000), price: Some(Price::from_f64(100.00).expect("Valid price")), symbol: "INTC".to_string(), client_id: "CLIENT012".to_string(), timestamp: Utc::now(), }; let analysis = analyzer.analyze_best_execution(&order_info).await .expect("Analysis should succeed"); // Execution score should reflect quality metrics and costs let score = analysis.execution_score; let metrics = &analysis.quality_metrics; let costs = &analysis.cost_analysis; // High fill rate and low costs should correlate with higher score if metrics.fill_rate > 0.95 && costs.total_costs_bps < 10.0 { assert!(score > 0.7, "Good execution should have high score"); } // Verify score is normalized assert!(score >= 0.0 && score <= 1.0, "Score should be between 0 and 1"); }