"""Tests for intelligent autopilot functionality.""" import pytest from decimal import Decimal from unittest.mock import Mock, patch, AsyncMock from src.core.database import OrderSide, OrderType class TestPreFlightValidation: """Tests for pre-flight order validation.""" @pytest.fixture def mock_autopilot(self): """Create mock autopilot with necessary attributes.""" from src.autopilot.intelligent_autopilot import IntelligentAutopilot with patch.object(IntelligentAutopilot, '__init__', lambda x, *args, **kwargs: None): autopilot = IntelligentAutopilot.__new__(IntelligentAutopilot) autopilot.symbol = 'BTC/USD' autopilot.paper_trading = True autopilot.logger = Mock() # Mock trading engine autopilot.trading_engine = Mock() autopilot.trading_engine.paper_trading = Mock() autopilot.trading_engine.paper_trading.get_balance.return_value = Decimal('1000.0') autopilot.trading_engine.paper_trading.get_positions.return_value = [] return autopilot @pytest.mark.asyncio async def test_can_execute_order_insufficient_funds(self, mock_autopilot): """Test that insufficient funds returns False.""" mock_autopilot.trading_engine.paper_trading.get_balance.return_value = Decimal('10.0') can_execute, reason = await mock_autopilot._can_execute_order( side=OrderSide.BUY, quantity=Decimal('1.0'), price=Decimal('100.0') ) assert can_execute is False assert 'Insufficient funds' in reason @pytest.mark.asyncio async def test_can_execute_order_sufficient_funds(self, mock_autopilot): """Test that sufficient funds returns True.""" mock_autopilot.trading_engine.paper_trading.get_balance.return_value = Decimal('1000.0') can_execute, reason = await mock_autopilot._can_execute_order( side=OrderSide.BUY, quantity=Decimal('1.0'), price=Decimal('100.0') ) assert can_execute is True assert reason == 'OK' @pytest.mark.asyncio async def test_can_execute_order_no_position_for_sell(self, mock_autopilot): """Test that SELL without position returns False.""" mock_autopilot.trading_engine.paper_trading.get_positions.return_value = [] can_execute, reason = await mock_autopilot._can_execute_order( side=OrderSide.SELL, quantity=Decimal('1.0'), price=Decimal('100.0') ) assert can_execute is False assert 'No position to sell' in reason @pytest.mark.asyncio async def test_can_execute_order_minimum_value(self, mock_autopilot): """Test that order below minimum value returns False.""" can_execute, reason = await mock_autopilot._can_execute_order( side=OrderSide.BUY, quantity=Decimal('0.001'), price=Decimal('0.10') # Order value = $0.0001 ) assert can_execute is False assert 'below minimum' in reason class TestSmartOrderTypeSelection: """Tests for smart order type selection.""" @pytest.fixture def mock_autopilot(self): """Create mock autopilot for order type tests.""" from src.autopilot.intelligent_autopilot import IntelligentAutopilot with patch.object(IntelligentAutopilot, '__init__', lambda x, *args, **kwargs: None): autopilot = IntelligentAutopilot.__new__(IntelligentAutopilot) autopilot.logger = Mock() return autopilot def test_strong_signal_uses_market(self, mock_autopilot): """Test that strong signals (>80%) use MARKET orders.""" order_type, price = mock_autopilot._determine_order_type_and_price( side=OrderSide.BUY, signal_strength=0.85, current_price=Decimal('100.0'), is_stop_loss=False ) assert order_type == OrderType.MARKET assert price is None def test_normal_signal_uses_limit(self, mock_autopilot): """Test that normal signals use LIMIT orders.""" order_type, price = mock_autopilot._determine_order_type_and_price( side=OrderSide.BUY, signal_strength=0.65, current_price=Decimal('100.0'), is_stop_loss=False ) assert order_type == OrderType.LIMIT assert price is not None # BUY limit should be below market assert price < Decimal('100.0') def test_stop_loss_uses_market(self, mock_autopilot): """Test that stop-loss exits use MARKET orders.""" order_type, price = mock_autopilot._determine_order_type_and_price( side=OrderSide.SELL, signal_strength=0.5, current_price=Decimal('100.0'), is_stop_loss=True ) assert order_type == OrderType.MARKET assert price is None def test_take_profit_uses_limit(self, mock_autopilot): """Test that take-profit exits can use LIMIT orders.""" order_type, price = mock_autopilot._determine_order_type_and_price( side=OrderSide.SELL, signal_strength=0.6, current_price=Decimal('100.0'), is_stop_loss=False ) assert order_type == OrderType.LIMIT assert price is not None # SELL limit should be above market assert price > Decimal('100.0') def test_buy_limit_price_discount(self, mock_autopilot): """Test BUY LIMIT price is 0.1% below market.""" order_type, price = mock_autopilot._determine_order_type_and_price( side=OrderSide.BUY, signal_strength=0.6, current_price=Decimal('1000.00'), is_stop_loss=False ) # 0.1% discount = 999.00 expected = Decimal('999.00') assert price == expected def test_sell_limit_price_premium(self, mock_autopilot): """Test SELL LIMIT price is 0.1% above market.""" order_type, price = mock_autopilot._determine_order_type_and_price( side=OrderSide.SELL, signal_strength=0.6, current_price=Decimal('1000.00'), is_stop_loss=False ) # 0.1% premium = 1001.00 expected = Decimal('1001.00') assert price == expected