Implement comprehensive chart configuration and validation system - Introduced a modular chart configuration system in `components/charts/config/` to manage indicator definitions, default configurations, and strategy-specific setups. - Added new modules for error handling and validation, enhancing user guidance and error reporting capabilities. - Implemented detailed schema validation for indicators and strategies, ensuring robust configuration management. - Created example strategies and default configurations to facilitate user onboarding and usage. - Enhanced documentation to provide clear guidelines on the configuration system, validation rules, and usage examples. - Added unit tests for all new components to ensure functionality and reliability across the configuration system.
366 lines
14 KiB
Python
366 lines
14 KiB
Python
"""
|
|
Tests for Default Indicator Configurations System
|
|
|
|
Tests the comprehensive default indicator configurations, categories,
|
|
trading strategies, and preset management functionality.
|
|
"""
|
|
|
|
import pytest
|
|
from typing import Dict, Any
|
|
|
|
from components.charts.config.defaults import (
|
|
IndicatorCategory,
|
|
TradingStrategy,
|
|
IndicatorPreset,
|
|
CATEGORY_COLORS,
|
|
create_trend_indicators,
|
|
create_momentum_indicators,
|
|
create_volatility_indicators,
|
|
create_strategy_presets,
|
|
get_all_default_indicators,
|
|
get_indicators_by_category,
|
|
get_indicators_for_timeframe,
|
|
get_strategy_indicators,
|
|
get_strategy_info,
|
|
get_available_strategies,
|
|
get_available_categories,
|
|
create_custom_preset
|
|
)
|
|
|
|
from components.charts.config.indicator_defs import (
|
|
ChartIndicatorConfig,
|
|
validate_indicator_configuration
|
|
)
|
|
|
|
|
|
class TestIndicatorCategories:
|
|
"""Test indicator category functionality."""
|
|
|
|
def test_trend_indicators_creation(self):
|
|
"""Test creation of trend indicators."""
|
|
trend_indicators = create_trend_indicators()
|
|
|
|
# Should have multiple SMA and EMA configurations
|
|
assert len(trend_indicators) > 10
|
|
|
|
# Check specific indicators exist
|
|
assert "sma_20" in trend_indicators
|
|
assert "sma_50" in trend_indicators
|
|
assert "ema_12" in trend_indicators
|
|
assert "ema_26" in trend_indicators
|
|
|
|
# Validate all configurations
|
|
for name, preset in trend_indicators.items():
|
|
assert isinstance(preset, IndicatorPreset)
|
|
assert preset.category == IndicatorCategory.TREND
|
|
|
|
# Validate the actual configuration
|
|
is_valid, errors = validate_indicator_configuration(preset.config)
|
|
assert is_valid, f"Invalid trend indicator {name}: {errors}"
|
|
|
|
def test_momentum_indicators_creation(self):
|
|
"""Test creation of momentum indicators."""
|
|
momentum_indicators = create_momentum_indicators()
|
|
|
|
# Should have multiple RSI and MACD configurations
|
|
assert len(momentum_indicators) > 8
|
|
|
|
# Check specific indicators exist
|
|
assert "rsi_14" in momentum_indicators
|
|
assert "macd_12_26_9" in momentum_indicators
|
|
|
|
# Validate all configurations
|
|
for name, preset in momentum_indicators.items():
|
|
assert isinstance(preset, IndicatorPreset)
|
|
assert preset.category == IndicatorCategory.MOMENTUM
|
|
|
|
is_valid, errors = validate_indicator_configuration(preset.config)
|
|
assert is_valid, f"Invalid momentum indicator {name}: {errors}"
|
|
|
|
def test_volatility_indicators_creation(self):
|
|
"""Test creation of volatility indicators."""
|
|
volatility_indicators = create_volatility_indicators()
|
|
|
|
# Should have multiple Bollinger Bands configurations
|
|
assert len(volatility_indicators) > 3
|
|
|
|
# Check specific indicators exist
|
|
assert "bb_20_20" in volatility_indicators
|
|
|
|
# Validate all configurations
|
|
for name, preset in volatility_indicators.items():
|
|
assert isinstance(preset, IndicatorPreset)
|
|
assert preset.category == IndicatorCategory.VOLATILITY
|
|
|
|
is_valid, errors = validate_indicator_configuration(preset.config)
|
|
assert is_valid, f"Invalid volatility indicator {name}: {errors}"
|
|
|
|
|
|
class TestStrategyPresets:
|
|
"""Test trading strategy preset functionality."""
|
|
|
|
def test_strategy_presets_creation(self):
|
|
"""Test creation of strategy presets."""
|
|
strategy_presets = create_strategy_presets()
|
|
|
|
# Should have all strategy types
|
|
expected_strategies = [strategy.value for strategy in TradingStrategy]
|
|
for strategy in expected_strategies:
|
|
assert strategy in strategy_presets
|
|
|
|
preset = strategy_presets[strategy]
|
|
assert "name" in preset
|
|
assert "description" in preset
|
|
assert "timeframes" in preset
|
|
assert "indicators" in preset
|
|
assert len(preset["indicators"]) > 0
|
|
|
|
def test_get_strategy_indicators(self):
|
|
"""Test getting indicators for specific strategies."""
|
|
scalping_indicators = get_strategy_indicators(TradingStrategy.SCALPING)
|
|
assert len(scalping_indicators) > 0
|
|
assert "ema_5" in scalping_indicators
|
|
assert "rsi_7" in scalping_indicators
|
|
|
|
day_trading_indicators = get_strategy_indicators(TradingStrategy.DAY_TRADING)
|
|
assert len(day_trading_indicators) > 0
|
|
assert "sma_20" in day_trading_indicators
|
|
assert "rsi_14" in day_trading_indicators
|
|
|
|
def test_get_strategy_info(self):
|
|
"""Test getting complete strategy information."""
|
|
scalping_info = get_strategy_info(TradingStrategy.SCALPING)
|
|
assert "name" in scalping_info
|
|
assert "description" in scalping_info
|
|
assert "timeframes" in scalping_info
|
|
assert "indicators" in scalping_info
|
|
assert "1m" in scalping_info["timeframes"]
|
|
assert "5m" in scalping_info["timeframes"]
|
|
|
|
|
|
class TestDefaultIndicators:
|
|
"""Test default indicator functionality."""
|
|
|
|
def test_get_all_default_indicators(self):
|
|
"""Test getting all default indicators."""
|
|
all_indicators = get_all_default_indicators()
|
|
|
|
# Should have indicators from all categories
|
|
assert len(all_indicators) > 20
|
|
|
|
# Validate all indicators
|
|
for name, preset in all_indicators.items():
|
|
assert isinstance(preset, IndicatorPreset)
|
|
assert preset.category in [cat for cat in IndicatorCategory]
|
|
|
|
is_valid, errors = validate_indicator_configuration(preset.config)
|
|
assert is_valid, f"Invalid default indicator {name}: {errors}"
|
|
|
|
def test_get_indicators_by_category(self):
|
|
"""Test filtering indicators by category."""
|
|
trend_indicators = get_indicators_by_category(IndicatorCategory.TREND)
|
|
momentum_indicators = get_indicators_by_category(IndicatorCategory.MOMENTUM)
|
|
volatility_indicators = get_indicators_by_category(IndicatorCategory.VOLATILITY)
|
|
|
|
# All should have indicators
|
|
assert len(trend_indicators) > 0
|
|
assert len(momentum_indicators) > 0
|
|
assert len(volatility_indicators) > 0
|
|
|
|
# Check categories are correct
|
|
for preset in trend_indicators.values():
|
|
assert preset.category == IndicatorCategory.TREND
|
|
|
|
for preset in momentum_indicators.values():
|
|
assert preset.category == IndicatorCategory.MOMENTUM
|
|
|
|
for preset in volatility_indicators.values():
|
|
assert preset.category == IndicatorCategory.VOLATILITY
|
|
|
|
def test_get_indicators_for_timeframe(self):
|
|
"""Test filtering indicators by timeframe."""
|
|
scalping_indicators = get_indicators_for_timeframe("1m")
|
|
day_trading_indicators = get_indicators_for_timeframe("1h")
|
|
position_indicators = get_indicators_for_timeframe("1d")
|
|
|
|
# All should have some indicators
|
|
assert len(scalping_indicators) > 0
|
|
assert len(day_trading_indicators) > 0
|
|
assert len(position_indicators) > 0
|
|
|
|
# Check timeframes are included
|
|
for preset in scalping_indicators.values():
|
|
assert "1m" in preset.recommended_timeframes
|
|
|
|
for preset in day_trading_indicators.values():
|
|
assert "1h" in preset.recommended_timeframes
|
|
|
|
|
|
class TestUtilityFunctions:
|
|
"""Test utility functions for defaults system."""
|
|
|
|
def test_get_available_strategies(self):
|
|
"""Test getting available trading strategies."""
|
|
strategies = get_available_strategies()
|
|
|
|
# Should have all strategy types
|
|
assert len(strategies) == len(TradingStrategy)
|
|
|
|
for strategy in strategies:
|
|
assert "value" in strategy
|
|
assert "name" in strategy
|
|
assert "description" in strategy
|
|
assert "timeframes" in strategy
|
|
|
|
def test_get_available_categories(self):
|
|
"""Test getting available indicator categories."""
|
|
categories = get_available_categories()
|
|
|
|
# Should have all category types
|
|
assert len(categories) == len(IndicatorCategory)
|
|
|
|
for category in categories:
|
|
assert "value" in category
|
|
assert "name" in category
|
|
assert "description" in category
|
|
|
|
def test_create_custom_preset(self):
|
|
"""Test creating custom indicator presets."""
|
|
custom_configs = [
|
|
{
|
|
"name": "Custom SMA",
|
|
"indicator_type": "sma",
|
|
"parameters": {"period": 15},
|
|
"color": "#123456"
|
|
},
|
|
{
|
|
"name": "Custom RSI",
|
|
"indicator_type": "rsi",
|
|
"parameters": {"period": 10},
|
|
"color": "#654321"
|
|
}
|
|
]
|
|
|
|
custom_presets = create_custom_preset(
|
|
name="Test Custom",
|
|
description="Test custom preset",
|
|
category=IndicatorCategory.TREND,
|
|
indicator_configs=custom_configs,
|
|
recommended_timeframes=["5m", "15m"]
|
|
)
|
|
|
|
# Should create presets for valid configurations
|
|
assert len(custom_presets) == 2
|
|
|
|
for preset in custom_presets.values():
|
|
assert preset.category == IndicatorCategory.TREND
|
|
assert "5m" in preset.recommended_timeframes
|
|
assert "15m" in preset.recommended_timeframes
|
|
|
|
|
|
class TestColorSchemes:
|
|
"""Test color scheme functionality."""
|
|
|
|
def test_category_colors_exist(self):
|
|
"""Test that color schemes exist for categories."""
|
|
required_categories = [
|
|
IndicatorCategory.TREND,
|
|
IndicatorCategory.MOMENTUM,
|
|
IndicatorCategory.VOLATILITY
|
|
]
|
|
|
|
for category in required_categories:
|
|
assert category in CATEGORY_COLORS
|
|
colors = CATEGORY_COLORS[category]
|
|
|
|
# Should have multiple color options
|
|
assert "primary" in colors
|
|
assert "secondary" in colors
|
|
assert "tertiary" in colors
|
|
assert "quaternary" in colors
|
|
|
|
# Colors should be valid hex codes
|
|
for color_name, color_value in colors.items():
|
|
assert color_value.startswith("#")
|
|
assert len(color_value) == 7
|
|
|
|
|
|
class TestIntegration:
|
|
"""Test integration with existing systems."""
|
|
|
|
def test_default_indicators_match_schema(self):
|
|
"""Test that default indicators match their schemas."""
|
|
all_indicators = get_all_default_indicators()
|
|
|
|
for name, preset in all_indicators.items():
|
|
config = preset.config
|
|
|
|
# Should validate against schema
|
|
is_valid, errors = validate_indicator_configuration(config)
|
|
assert is_valid, f"Default indicator {name} validation failed: {errors}"
|
|
|
|
def test_strategy_indicators_exist_in_defaults(self):
|
|
"""Test that strategy indicators exist in default configurations."""
|
|
all_indicators = get_all_default_indicators()
|
|
|
|
for strategy in TradingStrategy:
|
|
strategy_indicators = get_strategy_indicators(strategy)
|
|
|
|
for indicator_name in strategy_indicators:
|
|
# Each strategy indicator should exist in defaults
|
|
# Note: Some might not exist yet, but most should
|
|
if indicator_name in all_indicators:
|
|
preset = all_indicators[indicator_name]
|
|
assert isinstance(preset, IndicatorPreset)
|
|
|
|
def test_timeframe_recommendations_valid(self):
|
|
"""Test that timeframe recommendations are valid."""
|
|
all_indicators = get_all_default_indicators()
|
|
valid_timeframes = ["1m", "5m", "15m", "1h", "4h", "1d", "1w"]
|
|
|
|
for name, preset in all_indicators.items():
|
|
for timeframe in preset.recommended_timeframes:
|
|
assert timeframe in valid_timeframes, f"Invalid timeframe {timeframe} for {name}"
|
|
|
|
|
|
class TestPresetValidation:
|
|
"""Test that all presets are properly validated."""
|
|
|
|
def test_all_trend_indicators_valid(self):
|
|
"""Test that all trend indicators are valid."""
|
|
trend_indicators = create_trend_indicators()
|
|
|
|
for name, preset in trend_indicators.items():
|
|
# Test the preset structure
|
|
assert isinstance(preset.name, str)
|
|
assert isinstance(preset.description, str)
|
|
assert preset.category == IndicatorCategory.TREND
|
|
assert isinstance(preset.recommended_timeframes, list)
|
|
assert len(preset.recommended_timeframes) > 0
|
|
|
|
# Test the configuration
|
|
config = preset.config
|
|
is_valid, errors = validate_indicator_configuration(config)
|
|
assert is_valid, f"Trend indicator {name} failed validation: {errors}"
|
|
|
|
def test_all_momentum_indicators_valid(self):
|
|
"""Test that all momentum indicators are valid."""
|
|
momentum_indicators = create_momentum_indicators()
|
|
|
|
for name, preset in momentum_indicators.items():
|
|
config = preset.config
|
|
is_valid, errors = validate_indicator_configuration(config)
|
|
assert is_valid, f"Momentum indicator {name} failed validation: {errors}"
|
|
|
|
def test_all_volatility_indicators_valid(self):
|
|
"""Test that all volatility indicators are valid."""
|
|
volatility_indicators = create_volatility_indicators()
|
|
|
|
for name, preset in volatility_indicators.items():
|
|
config = preset.config
|
|
is_valid, errors = validate_indicator_configuration(config)
|
|
assert is_valid, f"Volatility indicator {name} failed validation: {errors}"
|
|
|
|
|
|
if __name__ == "__main__":
|
|
pytest.main([__file__]) |