Files
foxhunt/tests/integration/backtesting_flow.rs
jgrusewski c0be3ca530 🔧 Major compilation fixes across entire workspace - Significant progress achieved
## Summary of Compilation Fixes

### Core Infrastructure Improvements
- **Fixed import system**: Established canonical type imports from common::types
- **Resolved syntax errors**: Fixed malformed use statements with embedded comments
- **Import consolidation**: Eliminated duplicate and conflicting type imports
- **Type visibility**: Improved public/private type access patterns

### Major Areas Fixed

#### Trading Engine (trading_engine/)
-  Fixed syntax errors in types/basic.rs with clean re-exports
-  Resolved OrderSide/Side naming conflicts
-  Fixed type_registry.rs malformed imports
-  Consolidated canonical type imports from common::types
-  Fixed broker_client.rs duplicate OrderStatus imports
- 🔄 Remaining: 41 type visibility errors (down from 286+ errors)

#### Common Types (common/)
-  Established as single source of truth for all types
-  Clean type definitions with proper visibility
-  Consistent error handling patterns

#### Data Pipeline (data/)
-  Updated imports to use canonical common::types
-  Fixed provider trait implementations
-  Resolved database integration issues

#### ML Components (ml/)
-  Fixed model interface imports
-  Updated feature extraction systems
-  Resolved training pipeline dependencies

#### Risk Management (risk/)
-  Fixed safety module imports
-  Updated VaR calculator dependencies
-  Consolidated compliance types

#### Services
-  Trading Service: Fixed repository implementations
-  Backtesting Service: Updated strategy engines
-  TLI: Fixed dashboard and UI components

#### Test Infrastructure
-  Updated integration test imports
-  Fixed performance benchmark dependencies
-  Resolved mock implementations

### Technical Achievements

#### Import System Overhaul
- Established common::types as canonical source
- Eliminated circular dependencies
- Fixed visibility modifiers (pub use vs use)
- Resolved naming conflicts (Side → OrderSide)

#### Type System Cleanup
- Consolidated duplicate type definitions
- Fixed malformed syntax (comments in use statements)
- Standardized error handling patterns
- Improved module structure

#### Configuration Management
- Enhanced config crate integration
- Fixed database configuration patterns
- Improved hot-reload mechanisms

### Error Reduction Progress
- **Before**: 371+ compilation errors across workspace
- **After**: ~202 errors remaining (46% reduction achieved)
- **Major**: Fixed critical syntax errors preventing any compilation
- **Infrastructure**: Resolved fundamental import and type system issues

### Files Modified: 347
- Core types and infrastructure
- Service implementations
- Test suites and benchmarks
- Configuration systems
- Database integrations

### Next Steps
- Complete remaining type visibility fixes in trading_engine
- Finalize import resolution in remaining modules
- Validate cross-crate dependencies
- Run comprehensive test suite

This represents a major milestone in achieving zero compilation errors across
the entire Foxhunt HFT trading system workspace. The foundational type system
and import structure has been successfully established and standardized.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-27 20:56:22 +02:00

762 lines
31 KiB
Rust

//! Backtesting Flow Integration Tests
//!
//! Comprehensive integration tests for TLI Client ↔ Backtesting Service communication.
//! Tests historical data replay, strategy execution, performance analytics, and
//! ML model integration with real-time monitoring.
use std::collections::HashMap;
use std::sync::{Arc, atomic::{AtomicU64, Ordering}};
use std::time::{Duration, Instant};
use tokio::sync::{mpsc, RwLock};
use tokio::time::timeout;
use uuid::Uuid;
use serde_json::json;
use chrono::{DateTime, Utc, Duration as ChronoDuration};
use tli::prelude::*;
use backtesting::*;
use ml::*;
use crate::fixtures::*;
use crate::mocks::*;
/// Backtesting flow integration test suite
pub struct BacktestingFlowTests {
/// TLI client suite for testing
client_suite: TliClientSuite,
/// Mock backtesting service
mock_backtesting_service: MockBacktestingService,
/// Historical data provider
test_data_provider: TestDataProvider,
/// ML model testing infrastructure
ml_test_infrastructure: MLTestInfrastructure,
/// Performance metrics collector
metrics: Arc<BacktestingMetrics>,
/// Test configuration
config: IntegrationTestConfig,
}
/// Performance metrics for backtesting operations
#[derive(Debug, Default)]
pub struct BacktestingMetrics {
/// Backtest initialization latency (nanoseconds)
pub initialization_latencies: RwLock<Vec<u64>>,
/// Data processing throughput (events per second)
pub data_processing_throughput: RwLock<Vec<f64>>,
/// ML inference latencies (nanoseconds)
pub ml_inference_latencies: RwLock<Vec<u64>>,
/// Strategy execution latencies (nanoseconds)
pub strategy_execution_latencies: RwLock<Vec<u64>>,
/// Memory usage during backtesting (MB)
pub memory_usage_samples: RwLock<Vec<u64>>,
/// Total events processed
pub total_events_processed: AtomicU64,
/// Error counter
pub error_count: AtomicU64,
}
impl BacktestingFlowTests {
/// Create new backtesting flow test suite
pub async fn new(config: IntegrationTestConfig) -> TliResult<Self> {
// Initialize test data provider with historical market data
let test_data_provider = TestDataProvider::new().await?;
// Initialize ML testing infrastructure
let ml_test_infrastructure = MLTestInfrastructure::new().await?;
// Initialize mock backtesting service
let mock_backtesting_service = MockBacktestingService::new().await?;
// Create TLI client suite with backtesting endpoints
let client_suite = TliClientBuilder::new()
.with_service_endpoint(
"backtesting_service".to_string(),
format!("http://localhost:{}", mock_backtesting_service.port())
)
.with_backtesting_config(BacktestingClientConfig {
timeout_ms: config.request_timeout_ms,
max_retry_attempts: config.max_retry_attempts,
stream_buffer_size: config.stream_buffer_size,
enable_real_time_monitoring: true,
..Default::default()
})
.build()
.await?;
Ok(Self {
client_suite,
mock_backtesting_service,
test_data_provider,
ml_test_infrastructure,
metrics: Arc::new(BacktestingMetrics::default()),
config,
})
}
/// Test basic backtest initialization and execution
pub async fn test_basic_backtest_execution(&self) -> TliResult<TestResult> {
let mut test_result = TestResult::new("basic_backtest_execution");
let start_time = Instant::now();
// Create backtest configuration
let backtest_config = CreateBacktestRequest {
name: "Integration Test Basic Strategy".to_string(),
strategy_type: "mean_reversion".to_string(),
symbol: "AAPL".to_string(),
start_date: (Utc::now() - ChronoDuration::days(30)).timestamp(),
end_date: Utc::now().timestamp(),
initial_capital: 100_000.0,
parameters: json!({
"lookback_period": 20,
"entry_threshold": 2.0,
"exit_threshold": 0.5,
"position_size": 0.02
}),
enable_real_time_monitoring: true,
};
// Configure mock response with realistic backtest results
self.mock_backtesting_service.configure_backtest_response(
&backtest_config.name,
BacktestResult {
backtest_id: format!("bt_{}", Uuid::new_v4()),
strategy_name: backtest_config.strategy_type.clone(),
total_return: 0.0847, // 8.47% return
annualized_return: 0.1124, // 11.24% annualized
max_drawdown: -0.0423, // -4.23% max drawdown
sharpe_ratio: 1.45,
total_trades: 127,
win_rate: 0.61,
avg_trade_return: 0.0012,
final_value: 108_470.0,
execution_time_ms: 2340,
events_processed: 876_543,
}
).await;
// Measure initialization latency
let init_start = Instant::now();
let create_response = match self.client_suite.backtesting_client {
Some(ref client) => {
timeout(
Duration::from_millis(self.config.request_timeout_ms),
client.create_backtest(backtest_config.clone())
).await
}
None => {
test_result.add_error("Backtesting client not available".to_string());
return Ok(test_result);
}
};
let init_latency = init_start.elapsed().as_nanos() as u64;
self.metrics.initialization_latencies.write().await.push(init_latency);
// Validate backtest creation
let backtest_id = match create_response {
Ok(Ok(resp)) => {
test_result.add_assertion("Backtest created successfully", resp.success);
test_result.add_assertion("Backtest ID provided", !resp.backtest_id.is_empty());
test_result.add_assertion(
"Initialization latency acceptable",
init_latency < self.config.max_init_latency_ns
);
resp.backtest_id
}
Ok(Err(e)) => {
test_result.add_error(format!("Backtest creation failed: {:?}", e));
return Ok(test_result);
}
Err(_) => {
test_result.add_error("Backtest creation timeout".to_string());
return Ok(test_result);
}
};
// Start backtest execution
if let Some(ref client) = self.client_suite.backtesting_client {
let start_response = client.start_backtest(StartBacktestRequest {
backtest_id: backtest_id.clone(),
enable_monitoring: true,
}).await?;
test_result.add_assertion("Backtest started successfully", start_response.success);
// Monitor backtest progress
let mut progress_updates = 0;
let monitor_duration = Duration::from_secs(10);
let monitor_start = Instant::now();
let progress_stream = client.subscribe_to_backtest_progress(&backtest_id).await?;
while monitor_start.elapsed() < monitor_duration {
if let Ok(update) = timeout(Duration::from_secs(1), progress_stream.recv()).await {
if let Some(progress) = update {
progress_updates += 1;
// Record performance metrics
if let Some(throughput) = progress.events_per_second {
self.metrics.data_processing_throughput.write().await.push(throughput);
}
if let Some(memory_mb) = progress.memory_usage_mb {
self.metrics.memory_usage_samples.write().await.push(memory_mb);
}
// Check if backtest completed
if progress.status == BacktestStatus::Completed {
break;
}
}
}
}
test_result.add_assertion("Received progress updates", progress_updates > 0);
// Get final results
let results_response = client.get_backtest_results(&backtest_id).await?;
if let Some(results) = results_response.results {
test_result.add_assertion("Results contain performance metrics", results.sharpe_ratio > 0.0);
test_result.add_assertion("Total trades executed", results.total_trades > 0);
test_result.add_assertion("Events processed", results.events_processed > 0);
test_result.metadata.insert("final_return".to_string(), json!(results.total_return));
test_result.metadata.insert("sharpe_ratio".to_string(), json!(results.sharpe_ratio));
test_result.metadata.insert("total_trades".to_string(), json!(results.total_trades));
self.metrics.total_events_processed.store(results.events_processed, Ordering::Relaxed);
}
}
test_result.execution_time = start_time.elapsed();
test_result.set_passed(test_result.errors.is_empty());
Ok(test_result)
}
/// Test ML-integrated backtesting with multiple models
pub async fn test_ml_integrated_backtesting(&self) -> TliResult<TestResult> {
let mut test_result = TestResult::new("ml_integrated_backtesting");
let start_time = Instant::now();
// Test multiple ML models
let test_models = vec!["TLOB", "MAMBA", "TFT", "DQN"];
for model_name in test_models {
let backtest_config = CreateBacktestRequest {
name: format!("ML Integration Test - {}", model_name),
strategy_type: "adaptive_ml".to_string(),
symbol: "AAPL".to_string(),
start_date: (Utc::now() - ChronoDuration::days(7)).timestamp(),
end_date: Utc::now().timestamp(),
initial_capital: 50_000.0,
parameters: json!({
"model_type": model_name,
"inference_interval_ms": 100,
"retraining_interval_hours": 4,
"feature_window": 50,
"confidence_threshold": 0.7
}),
enable_real_time_monitoring: true,
};
// Configure model-specific responses
let expected_performance = match model_name {
"TLOB" => (0.0623, 1.34, 89), // return, sharpe, trades
"MAMBA" => (0.0791, 1.52, 76),
"TFT" => (0.0534, 1.21, 102),
"DQN" => (0.0445, 1.08, 134),
_ => (0.05, 1.0, 100),
};
self.mock_backtesting_service.configure_ml_backtest_response(
&backtest_config.name,
model_name,
expected_performance.0,
expected_performance.1,
expected_performance.2,
).await;
// Execute ML backtest
if let Some(ref client) = self.client_suite.backtesting_client {
let ml_start = Instant::now();
let create_response = client.create_backtest(backtest_config.clone()).await?;
test_result.add_assertion(
&format!("{} backtest created", model_name),
create_response.success
);
if create_response.success {
let start_response = client.start_backtest(StartBacktestRequest {
backtest_id: create_response.backtest_id.clone(),
enable_monitoring: true,
}).await?;
test_result.add_assertion(
&format!("{} backtest started", model_name),
start_response.success
);
// Monitor ML inference performance
let inference_stream = client.subscribe_to_ml_metrics(&create_response.backtest_id).await?;
let mut inference_samples = 0;
// Collect inference metrics for 5 seconds
let inference_start = Instant::now();
while inference_start.elapsed() < Duration::from_secs(5) && inference_samples < 10 {
if let Ok(Some(metrics)) = timeout(Duration::from_millis(500), inference_stream.recv()).await {
inference_samples += 1;
if let Some(inference_latency) = metrics.inference_latency_ns {
self.metrics.ml_inference_latencies.write().await.push(inference_latency);
test_result.add_assertion(
&format!("{} inference latency acceptable", model_name),
inference_latency < self.config.max_ml_inference_latency_ns
);
}
}
}
test_result.add_assertion(
&format!("{} inference samples collected", model_name),
inference_samples > 0
);
}
let ml_latency = ml_start.elapsed().as_nanos() as u64;
test_result.metadata.insert(
format!("{}_execution_latency_ns", model_name),
json!(ml_latency)
);
}
}
test_result.execution_time = start_time.elapsed();
test_result.set_passed(test_result.errors.is_empty());
Ok(test_result)
}
/// Test ensemble backtesting with model comparison
pub async fn test_ensemble_backtesting(&self) -> TliResult<TestResult> {
let mut test_result = TestResult::new("ensemble_backtesting");
let start_time = Instant::now();
let ensemble_config = CreateBacktestRequest {
name: "Ensemble Strategy Integration Test".to_string(),
strategy_type: "ensemble_ml".to_string(),
symbol: "AAPL".to_string(),
start_date: (Utc::now() - ChronoDuration::days(14)).timestamp(),
end_date: Utc::now().timestamp(),
initial_capital: 100_000.0,
parameters: json!({
"models": ["TLOB", "MAMBA", "TFT"],
"ensemble_method": "weighted_average",
"model_weights": [0.4, 0.35, 0.25],
"rebalance_interval_hours": 6,
"confidence_threshold": 0.65
}),
enable_real_time_monitoring: true,
};
// Configure ensemble response with expected improved performance
self.mock_backtesting_service.configure_ensemble_response(
&ensemble_config.name,
EnsembleResults {
ensemble_return: 0.0934, // Better than individual models
ensemble_sharpe: 1.67, // Higher Sharpe ratio
individual_returns: vec![0.0623, 0.0791, 0.0534],
individual_sharpes: vec![1.34, 1.52, 1.21],
diversification_benefit: 0.0143,
model_weights_final: vec![0.42, 0.38, 0.20],
rebalance_count: 28,
}
).await;
if let Some(ref client) = self.client_suite.backtesting_client {
let ensemble_start = Instant::now();
// Create ensemble backtest
let create_response = client.create_backtest(ensemble_config.clone()).await?;
test_result.add_assertion("Ensemble backtest created", create_response.success);
if create_response.success {
// Start ensemble execution
let start_response = client.start_backtest(StartBacktestRequest {
backtest_id: create_response.backtest_id.clone(),
enable_monitoring: true,
}).await?;
test_result.add_assertion("Ensemble backtest started", start_response.success);
// Monitor ensemble metrics
let ensemble_stream = client.subscribe_to_ensemble_metrics(&create_response.backtest_id).await?;
let mut ensemble_updates = 0;
let mut weight_updates = Vec::new();
// Collect ensemble metrics
let monitor_start = Instant::now();
while monitor_start.elapsed() < Duration::from_secs(8) && ensemble_updates < 15 {
if let Ok(Some(metrics)) = timeout(Duration::from_millis(500), ensemble_stream.recv()).await {
ensemble_updates += 1;
if let Some(weights) = metrics.current_weights {
weight_updates.push(weights);
}
if let Some(diversification) = metrics.diversification_benefit {
test_result.add_assertion(
"Positive diversification benefit",
diversification > 0.0
);
}
}
}
test_result.add_assertion("Ensemble updates received", ensemble_updates > 0);
test_result.add_assertion("Weight rebalancing observed", weight_updates.len() > 1);
// Get final ensemble results
let results = client.get_ensemble_comparison(&create_response.backtest_id).await?;
if let Some(comparison) = results.comparison {
test_result.add_assertion(
"Ensemble outperformed individual models",
comparison.ensemble_improvement > 0.0
);
test_result.metadata.insert("ensemble_improvement".to_string(),
json!(comparison.ensemble_improvement));
test_result.metadata.insert("diversification_benefit".to_string(),
json!(comparison.diversification_benefit));
}
}
let ensemble_latency = ensemble_start.elapsed().as_nanos() as u64;
test_result.metadata.insert("ensemble_execution_latency_ns".to_string(), json!(ensemble_latency));
}
test_result.execution_time = start_time.elapsed();
test_result.set_passed(test_result.errors.is_empty());
Ok(test_result)
}
/// Test parallel backtesting execution for throughput validation
pub async fn test_parallel_backtesting_throughput(&self) -> TliResult<TestResult> {
let mut test_result = TestResult::new("parallel_backtesting_throughput");
let start_time = Instant::now();
let num_parallel_backtests = self.config.parallel_backtest_count;
let mut handles = Vec::new();
// Create multiple backtests in parallel
for i in 0..num_parallel_backtests {
let client = match self.client_suite.backtesting_client {
Some(ref c) => c.clone(),
None => {
test_result.add_error("Backtesting client not available".to_string());
return Ok(test_result);
}
};
let backtest_config = CreateBacktestRequest {
name: format!("Parallel Backtest {}", i),
strategy_type: "simple_ma".to_string(),
symbol: if i % 2 == 0 { "AAPL" } else { "MSFT" }.to_string(),
start_date: (Utc::now() - ChronoDuration::days(7)).timestamp(),
end_date: Utc::now().timestamp(),
initial_capital: 25_000.0,
parameters: json!({
"fast_period": 10 + (i % 5),
"slow_period": 20 + (i % 10),
"position_size": 0.1
}),
enable_real_time_monitoring: false, // Disable for throughput test
};
let metrics = Arc::clone(&self.metrics);
let handle = tokio::spawn(async move {
let start = Instant::now();
// Create and execute backtest
let create_result = client.create_backtest(backtest_config).await;
let execution_latency = start.elapsed().as_nanos() as u64;
match create_result {
Ok(response) if response.success => {
// Start the backtest
let start_result = client.start_backtest(StartBacktestRequest {
backtest_id: response.backtest_id.clone(),
enable_monitoring: false,
}).await;
match start_result {
Ok(start_resp) if start_resp.success => {
metrics.initialization_latencies.write().await.push(execution_latency);
true
}
_ => false
}
}
_ => {
metrics.error_count.fetch_add(1, Ordering::Relaxed);
false
}
}
});
handles.push(handle);
}
// Wait for all backtests to complete
let mut successful_backtests = 0;
for handle in handles {
if let Ok(success) = handle.await {
if success {
successful_backtests += 1;
}
}
}
let total_time = start_time.elapsed();
let throughput = successful_backtests as f64 / total_time.as_secs_f64();
// Validate throughput requirements
test_result.add_assertion(
"Minimum successful backtests",
successful_backtests >= (num_parallel_backtests * 8 / 10) // 80% success rate
);
test_result.add_assertion(
"Throughput meets requirements",
throughput >= self.config.min_backtest_throughput
);
test_result.metadata.insert("throughput_backtests_per_sec".to_string(), json!(throughput));
test_result.metadata.insert("successful_backtests".to_string(), json!(successful_backtests));
test_result.metadata.insert("total_backtests".to_string(), json!(num_parallel_backtests));
test_result.execution_time = total_time;
test_result.set_passed(test_result.errors.is_empty());
Ok(test_result)
}
/// Test real-time backtest monitoring and control
pub async fn test_real_time_monitoring_and_control(&self) -> TliResult<TestResult> {
let mut test_result = TestResult::new("real_time_monitoring_control");
let start_time = Instant::now();
let backtest_config = CreateBacktestRequest {
name: "Real-time Monitoring Test".to_string(),
strategy_type: "monitoring_test".to_string(),
symbol: "AAPL".to_string(),
start_date: (Utc::now() - ChronoDuration::days(30)).timestamp(),
end_date: Utc::now().timestamp(),
initial_capital: 100_000.0,
parameters: json!({
"slow_execution": true, // Force slow execution for control testing
"report_interval_ms": 1000
}),
enable_real_time_monitoring: true,
};
if let Some(ref client) = self.client_suite.backtesting_client {
// Create backtest
let create_response = client.create_backtest(backtest_config.clone()).await?;
test_result.add_assertion("Monitoring test backtest created", create_response.success);
if create_response.success {
let backtest_id = create_response.backtest_id;
// Start backtest
let start_response = client.start_backtest(StartBacktestRequest {
backtest_id: backtest_id.clone(),
enable_monitoring: true,
}).await?;
test_result.add_assertion("Monitoring test started", start_response.success);
// Monitor for 3 seconds, then pause
let progress_stream = client.subscribe_to_backtest_progress(&backtest_id).await?;
let mut progress_count = 0;
let monitor_start = Instant::now();
while monitor_start.elapsed() < Duration::from_secs(3) {
if let Ok(Some(_progress)) = timeout(Duration::from_millis(500), progress_stream.recv()).await {
progress_count += 1;
}
}
test_result.add_assertion("Progress updates received", progress_count > 0);
// Test pause functionality
let pause_response = client.pause_backtest(&backtest_id).await?;
test_result.add_assertion("Backtest paused successfully", pause_response.success);
// Verify paused state
tokio::time::sleep(Duration::from_millis(100)).await;
let status = client.get_backtest_status(&backtest_id).await?;
test_result.add_assertion("Status shows paused", status.status == BacktestStatus::Paused);
// Test resume functionality
let resume_response = client.resume_backtest(&backtest_id).await?;
test_result.add_assertion("Backtest resumed successfully", resume_response.success);
// Monitor resumed execution for 2 seconds
let resume_start = Instant::now();
let mut resume_progress_count = 0;
while resume_start.elapsed() < Duration::from_secs(2) {
if let Ok(Some(_progress)) = timeout(Duration::from_millis(500), progress_stream.recv()).await {
resume_progress_count += 1;
}
}
test_result.add_assertion("Progress after resume", resume_progress_count > 0);
// Test stop functionality
let stop_response = client.stop_backtest(&backtest_id).await?;
test_result.add_assertion("Backtest stopped successfully", stop_response.success);
// Verify stopped state
tokio::time::sleep(Duration::from_millis(100)).await;
let final_status = client.get_backtest_status(&backtest_id).await?;
test_result.add_assertion("Status shows stopped",
final_status.status == BacktestStatus::Stopped ||
final_status.status == BacktestStatus::Completed);
}
}
test_result.execution_time = start_time.elapsed();
test_result.set_passed(test_result.errors.is_empty());
Ok(test_result)
}
/// Run complete backtesting flow test suite
pub async fn run_complete_suite(&self) -> TliResult<TestSuite> {
let mut suite = TestSuite::new("backtesting_flow_integration");
let suite_start = Instant::now();
// Run all test cases
let tests = vec![
self.test_basic_backtest_execution().await?,
self.test_ml_integrated_backtesting().await?,
self.test_ensemble_backtesting().await?,
self.test_parallel_backtesting_throughput().await?,
self.test_real_time_monitoring_and_control().await?,
];
for test in tests {
suite.add_test_result(test);
}
// Generate performance summary
let metrics = self.generate_performance_summary().await;
suite.metadata.insert("backtesting_metrics".to_string(), json!(metrics));
suite.execution_time = suite_start.elapsed();
suite.set_passed(suite.passed_tests >= suite.total_tests * 80 / 100); // 80% pass rate
Ok(suite)
}
/// Generate comprehensive performance summary
async fn generate_performance_summary(&self) -> serde_json::Value {
let init_latencies = self.metrics.initialization_latencies.read().await;
let ml_latencies = self.metrics.ml_inference_latencies.read().await;
let throughput_samples = self.metrics.data_processing_throughput.read().await;
let memory_samples = self.metrics.memory_usage_samples.read().await;
let init_stats = calculate_latency_stats(&init_latencies);
let ml_stats = calculate_latency_stats(&ml_latencies);
let avg_throughput = if !throughput_samples.is_empty() {
throughput_samples.iter().sum::<f64>() / throughput_samples.len() as f64
} else {
0.0
};
let avg_memory = if !memory_samples.is_empty() {
memory_samples.iter().sum::<u64>() / memory_samples.len() as u64
} else {
0
};
json!({
"initialization": {
"count": init_latencies.len(),
"avg_ns": init_stats.avg,
"p95_ns": init_stats.p95,
"p99_ns": init_stats.p99,
"max_ns": init_stats.max
},
"ml_inference": {
"count": ml_latencies.len(),
"avg_ns": ml_stats.avg,
"p95_ns": ml_stats.p95,
"p99_ns": ml_stats.p99,
"max_ns": ml_stats.max
},
"data_processing": {
"avg_throughput_eps": avg_throughput,
"samples": throughput_samples.len()
},
"memory_usage": {
"avg_mb": avg_memory,
"samples": memory_samples.len()
},
"total_events_processed": self.metrics.total_events_processed.load(Ordering::Relaxed),
"error_count": self.metrics.error_count.load(Ordering::Relaxed)
})
}
}
/// Calculate latency statistics from measurements
fn calculate_latency_stats(latencies: &[u64]) -> LatencyStats {
if latencies.is_empty() {
return LatencyStats::default();
}
let mut sorted = latencies.to_vec();
sorted.sort_unstable();
let len = sorted.len();
let avg = sorted.iter().sum::<u64>() / len as u64;
let p95 = sorted[len * 95 / 100];
let p99 = sorted[len * 99 / 100];
let max = sorted[len - 1];
LatencyStats { avg, p95, p99, max }
}
/// Latency statistics structure
#[derive(Debug, Default)]
struct LatencyStats {
avg: u64,
p95: u64,
p99: u64,
max: u64,
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_backtesting_flow_integration() {
let config = IntegrationTestConfig::default();
let tests = BacktestingFlowTests::new(config).await.unwrap();
let results = tests.run_complete_suite().await.unwrap();
println!("Backtesting Flow Integration Test Results:");
println!("Passed: {}/{}", results.passed_tests, results.total_tests);
println!("Execution time: {:?}", results.execution_time);
// Print performance metrics
if let Some(metrics) = results.metadata.get("backtesting_metrics") {
println!("Backtesting Metrics: {}", serde_json::to_string_pretty(metrics).unwrap());
}
assert!(results.passed, "Backtesting flow integration tests should pass");
}
}