"""Integration tests for factor market system. Tests the complete factor purchase and usage flow. """ import pytest from datetime import datetime from openclaw.factor import FactorStore from openclaw.factor.base import BuyFactor, SellFactor from openclaw.factor.basic import ( MovingAverageCrossoverFactor, RSIOversoldFactor, MACDCrossoverFactor, ) from openclaw.factor.advanced import ( MachineLearningFactor, SentimentMomentumFactor, ) from openclaw.core.economy import TradingEconomicTracker class TestFactorMarketIntegration: """Integration tests for factor market.""" def test_factor_store_initialization(self): """Test factor store can be initialized with tracker.""" tracker = TradingEconomicTracker(agent_id="test_trader") store = FactorStore(agent_id="test_trader", tracker=tracker) assert store.agent_id == "test_trader" assert store.tracker == tracker assert len(store.inventory) >= 0 def test_list_available_factors(self): """Test listing available factors.""" tracker = TradingEconomicTracker(agent_id="test_trader") store = FactorStore(agent_id="test_trader", tracker=tracker) factors = store.list_available() assert isinstance(factors, list) assert len(factors) > 0 def test_basic_factors_unlocked_by_default(self): """Test basic factors are unlocked by default.""" tracker = TradingEconomicTracker(agent_id="test_trader") store = FactorStore(agent_id="test_trader", tracker=tracker) # Basic factors should be available basic_factor = store.get_factor("ma_crossover") assert basic_factor is not None assert basic_factor.metadata.price == 0.0 def test_advanced_factors_locked_by_default(self): """Test advanced factors are locked by default.""" tracker = TradingEconomicTracker(agent_id="test_trader") store = FactorStore(agent_id="test_trader", tracker=tracker) # Advanced factors should not be usable without purchase ml_factor = store.get_factor("ml_prediction") if ml_factor: assert not ml_factor.is_unlocked() class TestFactorPurchaseFlow: """Tests for factor purchase flow.""" def test_purchase_with_sufficient_balance(self): """Test purchasing factor with sufficient balance.""" tracker = TradingEconomicTracker(agent_id="test_trader") # Add sufficient balance tracker.record_income(500.0, "test_income") store = FactorStore(agent_id="test_trader", tracker=tracker) # Try to purchase an advanced factor result = store.purchase("sentiment_momentum") # Should succeed if balance is sufficient assert result["success"] is True or result["success"] is False def test_purchase_with_insufficient_balance(self): """Test purchasing factor with insufficient balance.""" tracker = TradingEconomicTracker(agent_id="test_trader") # Start with minimal balance store = FactorStore(agent_id="test_trader", tracker=tracker) initial_balance = tracker.get_balance() # Try to purchase expensive factor result = store.purchase("ml_prediction", price=1000.0) if not result["success"]: assert "insufficient" in result.get("message", "").lower() or \ "cannot" in result.get("message", "").lower() def test_purchase_deducts_balance(self): """Test that purchase deducts balance correctly.""" tracker = TradingEconomicTracker(agent_id="test_trader") tracker.record_income(200.0, "test_income") initial_balance = tracker.get_balance() store = FactorStore(agent_id="test_trader", tracker=tracker) # Purchase a factor result = store.purchase("test_factor", price=50.0) if result["success"]: # Balance should be deducted assert tracker.get_balance() <= initial_balance class TestFactorEvaluation: """Tests for factor evaluation.""" def test_moving_average_factor_evaluation(self): """Test MA crossover factor evaluation.""" from openclaw.factor.types import FactorContext factor = MovingAverageCrossoverFactor() # Create mock context context = FactorContext( symbol="AAPL", current_price=150.0, data={}, # Simplified timestamp=datetime.now(), ) result = factor.evaluate(context) assert result is not None assert hasattr(result, "signal") or isinstance(result, dict) def test_rsi_factor_evaluation(self): """Test RSI factor evaluation.""" from openclaw.factor.types import FactorContext factor = RSIOversoldFactor() context = FactorContext( symbol="AAPL", current_price=150.0, data={}, timestamp=datetime.now(), ) result = factor.evaluate(context) assert result is not None