//! DBN Backtesting Integration Example //! //! This example demonstrates using DBN data with the backtesting service's //! MarketDataRepository interface. //! //! ## Usage //! //! ```bash //! cargo run --example dbn_backtesting_integration //! ``` use backtesting_service::{ dbn_repository::DbnMarketDataRepository, repositories::MarketDataRepository, }; use chrono::{TimeZone, Utc}; use std::collections::HashMap; #[tokio::main] async fn main() -> anyhow::Result<()> { println!("=== DBN Backtesting Integration Example ===\n"); // 1. Setup repository with DBN data let mut file_mapping = HashMap::new(); file_mapping.insert( "ES.FUT".to_string(), "test_data/real/databento/ES.FUT_ohlcv-1m_2024-01-02.dbn".to_string(), ); println!("Creating MarketDataRepository with DBN backend..."); let repo = DbnMarketDataRepository::new(file_mapping).await?; println!("Available symbols: {:?}", repo.available_symbols()); // 2. Define backtest time range let start_time = Utc .with_ymd_and_hms(2024, 1, 2, 14, 30, 0) .unwrap() .timestamp_nanos_opt() .unwrap(); let end_time = Utc .with_ymd_and_hms(2024, 1, 2, 16, 0, 0) .unwrap() .timestamp_nanos_opt() .unwrap(); println!( "\nBacktest window: {} to {}", Utc.timestamp_nanos(start_time).format("%Y-%m-%d %H:%M:%S"), Utc.timestamp_nanos(end_time).format("%Y-%m-%d %H:%M:%S") ); // 3. Load historical data via repository interface let symbols = vec!["ES.FUT".to_string()]; println!("\nLoading historical data for {:?}...", symbols); let data = repo.load_historical_data(&symbols, start_time, end_time).await?; println!("āœ… Loaded {} bars via repository interface\n", data.len()); // 4. Check data availability println!("=== Data Availability Check ==="); let availability = repo .check_data_availability(&symbols, start_time, end_time) .await?; for (symbol, available) in availability.iter() { println!( "{}: {}", symbol, if *available { "āœ… Available" } else { "āŒ Not available" } ); } // 5. Simulate simple backtest logic println!("\n=== Simulating Simple Backtest ==="); let mut position = 0i32; let mut pnl = 0.0; let mut trades = 0; for (i, bar) in data.iter().enumerate() { let close_f64 = bar.close.to_string().parse::().unwrap(); // Simple strategy: Buy when price drops, sell when price rises if i > 0 { let prev_close = data[i - 1].close.to_string().parse::().unwrap(); let price_change = close_f64 - prev_close; if position == 0 && price_change < -1.0 { // Buy signal position = 1; pnl -= close_f64; // Entry cost trades += 1; println!(" [{}] BUY @ {:.2}", bar.timestamp.format("%H:%M"), close_f64); } else if position == 1 && price_change > 1.0 { // Sell signal position = 0; pnl += close_f64; // Exit proceeds trades += 1; println!(" [{}] SELL @ {:.2}", bar.timestamp.format("%H:%M"), close_f64); } } } // Close any open position if position != 0 { let last_close = data.last().unwrap().close.to_string().parse::().unwrap(); pnl += last_close * position as f64; trades += 1; println!( " [{}] CLOSE @ {:.2}", data.last().unwrap().timestamp.format("%H:%M"), last_close ); } println!("\n=== Backtest Results ==="); println!("Total trades: {}", trades); println!("Final PnL: ${:.2}", pnl); // 6. Advanced repository features println!("\n=== Advanced Repository Features ==="); // Load with volume filter let min_volume = rust_decimal::Decimal::from(50); let high_volume_bars = repo .load_with_volume_filter(&symbols, min_volume, start_time, end_time) .await?; println!( "High-volume bars (volume >= {}): {}", min_volume, high_volume_bars.len() ); // Get date range let (first_ts, last_ts) = repo.get_date_range("ES.FUT").await?; println!("Data range: {} to {}", first_ts, last_ts); // Generate summary statistics let stats = repo.generate_summary_stats(&data); println!("\nSummary Statistics:"); println!(" Count: {}", stats.get("count").unwrap()); println!(" Mean close: ${:.2}", stats.get("mean_close").unwrap()); println!(" Std close: ${:.2}", stats.get("std_close").unwrap()); println!(" Min close: ${:.2}", stats.get("min_close").unwrap()); println!(" Max close: ${:.2}", stats.get("max_close").unwrap()); println!("\nāœ… Example completed successfully!"); Ok(()) }