//! Basic adaptive strategy example //! //! This example demonstrates how to set up and run a basic adaptive trading strategy //! with ensemble models, risk management, and execution algorithms. use adaptive_strategy::config::*; use adaptive_strategy::{AdaptiveStrategy, StrategyConfig}; use std::collections::HashMap; use std::time::Duration; use tokio::time::sleep; use tracing::{info, Level}; #[tokio::main] async fn main() -> Result<(), Box> { // Initialize logging tracing_subscriber::fmt().with_max_level(Level::INFO).init(); info!("Starting basic adaptive strategy example"); // Create configuration let config = create_strategy_config(); // Initialize the adaptive strategy let mut strategy = AdaptiveStrategy::new(config).await?; info!("Strategy initialized successfully"); // Get initial state let initial_state = strategy.get_state().await; info!( "Initial strategy state: active={}, regime={}", initial_state.active, initial_state.current_regime ); // Simulate running for a short period (in production, this would run continuously) info!("Running strategy simulation for 10 seconds..."); // Start the strategy (this would run indefinitely in production) // For demo purposes, we'll use a timeout let strategy_task = tokio::spawn(async move { if let Err(e) = strategy.start().await { eprintln!("Strategy error: {}", e); } }); // Let it run for 10 seconds sleep(Duration::from_secs(10)).await; info!("Stopping strategy simulation"); strategy_task.abort(); info!("Example completed successfully"); Ok(()) } /// Create a comprehensive strategy configuration fn create_strategy_config() -> StrategyConfig { StrategyConfig { general: GeneralConfig { name: "basic_adaptive_strategy".to_string(), symbols: vec![ "BTC-USD".to_string(), "ETH-USD".to_string(), "SOL-USD".to_string(), ], execution_interval: Duration::from_millis(500), // Execute every 500ms error_backoff_duration: Duration::from_secs(2), max_position_fraction: 0.15, // Maximum 15% position size live_trading_enabled: false, // Paper trading for demo }, ensemble: EnsembleConfig { models: vec![ // Primary LSTM model with higher weight ModelConfig { model_type: "lstm".to_string(), name: "primary_lstm".to_string(), initial_weight: 0.4, parameters: create_lstm_parameters(), enabled: true, performance_threshold: 0.55, }, // Secondary Transformer model ModelConfig { model_type: "transformer".to_string(), name: "secondary_transformer".to_string(), initial_weight: 0.3, parameters: create_transformer_parameters(), enabled: true, performance_threshold: 0.55, }, // Tertiary GRU model ModelConfig { model_type: "gru".to_string(), name: "tertiary_gru".to_string(), initial_weight: 0.3, parameters: create_gru_parameters(), enabled: true, performance_threshold: 0.52, }, ], rebalance_interval: Duration::from_secs(300), // Rebalance every 5 minutes min_confidence_threshold: 0.65, // Require 65% confidence max_concurrent_models: 3, weight_decay_factor: 0.95, // Slight decay to prevent overfitting }, risk: RiskConfig { max_portfolio_var: 0.025, // 2.5% max portfolio VaR var_confidence_level: 0.95, // 95% confidence level max_drawdown_threshold: 0.08, // 8% max drawdown position_sizing_method: PositionSizingMethod::Kelly, kelly_fraction: 0.25, // Conservative quarter-Kelly max_leverage: 1.8, // Maximum 1.8x leverage stop_loss_pct: 0.025, // 2.5% stop loss take_profit_pct: 0.05, // 5% take profit }, execution: ExecutionConfig { algorithm: ExecutionAlgorithm::TWAP, // Use TWAP for demo max_order_size: 50000.0, // Maximum $50k orders min_order_size: 500.0, // Minimum $500 orders order_timeout: Duration::from_secs(45), max_slippage_bps: 15.0, // 15 basis points max slippage smart_routing_enabled: true, dark_pool_preference: 0.25, // 25% dark pool preference }, regime: RegimeConfig { detection_method: RegimeDetectionMethod::HMM, // Use HMM for regime detection lookback_window: 500, // 500 data points lookback min_regime_duration: Duration::from_secs(600), // 10 minutes minimum transition_sensitivity: 0.75, // 75% sensitivity features: vec![ "volatility".to_string(), "volume".to_string(), "returns".to_string(), "momentum".to_string(), "bid_ask_spread".to_string(), ], }, microstructure: MicrostructureConfig { book_depth: 15, // Analyze 15 levels deep trade_size_buckets: vec![ 1000.0, // Small trades 5000.0, // Medium trades 25000.0, // Large trades 100000.0, // Very large trades ], features: vec![ MicrostructureFeature::BidAskSpread, MicrostructureFeature::OrderBookImbalance, MicrostructureFeature::TradeSign, MicrostructureFeature::VolumeProfile, MicrostructureFeature::PriceImpact, ], update_frequency: Duration::from_millis(250), // Update every 250ms }, } } /// Create LSTM model parameters fn create_lstm_parameters() -> HashMap { let mut params = HashMap::new(); params.insert( "learning_rate".to_string(), serde_json::Value::Number(serde_json::Number::from_f64(0.001).unwrap()), ); params.insert( "hidden_size".to_string(), serde_json::Value::Number(serde_json::Number::from(128)), ); params.insert( "num_layers".to_string(), serde_json::Value::Number(serde_json::Number::from(2)), ); params.insert( "dropout".to_string(), serde_json::Value::Number(serde_json::Number::from_f64(0.2).unwrap()), ); params.insert( "sequence_length".to_string(), serde_json::Value::Number(serde_json::Number::from(50)), ); params } /// Create Transformer model parameters fn create_transformer_parameters() -> HashMap { let mut params = HashMap::new(); params.insert( "learning_rate".to_string(), serde_json::Value::Number(serde_json::Number::from_f64(0.0005).unwrap()), ); params.insert( "d_model".to_string(), serde_json::Value::Number(serde_json::Number::from(256)), ); params.insert( "num_heads".to_string(), serde_json::Value::Number(serde_json::Number::from(8)), ); params.insert( "num_layers".to_string(), serde_json::Value::Number(serde_json::Number::from(6)), ); params.insert( "dropout".to_string(), serde_json::Value::Number(serde_json::Number::from_f64(0.1).unwrap()), ); params.insert( "max_sequence_length".to_string(), serde_json::Value::Number(serde_json::Number::from(100)), ); params } /// Create GRU model parameters fn create_gru_parameters() -> HashMap { let mut params = HashMap::new(); params.insert( "learning_rate".to_string(), serde_json::Value::Number(serde_json::Number::from_f64(0.002).unwrap()), ); params.insert( "hidden_size".to_string(), serde_json::Value::Number(serde_json::Number::from(96)), ); params.insert( "num_layers".to_string(), serde_json::Value::Number(serde_json::Number::from(3)), ); params.insert( "dropout".to_string(), serde_json::Value::Number(serde_json::Number::from_f64(0.15).unwrap()), ); params.insert( "sequence_length".to_string(), serde_json::Value::Number(serde_json::Number::from(40)), ); params }