## Summary
Pre-commit warning regression fix wave - deployed 11 parallel Task agents to systematically eliminate all compilation errors (2) and warnings (136) across the entire workspace.
## Changes by Category
### P0 Compilation Fixes (2 errors → 0)
- ml/src/hyperopt/adapters/mamba2.rs: Added missing `trial_counter: 0` to test initializers (lines 1135, 1165)
### ML Crate Warnings (35 → 0)
- ml/src/hyperopt/tests.rs: Added `#[allow(deprecated)]` for test-specific deprecated function usage
- ml/src/ensemble/ab_testing.rs: Renamed unused variables (_control_count, _rng)
- ml/src/security/*.rs: Fixed unused loop variables (i → _)
- ml/src/tft/quantized_attention.rs: Renamed unused test variable (_v)
- ml/src/features/regime_adaptive.rs: Renamed unused variables (_adaptive)
- ml/src/regime/{orchestrator,ranging}.rs: Renamed unused variables
### Data Crate Fixes (28 warnings + 4 errors → 0)
- data/Cargo.toml: Moved clap from [dev-dependencies] to [dependencies] (examples require it)
- data/examples/validate_cl_fut.rs: Updated to databento 0.42.0 API (decode_record_ref loop pattern)
- data/examples/download_mbp10_data.rs: Fixed reqwest 0.12 API (bytes_stream → chunk)
- data/examples/*.rs: Removed unused imports (4 files via cargo fix)
- data/tests/real_data_helpers.rs: Added `#[allow(dead_code)]` to cross-binary test helpers
### API Gateway Test Warnings (19 → 0)
- services/api_gateway/tests/common/mod.rs: Added `#[allow(dead_code)]` to shared test utilities (6 items)
- services/api_gateway/tests/rate_limiting_tests.rs: Added `#[allow(dead_code)]` to REDIS_URL constant
## Verification
```bash
cargo check --workspace
# Result: Finished in 49.41s
# Warnings: 0 (was 136)
# Errors: 0 (was 2)
```
## Files Modified: 26 total
- ML: 14 files (9 manual + 5 auto-fixed)
- Data: 10 files (2 Cargo.toml + 6 examples + 1 test + 1 dependency update)
- API Gateway: 2 test files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
251 lines
9.2 KiB
Rust
251 lines
9.2 KiB
Rust
#![allow(unused_crate_dependencies)]
|
|
use common::{Order, OrderSide, OrderType, Price, Quantity, Symbol, TimeInForce};
|
|
use data::brokers::interactive_brokers::{IBConfig, InteractiveBrokersAdapter};
|
|
use data::brokers::{common::TradingOrder, BrokerClient};
|
|
use rust_decimal::prelude::ToPrimitive;
|
|
use rust_decimal_macros::dec;
|
|
use tokio::time::{sleep, Duration};
|
|
use tracing::error;
|
|
// use trading_engine::prelude::*; // REMOVED - prelude does not exist
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
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)
|
|
}
|