167 lines
5.4 KiB
Python
167 lines
5.4 KiB
Python
|
|
"""
|
||
|
|
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
|