""" Utility functions for loading and managing indicator configurations. """ import json import os import logging from typing import List, Dict, Any, Optional logger = logging.getLogger(__name__) def load_indicator_templates() -> Dict[str, Dict[str, Any]]: """Load all indicator templates from the templates directory. Returns: Dict[str, Dict[str, Any]]: Dictionary mapping indicator type to template configuration """ templates = {} try: # Get the templates directory path templates_dir = os.path.join(os.path.dirname(__file__), 'templates') if not os.path.exists(templates_dir): logger.error(f"Templates directory not found at {templates_dir}") return {} # Load all JSON files from templates directory for filename in os.listdir(templates_dir): if filename.endswith('_template.json'): file_path = os.path.join(templates_dir, filename) try: with open(file_path, 'r', encoding='utf-8') as f: template = json.load(f) indicator_type = template.get('type') if indicator_type: templates[indicator_type] = template else: logger.warning(f"Template {filename} missing 'type' field") except json.JSONDecodeError as e: logger.error(f"Error decoding JSON from {filename}: {e}") except Exception as e: logger.error(f"Error loading template {filename}: {e}") except Exception as e: logger.error(f"Error loading indicator templates: {e}") return templates def get_indicator_dropdown_options() -> List[Dict[str, str]]: """Generate dropdown options for indicator types from templates. Returns: List[Dict[str, str]]: List of dropdown options with label and value """ templates = load_indicator_templates() options = [] for indicator_type, template in templates.items(): option = { 'label': template.get('name', indicator_type.upper()), 'value': indicator_type } options.append(option) # Sort by label for consistent UI options.sort(key=lambda x: x['label']) return options def get_indicator_parameter_schema(indicator_type: str) -> Optional[Dict[str, Any]]: """Get parameter schema for a specific indicator type. Args: indicator_type (str): The indicator type (e.g., 'sma', 'ema') Returns: Optional[Dict[str, Any]]: Parameter schema or None if not found """ templates = load_indicator_templates() template = templates.get(indicator_type) if template: return template.get('parameter_schema', {}) return None def get_indicator_default_parameters(indicator_type: str) -> Optional[Dict[str, Any]]: """Get default parameters for a specific indicator type. Args: indicator_type (str): The indicator type (e.g., 'sma', 'ema') Returns: Optional[Dict[str, Any]]: Default parameters or None if not found """ templates = load_indicator_templates() template = templates.get(indicator_type) if template: return template.get('default_parameters', {}) return None def get_indicator_default_styling(indicator_type: str) -> Optional[Dict[str, Any]]: """Get default styling for a specific indicator type. Args: indicator_type (str): The indicator type (e.g., 'sma', 'ema') Returns: Optional[Dict[str, Any]]: Default styling or None if not found """ templates = load_indicator_templates() template = templates.get(indicator_type) if template: return template.get('default_styling', {}) return None def generate_parameter_fields_config(indicator_type: str) -> Optional[Dict[str, Any]]: """Generate parameter field configuration for dynamic UI generation. Args: indicator_type (str): The indicator type (e.g., 'sma', 'ema') Returns: Optional[Dict[str, Any]]: Configuration for generating parameter input fields """ schema = get_indicator_parameter_schema(indicator_type) defaults = get_indicator_default_parameters(indicator_type) if not schema or not defaults: return None fields_config = {} for param_name, param_schema in schema.items(): # Skip timeframe as it's handled separately in the modal if param_name == 'timeframe': continue field_config = { 'type': param_schema.get('type', 'int'), 'label': param_name.replace('_', ' ').title(), 'default': defaults.get(param_name, param_schema.get('default')), 'description': param_schema.get('description', ''), 'input_id': f'{indicator_type}-{param_name.replace("_", "-")}-input' } # Add validation constraints if present if 'min' in param_schema: field_config['min'] = param_schema['min'] if 'max' in param_schema: field_config['max'] = param_schema['max'] if 'step' in param_schema: field_config['step'] = param_schema['step'] fields_config[param_name] = field_config return fields_config