#![allow(unused_crate_dependencies)] use common::{Order, OrderSide, OrderType, Price, Quantity, Symbol, TimeInForce}; use data::brokers::interactive_brokers::{IBConfig, InteractiveBrokersAdapter}; use data::brokers::{BrokerClient, common::TradingOrder}; use rust_decimal_macros::dec; use rust_decimal::prelude::ToPrimitive; use tokio::time::{sleep, Duration}; use tracing::{error, info}; // use trading_engine::prelude::*; // REMOVED - prelude does not exist #[tokio::main] async fn main() -> Result<(), Box> { println!("=== Interactive Brokers Risk Management Demo ==="); // Configure for paper trading environment let config = IBConfig { host: "127.0.0.1".to_string(), port: 7497, // Paper trading TWS port client_id: 1003, 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"); // Demo 1: Position Size Risk Management println!("\n=== Demo 1: Position Size Risk Management ==="); let symbol = Symbol::from("AAPL"); let account_value = 100000.0; // $100,000 account let max_risk_per_trade = 0.02; // 2% risk per trade let max_position_size = account_value * max_risk_per_trade; // $2,000 max risk println!("Account Value: ${:.2}", account_value); println!( "Max Risk Per Trade: {:.1}% (${:.2})", max_risk_per_trade * 100.0, max_position_size ); // Calculate position size based on stop loss let entry_price = Price::from_decimal(dec!(150.0)); let stop_loss_price = Price::from_decimal(dec!(147.0)); let risk_per_share = entry_price.to_f64() - stop_loss_price.to_f64(); let max_shares = (max_position_size / risk_per_share).floor() as i32; let position_value = max_shares as f64 * entry_price.to_f64(); println!("\nPosition Sizing Calculation:"); println!("Entry Price: ${:.2}", entry_price); println!("Stop Loss: ${:.2}", stop_loss_price); println!("Risk Per Share: ${:.2}", risk_per_share); println!("Max Shares: {}", max_shares); println!("Position Value: ${:.2}", position_value); // Demo 2: Stop Loss Order with Risk Management println!("\n=== Demo 2: Stop Loss Order Management ==="); // Place a limit order with protective stop let mut buy_order = Order::new( symbol.clone(), OrderSide::Buy, Quantity::try_from(max_shares as f64)?, Some(entry_price), OrderType::Limit, ); buy_order.time_in_force = TimeInForce::Day; println!( "Submitting buy order: {} shares of {} at ${:.2}", max_shares, symbol, entry_price ); let trading_order = TradingOrder::from_common_order(&buy_order)?; match adapter.submit_order(&trading_order).await { Ok(_) => { println!("✓ Buy order submitted successfully"); // Wait a moment for order processing sleep(Duration::from_millis(2000)).await; // Place protective stop loss order let mut stop_order = Order::new( symbol.clone(), OrderSide::Sell, Quantity::try_from(max_shares as f64)?, None, // price OrderType::Stop, ); stop_order.stop_price = Some(stop_loss_price); stop_order.time_in_force = TimeInForce::GoodTillCancel; println!("Submitting protective stop loss at ${:.2}", stop_loss_price); let trading_order = TradingOrder::from_common_order(&stop_order)?; match adapter.submit_order(&trading_order).await { Ok(_) => println!("✓ Stop loss order submitted successfully"), Err(e) => error!("✗ Failed to submit stop loss: {}", e), } }, Err(e) => error!("✗ Failed to submit buy order: {}", e), } // Demo 3: Position Monitoring and Risk Alerts println!("\n=== Demo 3: Position Monitoring ==="); println!("Monitoring position for 20 seconds..."); let start_time = std::time::Instant::now(); let mut last_check = start_time; while start_time.elapsed() < Duration::from_secs(20) { if !adapter.is_connected() { println!("Connection lost, attempting to reconnect..."); if let Err(e) = adapter.connect().await { error!("Reconnection failed: {}", e); break; } } // Check position every 5 seconds if last_check.elapsed() >= Duration::from_secs(5) { println!("\nChecking current positions..."); match adapter.get_positions(None).await { Ok(positions) => { let aapl_position = positions.iter().find(|p| p.symbol == symbol); if let Some(position) = aapl_position { let unrealized_pnl = position.unrealized_pnl; let pnl_percentage = (unrealized_pnl.to_f64().unwrap_or(0.0) / position_value.to_f64().unwrap_or(1.0)) * 100.0; println!("Position Update: {} shares", position.quantity); println!( "Unrealized P&L: ${:.2} ({:.2}%)", unrealized_pnl, pnl_percentage ); // Risk alerts if pnl_percentage <= -1.5 { println!("🔴 WARNING: Position approaching stop loss (-1.5% or worse)"); } else if pnl_percentage >= 2.0 { println!("🟢 PROFIT TARGET: Position up 2% or more - consider taking profits"); } } else { println!("No {} position found", symbol); } }, Err(e) => error!("Failed to get positions: {}", e), } last_check = std::time::Instant::now(); } sleep(Duration::from_millis(1000)).await; } // Demo 4: Emergency Position Closure println!("\n=== Demo 4: Emergency Position Management ==="); // Cancel all pending orders for the symbol println!("Cancelling all pending orders for {}...", symbol); // NOTE: cancel_all_orders_for_symbol not implemented - would cancel individually println!("⚠️ Bulk cancel not available - individual order cancellation would be required"); // Close any open position at market match adapter.get_positions(None).await { Ok(positions) => { let aapl_position = positions.iter().find(|p| p.symbol == symbol); if let Some(position) = aapl_position { if let Some(qty) = position.quantity.to_f64() { if qty.abs() > 0.0 { println!("Closing position: {} shares at market", qty); let mut close_order = Order::new( symbol.clone(), if qty > 0.0 { OrderSide::Sell } else { OrderSide::Buy }, Quantity::try_from(qty.abs())?, None, // price OrderType::Market, ); close_order.time_in_force = TimeInForce::ImmediateOrCancel; let trading_order = TradingOrder::from_common_order(&close_order)?; match adapter.submit_order(&trading_order).await { Ok(_) => println!("✓ Market close order submitted"), Err(e) => error!("✗ Failed to submit close order: {}", e), } } else { println!("No open position to close"); } } } else { println!("No {} position found to close", symbol); } }, Err(e) => error!("Failed to check positions for closure: {}", e), } // Final cleanup sleep(Duration::from_millis(2000)).await; println!("\nDisconnecting..."); adapter.disconnect().await?; println!("✓ Risk Management demo completed successfully"); Ok(()) } // Risk management utility functions #[allow(dead_code)] fn calculate_position_size( account_value: f64, risk_percentage: f64, entry_price: f64, stop_loss: f64, ) -> i32 { let max_risk = account_value * risk_percentage; let risk_per_share = (entry_price - stop_loss).abs(); (max_risk / risk_per_share).floor() as i32 } #[allow(dead_code)] fn calculate_stop_loss_price(entry_price: f64, risk_percentage: f64) -> f64 { entry_price * (1.0 - risk_percentage) } #[allow(dead_code)] fn calculate_take_profit_price(entry_price: f64, profit_target: f64) -> f64 { entry_price * (1.0 + profit_target) }