#![allow( clippy::tests_outside_test_module, clippy::unwrap_used, clippy::expect_used, clippy::indexing_slicing, clippy::str_to_string, clippy::string_to_string, clippy::assertions_on_result_states, clippy::assertions_on_constants, clippy::let_underscore_must_use, clippy::use_debug, clippy::doc_markdown, clippy::shadow_unrelated, clippy::shadow_reuse, clippy::similar_names, clippy::clone_on_copy, clippy::get_unwrap, clippy::modulo_arithmetic, clippy::integer_division, clippy::non_ascii_literal, clippy::useless_vec, clippy::useless_format, clippy::wildcard_enum_match_arm, clippy::manual_range_contains, clippy::const_is_empty, clippy::needless_range_loop, clippy::field_reassign_with_default, clippy::items_after_test_module, clippy::missing_const_for_fn, unused_imports, unused_variables, unused_mut, unused_assignments, unused_comparisons, unused_must_use, dead_code, )] //! Trading Engine Integration Tests //! //! Comprehensive test coverage for the core trading engine //! Tests the full flow: order submission -> validation -> execution -> position updates use chrono::Utc; use common::{MarketDataEvent, OrderId, OrderSide, OrderStatus, OrderType}; use rust_decimal::Decimal; use std::sync::Arc; use tokio::sync::{broadcast, RwLock}; use trading_engine::trading::data_interface::{DataProvider, Subscription}; use trading_engine::trading::engine::TradingEngine; use trading_engine::trading_operations::{ExecutionResult, LiquidityFlag}; // ============================================================================ // Mock Data Provider for Testing // ============================================================================ #[derive(Debug, Clone)] struct MockDataProvider { market_data_tx: broadcast::Sender, order_update_tx: broadcast::Sender, subscriptions: Arc>>, } impl MockDataProvider { fn new() -> Self { let (market_data_tx, _) = broadcast::channel(1000); let (order_update_tx, _) = broadcast::channel(1000); Self { market_data_tx, order_update_tx, subscriptions: Arc::new(RwLock::new(Vec::new())), } } } #[async_trait::async_trait] impl DataProvider for MockDataProvider { async fn subscribe_market_data(&self, subscription: Subscription) -> Result<(), String> { self.subscriptions.write().await.push(subscription); Ok(()) } fn subscribe_market_data_events(&self) -> broadcast::Receiver { self.market_data_tx.subscribe() } fn subscribe_order_update_events(&self) -> broadcast::Receiver { self.order_update_tx.subscribe() } } // ============================================================================ // Helper Functions // ============================================================================ fn create_test_engine() -> TradingEngine { let data_provider = Arc::new(MockDataProvider::new()); TradingEngine::new(data_provider) } fn create_execution( order_id: OrderId, symbol: &str, quantity: i64, price: i64, ) -> ExecutionResult { ExecutionResult { order_id, symbol: symbol.to_string(), side: OrderSide::Buy, executed_quantity: Decimal::from(quantity), execution_price: Decimal::from(price), execution_time: Utc::now(), commission: Decimal::from(10), liquidity_flag: LiquidityFlag::Maker, } } // ============================================================================ // Order Submission Tests (10 scenarios) // Note: These test validation logic before broker submission // ============================================================================ #[tokio::test] async fn test_submit_market_order_buy_validation() { let engine = create_test_engine(); // This will validate and create the order, but fail at broker submission // which is expected without a configured broker let result = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::from(1), None, None, ) .await; // Should fail because no broker is configured, but this proves validation passed assert!(result.is_err()); assert!(result.unwrap_err().contains("broker")); } #[tokio::test] #[ignore] // Requires configured broker async fn test_submit_limit_order_sell() { let engine = create_test_engine(); let result = engine .submit_order( "ETHUSD".to_string(), OrderSide::Sell, OrderType::Limit, Decimal::from(10), Some(Decimal::from(3000)), None, ) .await; assert!(result.is_ok()); } #[tokio::test] async fn test_submit_order_zero_quantity_rejected() { let engine = create_test_engine(); let result = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::ZERO, None, None, ) .await; assert!(result.is_err()); assert!(result.unwrap_err().contains("positive")); } #[tokio::test] async fn test_submit_order_negative_quantity_rejected() { let engine = create_test_engine(); let result = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::from(-10), None, None, ) .await; assert!(result.is_err()); assert!(result.unwrap_err().contains("positive")); } #[tokio::test] async fn test_submit_limit_order_zero_price_rejected() { let engine = create_test_engine(); let result = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Limit, Decimal::from(1), Some(Decimal::ZERO), None, ) .await; assert!(result.is_err()); assert!(result.unwrap_err().contains("price")); } #[tokio::test] async fn test_submit_order_empty_symbol_rejected() { let engine = create_test_engine(); let result = engine .submit_order( "".to_string(), OrderSide::Buy, OrderType::Market, Decimal::from(1), None, None, ) .await; assert!(result.is_err()); assert!(result.unwrap_err().contains("symbol")); } #[tokio::test] async fn test_submit_order_exceeds_buying_power() { let engine = create_test_engine(); // Try to buy 10 BTC at 50k each (500k total) - exceeds demo account 100k buying power let result = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::from(10), Some(Decimal::from(50000)), None, ) .await; assert!(result.is_err()); assert!(result.unwrap_err().contains("buying power")); } #[tokio::test] #[ignore] // Requires configured broker async fn test_submit_multiple_orders_same_symbol() { let engine = create_test_engine(); let result1 = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::from(1), Some(Decimal::from(50000)), None, ) .await; let result2 = engine .submit_order( "BTCUSD".to_string(), OrderSide::Sell, OrderType::Limit, Decimal::from(1), Some(Decimal::from(51000)), None, ) .await; assert!(result1.is_ok()); assert!(result2.is_ok()); } #[tokio::test] #[ignore] // Requires configured broker async fn test_submit_orders_different_symbols() { let engine = create_test_engine(); let btc_result = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::from(1), None, None, ) .await; let eth_result = engine .submit_order( "ETHUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::from(1), None, None, ) .await; assert!(btc_result.is_ok()); assert!(eth_result.is_ok()); } #[tokio::test] #[ignore] // Requires configured broker async fn test_submit_order_within_buying_power_boundary() { let engine = create_test_engine(); // Exactly at buying power limit (2 * 50000 = 100000) let result = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Limit, Decimal::from(2), Some(Decimal::from(50000)), None, ) .await; assert!(result.is_ok()); } // ============================================================================ // Order Cancellation Tests (5 scenarios) // ============================================================================ #[tokio::test] #[ignore] // Requires configured broker async fn test_cancel_pending_order() { let engine = create_test_engine(); let order_id: OrderId = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Limit, Decimal::from(1), Some(Decimal::from(50000)), None, ) .await .unwrap() .into(); let result = engine.cancel_order(order_id).await; assert!(result.is_ok()); } #[tokio::test] #[ignore] // Requires configured broker async fn test_cancel_filled_order_rejected() { let engine = create_test_engine(); let order_id: OrderId = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::from(1), None, None, ) .await .unwrap() .into(); // Simulate fill let execution = create_execution(order_id, "BTCUSD", 1, 50000); let _ = engine.process_execution(execution).await; // Try to cancel filled order let result = engine.cancel_order(order_id).await; assert!(result.is_err()); assert!(result.unwrap_err().contains("filled")); } #[tokio::test] async fn test_cancel_nonexistent_order() { let engine = create_test_engine(); let fake_order_id: OrderId = "nonexistent".to_string().into(); let result = engine.cancel_order(fake_order_id).await; assert!(result.is_err()); assert!(result.unwrap_err().contains("not found")); } #[tokio::test] #[ignore] // Requires configured broker async fn test_cancel_partially_filled_order() { let engine = create_test_engine(); let order_id: OrderId = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Limit, Decimal::from(10), Some(Decimal::from(50000)), None, ) .await .unwrap() .into(); // Partial fill (5 out of 10) let execution = create_execution(order_id, "BTCUSD", 5, 50000); let _ = engine.process_execution(execution).await; // Should be able to cancel partially filled order let result = engine.cancel_order(order_id).await; assert!(result.is_ok()); } #[tokio::test] #[ignore] // Requires configured broker async fn test_get_order_status_after_submission() { let engine = create_test_engine(); let order_id: OrderId = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Limit, Decimal::from(1), Some(Decimal::from(50000)), None, ) .await .unwrap() .into(); let order = engine.get_order_status(order_id).await; assert!(order.is_ok()); let order_data = order.unwrap(); assert_eq!(order_data.symbol, "BTCUSD"); assert_eq!(order_data.quantity, Decimal::from(1)); } // ============================================================================ // Fill Processing Tests (8 scenarios) // ============================================================================ #[tokio::test] #[ignore] // Requires configured broker async fn test_process_full_execution() { let engine = create_test_engine(); let order_id: OrderId = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::from(1), None, None, ) .await .unwrap() .into(); let execution = create_execution(order_id, "BTCUSD", 1, 50000); let result = engine.process_execution(execution).await; assert!(result.is_ok()); // Verify order status is Filled let order = engine.get_order_status(order_id).await.unwrap(); assert_eq!(order.status, OrderStatus::Filled); } #[tokio::test] #[ignore] // Requires configured broker async fn test_process_partial_execution() { let engine = create_test_engine(); let order_id: OrderId = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Limit, Decimal::from(10), Some(Decimal::from(50000)), None, ) .await .unwrap() .into(); // First partial fill let execution1 = create_execution(order_id, "BTCUSD", 3, 50000); engine .process_execution(execution1) .await .expect("First execution should succeed"); let order = engine.get_order_status(order_id).await.unwrap(); assert_eq!(order.status, OrderStatus::PartiallyFilled); assert_eq!(order.fill_quantity, Decimal::from(3)); } #[tokio::test] #[ignore] // Requires configured broker async fn test_process_multiple_partial_fills() { let engine = create_test_engine(); let order_id: OrderId = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Limit, Decimal::from(100), Some(Decimal::from(50000)), None, ) .await .unwrap() .into(); // Multiple partial fills let execution1 = create_execution(order_id, "BTCUSD", 30, 50000); engine.process_execution(execution1).await.unwrap(); let execution2 = create_execution(order_id, "BTCUSD", 40, 50100); engine.process_execution(execution2).await.unwrap(); let execution3 = create_execution(order_id, "BTCUSD", 30, 49900); engine.process_execution(execution3).await.unwrap(); let order = engine.get_order_status(order_id).await.unwrap(); assert_eq!(order.status, OrderStatus::Filled); assert_eq!(order.fill_quantity, Decimal::from(100)); // Check weighted average price let expected_avg = (Decimal::from(30) * Decimal::from(50000) + Decimal::from(40) * Decimal::from(50100) + Decimal::from(30) * Decimal::from(49900)) / Decimal::from(100); assert_eq!(order.average_fill_price, Some(expected_avg)); } #[tokio::test] #[ignore] // Requires configured broker async fn test_execution_updates_position() { let engine = create_test_engine(); let order_id: OrderId = engine .submit_order( "ETHUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::from(10), None, None, ) .await .unwrap() .into(); let execution = create_execution(order_id, "ETHUSD", 10, 3000); engine.process_execution(execution).await.unwrap(); // Check position was created let positions = engine.get_positions(Some("ETHUSD".to_string())).await; assert!(positions.is_ok()); let pos_list = positions.unwrap(); assert_eq!(pos_list.len(), 1); assert_eq!(pos_list[0].quantity, Decimal::from(10)); } #[tokio::test] #[ignore] // Requires configured broker async fn test_execution_updates_account_balance() { let engine = create_test_engine(); let order_id: OrderId = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::from(1), None, None, ) .await .unwrap() .into(); let execution = ExecutionResult { order_id, symbol: "BTCUSD".to_string(), side: OrderSide::Buy, executed_quantity: Decimal::from(1), execution_price: Decimal::from(50000), execution_time: Utc::now(), commission: Decimal::from(25), // $25 commission liquidity_flag: LiquidityFlag::Taker, }; engine.process_execution(execution).await.unwrap(); // Account should be updated (execution value + commission deducted) let account = engine .get_account_info("DEMO_ACCOUNT".to_string()) .await .unwrap(); // Buy: cash -= (1 * 50000) + 25 = 50025 assert_eq!( account.cash_balance, Decimal::from(50000) - Decimal::from(50025) ); } #[tokio::test] #[ignore] // Requires configured broker async fn test_execution_with_slippage() { let engine = create_test_engine(); let order_id: OrderId = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Limit, Decimal::from(1), Some(Decimal::from(50000)), None, ) .await .unwrap() .into(); // Execute at worse price (slippage) let execution = create_execution(order_id, "BTCUSD", 1, 50100); let result = engine.process_execution(execution).await; assert!(result.is_ok()); let order = engine.get_order_status(order_id).await.unwrap(); assert_eq!(order.average_fill_price, Some(Decimal::from(50100))); } #[tokio::test] async fn test_execution_for_nonexistent_order() { let engine = create_test_engine(); let fake_order_id: OrderId = "nonexistent".to_string().into(); let execution = create_execution(fake_order_id, "BTCUSD", 1, 50000); let result = engine.process_execution(execution).await; assert!(result.is_err()); } #[tokio::test] #[ignore] // Requires configured broker async fn test_execution_creates_position_if_not_exists() { let engine = create_test_engine(); let order_id: OrderId = engine .submit_order( "SOLUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::from(100), None, None, ) .await .unwrap() .into(); let execution = create_execution(order_id, "SOLUSD", 100, 150); engine.process_execution(execution).await.unwrap(); let positions = engine.get_positions(Some("SOLUSD".to_string())).await; assert!(positions.is_ok()); let pos_list = positions.unwrap(); assert_eq!(pos_list.len(), 1); assert_eq!(pos_list[0].symbol.to_string(), "SOLUSD"); } // ============================================================================ // Position Management Tests (7 scenarios) // ============================================================================ #[tokio::test] async fn test_get_positions_empty() { let engine = create_test_engine(); let positions = engine.get_positions(None).await; assert!(positions.is_ok()); assert!(positions.unwrap().is_empty()); } #[tokio::test] #[ignore] // Requires configured broker async fn test_get_positions_after_execution() { let engine = create_test_engine(); let order_id: OrderId = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::from(2), None, None, ) .await .unwrap() .into(); let execution = create_execution(order_id, "BTCUSD", 2, 50000); engine.process_execution(execution).await.unwrap(); let positions = engine.get_positions(None).await.unwrap(); assert_eq!(positions.len(), 1); assert_eq!(positions[0].symbol.to_string(), "BTCUSD"); assert_eq!(positions[0].quantity, Decimal::from(2)); } #[tokio::test] #[ignore] // Requires configured broker async fn test_get_positions_multiple_symbols() { let engine = create_test_engine(); // BTC position let btc_order_id: OrderId = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::from(1), None, None, ) .await .unwrap() .into(); let btc_execution = create_execution(btc_order_id, "BTCUSD", 1, 50000); engine.process_execution(btc_execution).await.unwrap(); // ETH position let eth_order_id: OrderId = engine .submit_order( "ETHUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::from(10), None, None, ) .await .unwrap() .into(); let eth_execution = create_execution(eth_order_id, "ETHUSD", 10, 3000); engine.process_execution(eth_execution).await.unwrap(); let positions = engine.get_positions(None).await.unwrap(); assert_eq!(positions.len(), 2); let symbols: Vec = positions.iter().map(|p| p.symbol.to_string()).collect(); assert!(symbols.contains(&"BTCUSD".to_string())); assert!(symbols.contains(&"ETHUSD".to_string())); } #[tokio::test] #[ignore] // Requires configured broker async fn test_get_positions_filtered_by_symbol() { let engine = create_test_engine(); // Create multiple positions let btc_order_id: OrderId = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::from(1), None, None, ) .await .unwrap() .into(); let btc_execution = create_execution(btc_order_id, "BTCUSD", 1, 50000); engine.process_execution(btc_execution).await.unwrap(); let eth_order_id: OrderId = engine .submit_order( "ETHUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::from(10), None, None, ) .await .unwrap() .into(); let eth_execution = create_execution(eth_order_id, "ETHUSD", 10, 3000); engine.process_execution(eth_execution).await.unwrap(); // Filter for BTC only let btc_positions = engine .get_positions(Some("BTCUSD".to_string())) .await .unwrap(); assert_eq!(btc_positions.len(), 1); assert_eq!(btc_positions[0].symbol.to_string(), "BTCUSD"); } #[tokio::test] #[ignore] // Requires configured broker async fn test_position_increases_with_additional_buy() { let engine = create_test_engine(); // First buy let order1_id: OrderId = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::from(1), None, None, ) .await .unwrap() .into(); let execution1 = create_execution(order1_id, "BTCUSD", 1, 50000); engine.process_execution(execution1).await.unwrap(); // Second buy let order2_id: OrderId = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::from(1), None, None, ) .await .unwrap() .into(); let execution2 = create_execution(order2_id, "BTCUSD", 1, 51000); engine.process_execution(execution2).await.unwrap(); let positions = engine .get_positions(Some("BTCUSD".to_string())) .await .unwrap(); assert_eq!(positions.len(), 1); assert_eq!(positions[0].quantity, Decimal::from(2)); } #[tokio::test] #[ignore] // Requires configured broker async fn test_position_reduces_with_sell() { let engine = create_test_engine(); // Buy 10 let buy_order_id: OrderId = engine .submit_order( "ETHUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::from(10), None, None, ) .await .unwrap() .into(); let buy_execution = create_execution(buy_order_id, "ETHUSD", 10, 3000); engine.process_execution(buy_execution).await.unwrap(); // Sell 6 let sell_order_id: OrderId = engine .submit_order( "ETHUSD".to_string(), OrderSide::Sell, OrderType::Market, Decimal::from(6), None, None, ) .await .unwrap() .into(); let sell_execution = ExecutionResult { order_id: sell_order_id, symbol: "ETHUSD".to_string(), side: OrderSide::Sell, executed_quantity: Decimal::from(6), execution_price: Decimal::from(3100), execution_time: Utc::now(), commission: Decimal::from(10), liquidity_flag: LiquidityFlag::Taker, }; engine.process_execution(sell_execution).await.unwrap(); let positions = engine .get_positions(Some("ETHUSD".to_string())) .await .unwrap(); assert_eq!(positions.len(), 1); assert_eq!(positions[0].quantity, Decimal::from(4)); } #[tokio::test] #[ignore] // Requires configured broker async fn test_position_flattened_with_equal_sell() { let engine = create_test_engine(); // Buy 10 let buy_order_id: OrderId = engine .submit_order( "SOLUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::from(10), None, None, ) .await .unwrap() .into(); let buy_execution = create_execution(buy_order_id, "SOLUSD", 10, 100); engine.process_execution(buy_execution).await.unwrap(); // Sell 10 (flatten) let sell_order_id: OrderId = engine .submit_order( "SOLUSD".to_string(), OrderSide::Sell, OrderType::Market, Decimal::from(10), None, None, ) .await .unwrap() .into(); let sell_execution = ExecutionResult { order_id: sell_order_id, symbol: "SOLUSD".to_string(), side: OrderSide::Sell, executed_quantity: Decimal::from(10), execution_price: Decimal::from(110), execution_time: Utc::now(), commission: Decimal::from(5), liquidity_flag: LiquidityFlag::Maker, }; engine.process_execution(sell_execution).await.unwrap(); let positions = engine .get_positions(Some("SOLUSD".to_string())) .await .unwrap(); assert_eq!(positions.len(), 1); assert_eq!(positions[0].quantity, Decimal::ZERO); } // ============================================================================ // Market Data Subscription Tests (3 scenarios) // ============================================================================ #[tokio::test] async fn test_subscribe_market_data() { let engine = create_test_engine(); let result = engine .subscribe_market_data(vec!["BTCUSD".to_string(), "ETHUSD".to_string()]) .await; assert!(result.is_ok()); } #[tokio::test] async fn test_subscribe_order_updates() { let engine = create_test_engine(); let result = engine.subscribe_order_updates(None).await; assert!(result.is_ok()); } #[tokio::test] async fn test_subscribe_order_updates_with_account() { let engine = create_test_engine(); let result = engine .subscribe_order_updates(Some("DEMO_ACCOUNT".to_string())) .await; assert!(result.is_ok()); } // ============================================================================ // Trading Stats Tests (2 scenarios) // ============================================================================ #[tokio::test] async fn test_get_trading_stats_initial() { let engine = create_test_engine(); let stats = engine.get_trading_stats().await; // Initial stats should have zeros assert_eq!(stats.total_orders, 0); assert_eq!(stats.filled_orders, 0); } #[tokio::test] #[ignore] // Requires configured broker async fn test_get_trading_stats_after_orders() { let engine = create_test_engine(); // Submit and execute an order let order_id: OrderId = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::from(1), None, None, ) .await .unwrap() .into(); let execution = create_execution(order_id, "BTCUSD", 1, 50000); engine.process_execution(execution).await.unwrap(); let stats = engine.get_trading_stats().await; assert_eq!(stats.total_orders, 1); assert_eq!(stats.filled_orders, 1); } // ============================================================================ // Account Info Tests (2 scenarios) // ============================================================================ #[tokio::test] async fn test_get_account_info_demo_account() { let engine = create_test_engine(); let account = engine .get_account_info("DEMO_ACCOUNT".to_string()) .await; assert!(account.is_ok()); let account_info = account.unwrap(); assert_eq!(account_info.account_id, "DEMO_ACCOUNT"); assert_eq!(account_info.total_value, Decimal::from(100000)); assert_eq!(account_info.cash_balance, Decimal::from(50000)); } #[tokio::test] async fn test_get_account_info_nonexistent() { let engine = create_test_engine(); let result = engine .get_account_info("NONEXISTENT".to_string()) .await; assert!(result.is_err()); assert!(result.unwrap_err().contains("not found")); } // ============================================================================ // Edge Cases & Error Handling (5 scenarios) // ============================================================================ #[tokio::test] #[ignore] // Requires configured broker async fn test_concurrent_order_submissions() { let engine = Arc::new(create_test_engine()); let mut handles = vec![]; for i in 0..5 { let engine_clone = Arc::clone(&engine); let handle = tokio::spawn(async move { engine_clone .submit_order( format!("SYM{}", i), OrderSide::Buy, OrderType::Market, Decimal::from(1), None, None, ) .await }); handles.push(handle); } let results: Vec<_> = futures::future::join_all(handles).await; // All should succeed for result in results { assert!(result.unwrap().is_ok()); } } #[tokio::test] #[ignore] // Requires configured broker async fn test_rapid_fire_executions() { let engine = create_test_engine(); let order_id: OrderId = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Limit, Decimal::from(100), Some(Decimal::from(50000)), None, ) .await .unwrap() .into(); // Process 10 small executions rapidly for i in 1..=10 { let execution = create_execution(order_id, "BTCUSD", 10, 50000 + i * 10); engine.process_execution(execution).await.unwrap(); } let order = engine.get_order_status(order_id).await.unwrap(); assert_eq!(order.status, OrderStatus::Filled); assert_eq!(order.fill_quantity, Decimal::from(100)); } #[tokio::test] #[ignore] // Requires configured broker async fn test_order_after_partial_cancel() { let engine = create_test_engine(); let order_id: OrderId = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Limit, Decimal::from(10), Some(Decimal::from(50000)), None, ) .await .unwrap() .into(); // Partial fill let execution = create_execution(order_id, "BTCUSD", 3, 50000); engine.process_execution(execution).await.unwrap(); // Cancel the rest engine.cancel_order(order_id).await.unwrap(); let order = engine.get_order_status(order_id).await.unwrap(); assert_eq!(order.status, OrderStatus::Cancelled); assert_eq!(order.fill_quantity, Decimal::from(3)); // Partial fill remains } #[tokio::test] #[ignore] // Requires configured broker async fn test_large_order_quantity() { let engine = create_test_engine(); let result = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Limit, Decimal::from(1000000), Some(Decimal::from(1)), // Low price to pass buying power check None, ) .await; assert!(result.is_ok()); } #[tokio::test] #[ignore] // Requires configured broker async fn test_fractional_order_quantity() { let engine = create_test_engine(); let result = engine .submit_order( "BTCUSD".to_string(), OrderSide::Buy, OrderType::Market, Decimal::new(15, 1), // 1.5 None, None, ) .await; assert!(result.is_ok()); }