""" Indicator modal component for creating and editing indicators. """ from dash import html, dcc import dash_bootstrap_components as dbc from utils.timeframe_utils import load_timeframe_options from config.indicators.config_utils import get_indicator_dropdown_options, generate_parameter_fields_config def create_dynamic_parameter_fields(indicator_type: str) -> html.Div: """Create parameter input fields dynamically based on indicator configuration. Args: indicator_type (str): The indicator type (e.g., 'sma', 'ema') Returns: html.Div: Div containing the parameter input fields """ fields_config = generate_parameter_fields_config(indicator_type) if not fields_config: return html.Div( html.P("No parameters available for this indicator", className="text-muted fst-italic"), id=f'{indicator_type}-parameters', style={'display': 'none'}, className="mb-3" ) field_elements = [] # Handle single parameter (like SMA, EMA, RSI) if len(fields_config) == 1: param_name, field_config = next(iter(fields_config.items())) field_elements.append( html.Div([ dbc.Label(f"{field_config['label']}:"), dcc.Input( id=field_config['input_id'], type='number', value=field_config['default'], min=field_config.get('min'), max=field_config.get('max'), step=field_config.get('step', 1 if field_config['type'] == 'int' else 0.1) ), dbc.FormText(field_config['description']) if field_config['description'] else None ]) ) else: # Handle multiple parameters (like MACD, Bollinger Bands) rows = [] params_per_row = min(len(fields_config), 4) # Max 4 parameters per row param_items = list(fields_config.items()) for i in range(0, len(param_items), params_per_row): row_params = param_items[i:i + params_per_row] cols = [] for param_name, field_config in row_params: col = dbc.Col([ dbc.Label(f"{field_config['label']}:"), dcc.Input( id=field_config['input_id'], type='number', value=field_config['default'], min=field_config.get('min'), max=field_config.get('max'), step=field_config.get('step', 1 if field_config['type'] == 'int' else 0.1) ) ], width=12 // len(row_params)) cols.append(col) rows.append(dbc.Row(cols)) field_elements.extend(rows) # Add description for multi-parameter indicators if any(config['description'] for config in fields_config.values()): descriptions = [f"{config['label']}: {config['description']}" for config in fields_config.values() if config['description']] field_elements.append( dbc.FormText("; ".join(descriptions)) ) return html.Div( field_elements, id=f'{indicator_type}-parameters', style={'display': 'none'}, className="mb-3" ) def create_indicator_modal(): """Create the indicator modal dialog for adding/editing indicators.""" return html.Div([ dcc.Store(id='edit-indicator-store', data=None), dbc.Modal([ dbc.ModalHeader(dbc.ModalTitle("📊 Add New Indicator", id="modal-title")), dbc.ModalBody([ # Basic Settings html.H5("Basic Settings"), dbc.Row([ dbc.Col(dbc.Label("Indicator Name:"), width=12), dbc.Col(dcc.Input(id='indicator-name-input', type='text', placeholder='e.g., "SMA 30 Custom"', className="w-100"), width=12) ], className="mb-3"), dbc.Row([ dbc.Col(dbc.Label("Indicator Type:"), width=12), dbc.Col(dcc.Dropdown( id='indicator-type-dropdown', options=get_indicator_dropdown_options(), placeholder='Select indicator type', ), width=12) ], className="mb-3"), dbc.Row([ dbc.Col(dbc.Label("Timeframe (Optional):"), width=12), dbc.Col(dcc.Dropdown( id='indicator-timeframe-dropdown', options=[{'label': 'Chart Timeframe', 'value': ''}] + load_timeframe_options(), value='', placeholder='Defaults to chart timeframe' ), width=12), ], className="mb-3"), dbc.Row([ dbc.Col(dbc.Label("Description (Optional):"), width=12), dbc.Col(dcc.Textarea( id='indicator-description-input', placeholder='Brief description of this indicator configuration...', style={'width': '100%', 'height': '60px'} ), width=12) ], className="mb-3"), html.Hr(), # Parameters Section html.H5("Parameters"), html.Div( id='indicator-parameters-message', children=[html.P("Select an indicator type to configure parameters", className="text-muted fst-italic")] ), # Parameter fields (SMA, EMA, etc.) create_dynamic_parameter_fields('sma'), create_dynamic_parameter_fields('ema'), create_dynamic_parameter_fields('rsi'), create_dynamic_parameter_fields('macd'), create_dynamic_parameter_fields('bollinger_bands'), html.Hr(), # Styling Section html.H5("Styling"), dbc.Row([ dbc.Col([ dbc.Label("Color:"), dcc.Input(id='indicator-color-input', type='text', value='#007bff', className="w-100") ], width=6), dbc.Col([ dbc.Label("Line Width:"), dcc.Slider(id='indicator-line-width-slider', min=1, max=5, step=1, value=2, marks={i: str(i) for i in range(1, 6)}) ], width=6) ], className="mb-3"), ]), dbc.ModalFooter([ html.Div(id='save-indicator-feedback', className="me-auto"), dbc.Button("Cancel", id="cancel-indicator-btn", color="secondary"), dbc.Button("Save Indicator", id="save-indicator-btn", color="primary") ]) ], id='indicator-modal', size="lg", is_open=False), ])