#![allow(unused_crate_dependencies)] use common::{Price, Quantity, Symbol}; use data::brokers::interactive_brokers::{IBConfig, InteractiveBrokersAdapter}; use tokio::time::{sleep, Duration}; use tracing::{error, info, warn}; #[tokio::main] async fn main() -> Result<(), Box> { println!("=== Interactive Brokers Market Data Subscription Example ==="); // Configure for paper trading environment let config = IBConfig { host: "127.0.0.1".to_string(), port: 7497, // Paper trading TWS port client_id: 1001, account_id: "DU123456".to_string(), // Demo account connection_timeout: 30, max_reconnect_attempts: 3, heartbeat_interval: 60, request_timeout: 10, }; let mut adapter = InteractiveBrokersAdapter::new(config); println!("Connecting to TWS..."); adapter.connect().await?; if !adapter.is_connected() { error!("Failed to establish connection"); return Ok(()); } println!("✓ Connected successfully"); // Subscribe to market data for various symbols let symbols = vec![ Symbol::from("AAPL"), // Apple stock Symbol::from("MSFT"), // Microsoft stock Symbol::from("SPY"), // S&P 500 ETF Symbol::from("EUR.USD"), // EUR/USD forex pair ]; println!( "\nSubscribing to market data for {} symbols...", symbols.len() ); let mut request_ids = Vec::new(); for symbol in &symbols { match adapter.request_market_data(symbol).await { Ok(request_id) => { println!("✓ Subscribed to {} (request_id: {})", symbol, request_id); request_ids.push(request_id); }, Err(e) => error!("✗ Failed to subscribe to {}: {}", symbol, e), } // Small delay between subscriptions to avoid rate limiting sleep(Duration::from_millis(100)).await; } println!("\nListening for market data updates for 30 seconds..."); println!("Market data will be processed in the background message loop"); // Listen for market data for 30 seconds let start_time = std::time::Instant::now(); while start_time.elapsed() < Duration::from_secs(30) { if !adapter.is_connected() { println!("Connection lost, attempting to reconnect..."); if let Err(e) = adapter.connect().await { error!("Reconnection failed: {}", e); break; } } sleep(Duration::from_millis(1000)).await; // Print periodic status if start_time.elapsed().as_secs() % 10 == 0 { println!( "Still listening... ({:.0}s elapsed)", start_time.elapsed().as_secs() ); } } println!("\nUnsubscribing from market data..."); // Cancel all market data subscriptions for (symbol, request_id) in symbols.into_iter().zip(request_ids.into_iter()) { match adapter.cancel_market_data(request_id).await { Ok(_) => println!( "✓ Unsubscribed from {} (request_id: {})", symbol, request_id ), Err(e) => error!("✗ Failed to unsubscribe from {}: {}", symbol, e), } } println!("\nDisconnecting..."); adapter.disconnect().await?; println!("✓ Market data subscription example completed successfully"); Ok(()) } // Example of market data event handler (would be integrated with the adapter) #[allow(dead_code)] async fn handle_market_data_event( symbol: Symbol, bid: Price, ask: Price, last: Price, volume: Quantity, ) { println!( "Market Data Update: {} - Bid: {}, Ask: {}, Last: {}, Volume: {}", symbol, bid, ask, last, volume ); } // Example of tick-by-tick data handler #[allow(dead_code)] async fn handle_tick_data( symbol: Symbol, tick_type: &str, price: Price, size: Quantity, timestamp: u64, ) { println!( "Tick Data: {} - Type: {}, Price: {}, Size: {}, Time: {}", symbol, tick_type, price, size, timestamp ); }