""" Tests for Example Strategy Configurations Tests the example trading strategies including EMA crossover, momentum, mean reversion, scalping, and swing trading strategies. """ import pytest import json from typing import Dict, List from components.charts.config.example_strategies import ( StrategyExample, create_ema_crossover_strategy, create_momentum_breakout_strategy, create_mean_reversion_strategy, create_scalping_strategy, create_swing_trading_strategy, get_all_example_strategies, get_example_strategy, get_strategies_by_difficulty, get_strategies_by_risk_level, get_strategies_by_market_condition, get_strategy_summary, export_example_strategies_to_json ) from components.charts.config.strategy_charts import StrategyChartConfig from components.charts.config.defaults import TradingStrategy class TestStrategyExample: """Test StrategyExample dataclass.""" def test_strategy_example_creation(self): """Test StrategyExample creation with defaults.""" # Create a minimal config for testing config = StrategyChartConfig( strategy_name="Test Strategy", strategy_type=TradingStrategy.DAY_TRADING, description="Test strategy", timeframes=["1h"] ) example = StrategyExample( config=config, description="Test description" ) assert example.config == config assert example.description == "Test description" assert example.author == "TCPDashboard" assert example.difficulty == "Beginner" assert example.risk_level == "Medium" assert example.market_conditions == ["Trending"] # Default assert example.notes == [] # Default assert example.references == [] # Default def test_strategy_example_with_custom_values(self): """Test StrategyExample with custom values.""" config = StrategyChartConfig( strategy_name="Custom Strategy", strategy_type=TradingStrategy.SCALPING, description="Custom strategy", timeframes=["1m"] ) example = StrategyExample( config=config, description="Custom description", author="Custom Author", difficulty="Advanced", expected_return="10% monthly", risk_level="High", market_conditions=["Volatile", "High Volume"], notes=["Note 1", "Note 2"], references=["Reference 1"] ) assert example.author == "Custom Author" assert example.difficulty == "Advanced" assert example.expected_return == "10% monthly" assert example.risk_level == "High" assert example.market_conditions == ["Volatile", "High Volume"] assert example.notes == ["Note 1", "Note 2"] assert example.references == ["Reference 1"] class TestEMACrossoverStrategy: """Test EMA Crossover strategy.""" def test_ema_crossover_creation(self): """Test EMA crossover strategy creation.""" strategy = create_ema_crossover_strategy() assert isinstance(strategy, StrategyExample) assert isinstance(strategy.config, StrategyChartConfig) # Check strategy specifics assert strategy.config.strategy_name == "EMA Crossover Strategy" assert strategy.config.strategy_type == TradingStrategy.DAY_TRADING assert "15m" in strategy.config.timeframes assert "1h" in strategy.config.timeframes assert "4h" in strategy.config.timeframes # Check indicators assert "ema_12" in strategy.config.overlay_indicators assert "ema_26" in strategy.config.overlay_indicators assert "ema_50" in strategy.config.overlay_indicators assert "bb_20_20" in strategy.config.overlay_indicators # Check subplots assert len(strategy.config.subplot_configs) == 2 assert any(subplot.subplot_type.value == "rsi" for subplot in strategy.config.subplot_configs) assert any(subplot.subplot_type.value == "macd" for subplot in strategy.config.subplot_configs) # Check metadata assert strategy.difficulty == "Intermediate" assert strategy.risk_level == "Medium" assert "Trending" in strategy.market_conditions assert len(strategy.notes) > 0 assert len(strategy.references) > 0 def test_ema_crossover_validation(self): """Test EMA crossover strategy validation.""" strategy = create_ema_crossover_strategy() is_valid, errors = strategy.config.validate() # Strategy should be valid or have minimal issues assert isinstance(is_valid, bool) assert isinstance(errors, list) class TestMomentumBreakoutStrategy: """Test Momentum Breakout strategy.""" def test_momentum_breakout_creation(self): """Test momentum breakout strategy creation.""" strategy = create_momentum_breakout_strategy() assert isinstance(strategy, StrategyExample) assert strategy.config.strategy_name == "Momentum Breakout Strategy" assert strategy.config.strategy_type == TradingStrategy.MOMENTUM # Check for momentum-specific indicators assert "ema_8" in strategy.config.overlay_indicators assert "ema_21" in strategy.config.overlay_indicators assert "bb_20_25" in strategy.config.overlay_indicators # Check for fast indicators rsi_subplot = next((s for s in strategy.config.subplot_configs if s.subplot_type.value == "rsi"), None) assert rsi_subplot is not None assert "rsi_7" in rsi_subplot.indicators assert "rsi_14" in rsi_subplot.indicators # Check volume subplot volume_subplot = next((s for s in strategy.config.subplot_configs if s.subplot_type.value == "volume"), None) assert volume_subplot is not None # Check metadata assert strategy.difficulty == "Advanced" assert strategy.risk_level == "High" assert "Volatile" in strategy.market_conditions class TestMeanReversionStrategy: """Test Mean Reversion strategy.""" def test_mean_reversion_creation(self): """Test mean reversion strategy creation.""" strategy = create_mean_reversion_strategy() assert isinstance(strategy, StrategyExample) assert strategy.config.strategy_name == "Mean Reversion Strategy" assert strategy.config.strategy_type == TradingStrategy.MEAN_REVERSION # Check for mean reversion indicators assert "sma_20" in strategy.config.overlay_indicators assert "sma_50" in strategy.config.overlay_indicators assert "bb_20_20" in strategy.config.overlay_indicators assert "bb_20_15" in strategy.config.overlay_indicators # Check RSI configurations rsi_subplot = next((s for s in strategy.config.subplot_configs if s.subplot_type.value == "rsi"), None) assert rsi_subplot is not None assert "rsi_14" in rsi_subplot.indicators assert "rsi_21" in rsi_subplot.indicators # Check metadata assert strategy.difficulty == "Intermediate" assert strategy.risk_level == "Medium" assert "Sideways" in strategy.market_conditions class TestScalpingStrategy: """Test Scalping strategy.""" def test_scalping_creation(self): """Test scalping strategy creation.""" strategy = create_scalping_strategy() assert isinstance(strategy, StrategyExample) assert strategy.config.strategy_name == "Scalping Strategy" assert strategy.config.strategy_type == TradingStrategy.SCALPING # Check fast timeframes assert "1m" in strategy.config.timeframes assert "5m" in strategy.config.timeframes # Check very fast indicators assert "ema_5" in strategy.config.overlay_indicators assert "ema_12" in strategy.config.overlay_indicators assert "ema_21" in strategy.config.overlay_indicators # Check fast RSI rsi_subplot = next((s for s in strategy.config.subplot_configs if s.subplot_type.value == "rsi"), None) assert rsi_subplot is not None assert "rsi_7" in rsi_subplot.indicators # Check metadata assert strategy.difficulty == "Advanced" assert strategy.risk_level == "High" assert "High Liquidity" in strategy.market_conditions class TestSwingTradingStrategy: """Test Swing Trading strategy.""" def test_swing_trading_creation(self): """Test swing trading strategy creation.""" strategy = create_swing_trading_strategy() assert isinstance(strategy, StrategyExample) assert strategy.config.strategy_name == "Swing Trading Strategy" assert strategy.config.strategy_type == TradingStrategy.SWING_TRADING # Check longer timeframes assert "4h" in strategy.config.timeframes assert "1d" in strategy.config.timeframes # Check swing trading indicators assert "sma_20" in strategy.config.overlay_indicators assert "sma_50" in strategy.config.overlay_indicators assert "ema_21" in strategy.config.overlay_indicators assert "bb_20_20" in strategy.config.overlay_indicators # Check metadata assert strategy.difficulty == "Beginner" assert strategy.risk_level == "Medium" assert "Trending" in strategy.market_conditions class TestStrategyAccessors: """Test strategy accessor functions.""" def test_get_all_example_strategies(self): """Test getting all example strategies.""" strategies = get_all_example_strategies() assert isinstance(strategies, dict) assert len(strategies) == 5 # Should have 5 strategies expected_strategies = [ "ema_crossover", "momentum_breakout", "mean_reversion", "scalping", "swing_trading" ] for strategy_name in expected_strategies: assert strategy_name in strategies assert isinstance(strategies[strategy_name], StrategyExample) def test_get_example_strategy(self): """Test getting a specific example strategy.""" # Test existing strategy ema_strategy = get_example_strategy("ema_crossover") assert ema_strategy is not None assert isinstance(ema_strategy, StrategyExample) assert ema_strategy.config.strategy_name == "EMA Crossover Strategy" # Test non-existing strategy non_existent = get_example_strategy("non_existent_strategy") assert non_existent is None def test_get_strategies_by_difficulty(self): """Test filtering strategies by difficulty.""" # Test beginner strategies beginner_strategies = get_strategies_by_difficulty("Beginner") assert isinstance(beginner_strategies, list) assert len(beginner_strategies) > 0 for strategy in beginner_strategies: assert strategy.difficulty == "Beginner" # Test intermediate strategies intermediate_strategies = get_strategies_by_difficulty("Intermediate") assert isinstance(intermediate_strategies, list) assert len(intermediate_strategies) > 0 for strategy in intermediate_strategies: assert strategy.difficulty == "Intermediate" # Test advanced strategies advanced_strategies = get_strategies_by_difficulty("Advanced") assert isinstance(advanced_strategies, list) assert len(advanced_strategies) > 0 for strategy in advanced_strategies: assert strategy.difficulty == "Advanced" # Test non-existent difficulty empty_strategies = get_strategies_by_difficulty("Expert") assert isinstance(empty_strategies, list) assert len(empty_strategies) == 0 def test_get_strategies_by_risk_level(self): """Test filtering strategies by risk level.""" # Test medium risk strategies medium_risk = get_strategies_by_risk_level("Medium") assert isinstance(medium_risk, list) assert len(medium_risk) > 0 for strategy in medium_risk: assert strategy.risk_level == "Medium" # Test high risk strategies high_risk = get_strategies_by_risk_level("High") assert isinstance(high_risk, list) assert len(high_risk) > 0 for strategy in high_risk: assert strategy.risk_level == "High" # Test non-existent risk level empty_strategies = get_strategies_by_risk_level("Ultra High") assert isinstance(empty_strategies, list) assert len(empty_strategies) == 0 def test_get_strategies_by_market_condition(self): """Test filtering strategies by market condition.""" # Test trending market strategies trending_strategies = get_strategies_by_market_condition("Trending") assert isinstance(trending_strategies, list) assert len(trending_strategies) > 0 for strategy in trending_strategies: assert "Trending" in strategy.market_conditions # Test volatile market strategies volatile_strategies = get_strategies_by_market_condition("Volatile") assert isinstance(volatile_strategies, list) assert len(volatile_strategies) > 0 for strategy in volatile_strategies: assert "Volatile" in strategy.market_conditions # Test sideways market strategies sideways_strategies = get_strategies_by_market_condition("Sideways") assert isinstance(sideways_strategies, list) assert len(sideways_strategies) > 0 for strategy in sideways_strategies: assert "Sideways" in strategy.market_conditions class TestStrategyUtilities: """Test strategy utility functions.""" def test_get_strategy_summary(self): """Test getting strategy summary.""" summary = get_strategy_summary() assert isinstance(summary, dict) assert len(summary) == 5 # Should have 5 strategies # Check summary structure for strategy_name, strategy_info in summary.items(): assert isinstance(strategy_info, dict) required_fields = [ "name", "type", "difficulty", "risk_level", "timeframes", "market_conditions", "expected_return" ] for field in required_fields: assert field in strategy_info assert isinstance(strategy_info[field], str) # Check specific strategy assert "ema_crossover" in summary ema_summary = summary["ema_crossover"] assert ema_summary["name"] == "EMA Crossover Strategy" assert ema_summary["type"] == "day_trading" assert ema_summary["difficulty"] == "Intermediate" def test_export_example_strategies_to_json(self): """Test exporting strategies to JSON.""" json_str = export_example_strategies_to_json() # Should be valid JSON data = json.loads(json_str) assert isinstance(data, dict) assert len(data) == 5 # Should have 5 strategies # Check structure for strategy_name, strategy_data in data.items(): assert "config" in strategy_data assert "metadata" in strategy_data # Check config structure config = strategy_data["config"] assert "strategy_name" in config assert "strategy_type" in config assert "timeframes" in config # Check metadata structure metadata = strategy_data["metadata"] assert "description" in metadata assert "author" in metadata assert "difficulty" in metadata assert "risk_level" in metadata # Check specific strategy assert "ema_crossover" in data ema_data = data["ema_crossover"] assert ema_data["config"]["strategy_name"] == "EMA Crossover Strategy" assert ema_data["metadata"]["difficulty"] == "Intermediate" class TestStrategyValidation: """Test validation of example strategies.""" def test_all_strategies_have_required_fields(self): """Test that all strategies have required fields.""" strategies = get_all_example_strategies() for strategy_name, strategy in strategies.items(): # Check StrategyExample fields assert strategy.config is not None assert strategy.description is not None assert strategy.author is not None assert strategy.difficulty in ["Beginner", "Intermediate", "Advanced"] assert strategy.risk_level in ["Low", "Medium", "High"] assert isinstance(strategy.market_conditions, list) assert isinstance(strategy.notes, list) assert isinstance(strategy.references, list) # Check StrategyChartConfig fields config = strategy.config assert config.strategy_name is not None assert config.strategy_type is not None assert isinstance(config.timeframes, list) assert len(config.timeframes) > 0 assert isinstance(config.overlay_indicators, list) assert isinstance(config.subplot_configs, list) def test_strategy_configurations_are_valid(self): """Test that all strategy configurations are valid.""" strategies = get_all_example_strategies() for strategy_name, strategy in strategies.items(): # Test basic validation is_valid, errors = strategy.config.validate() # Should be valid or have minimal issues (like missing indicators in test environment) assert isinstance(is_valid, bool) assert isinstance(errors, list) # If there are errors, they should be reasonable (like missing indicators) if not is_valid: for error in errors: # Common acceptable errors in test environment acceptable_errors = [ "not found in defaults", # Missing indicators "not found", # Missing indicators ] assert any(acceptable in error for acceptable in acceptable_errors), \ f"Unexpected error in {strategy_name}: {error}" def test_strategy_timeframes_match_types(self): """Test that strategy timeframes match their types.""" strategies = get_all_example_strategies() # Expected timeframes for different strategy types expected_timeframes = { TradingStrategy.SCALPING: ["1m", "5m"], TradingStrategy.DAY_TRADING: ["5m", "15m", "1h", "4h"], TradingStrategy.SWING_TRADING: ["1h", "4h", "1d"], TradingStrategy.MOMENTUM: ["5m", "15m", "1h"], TradingStrategy.MEAN_REVERSION: ["15m", "1h", "4h"] } for strategy_name, strategy in strategies.items(): strategy_type = strategy.config.strategy_type timeframes = strategy.config.timeframes if strategy_type in expected_timeframes: expected = expected_timeframes[strategy_type] # Should have some overlap with expected timeframes overlap = set(timeframes) & set(expected) assert len(overlap) > 0, \ f"Strategy {strategy_name} timeframes {timeframes} don't match type {strategy_type}" class TestStrategyIntegration: """Test integration with other systems.""" def test_strategy_configs_work_with_validation(self): """Test that strategy configs work with validation system.""" from components.charts.config.validation import validate_configuration strategies = get_all_example_strategies() for strategy_name, strategy in strategies.items(): try: report = validate_configuration(strategy.config) assert hasattr(report, 'is_valid') assert hasattr(report, 'errors') assert hasattr(report, 'warnings') except Exception as e: pytest.fail(f"Validation failed for {strategy_name}: {e}") def test_strategy_json_roundtrip(self): """Test JSON export and import roundtrip.""" from components.charts.config.strategy_charts import ( export_strategy_config_to_json, load_strategy_config_from_json ) # Test one strategy for roundtrip original_strategy = create_ema_crossover_strategy() # Export to JSON json_str = export_strategy_config_to_json(original_strategy.config) # Import from JSON loaded_config, errors = load_strategy_config_from_json(json_str) if loaded_config: # Compare key fields assert loaded_config.strategy_name == original_strategy.config.strategy_name assert loaded_config.strategy_type == original_strategy.config.strategy_type assert loaded_config.timeframes == original_strategy.config.timeframes assert loaded_config.overlay_indicators == original_strategy.config.overlay_indicators if __name__ == "__main__": pytest.main([__file__])