2025-06-04 13:30:16 +08:00
|
|
|
|
"""
|
|
|
|
|
|
Chart control components for the market data layout.
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
from dash import html, dcc
|
|
|
|
|
|
from utils.logger import get_logger
|
|
|
|
|
|
|
2025-06-04 17:03:35 +08:00
|
|
|
|
logger = get_logger("default_logger")
|
2025-06-04 13:30:16 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_chart_config_panel(strategy_options, overlay_options, subplot_options):
|
|
|
|
|
|
"""Create the chart configuration panel with add/edit UI."""
|
|
|
|
|
|
return html.Div([
|
|
|
|
|
|
html.H5("🎯 Chart Configuration", style={'color': '#2c3e50', 'margin-bottom': '15px'}),
|
|
|
|
|
|
|
|
|
|
|
|
# Add New Indicator Button
|
|
|
|
|
|
html.Div([
|
|
|
|
|
|
html.Button(
|
|
|
|
|
|
"➕ Add New Indicator",
|
|
|
|
|
|
id="add-indicator-btn-visible",
|
|
|
|
|
|
className="btn btn-primary",
|
|
|
|
|
|
style={
|
|
|
|
|
|
'background-color': '#007bff',
|
|
|
|
|
|
'color': 'white',
|
|
|
|
|
|
'border': 'none',
|
|
|
|
|
|
'padding': '8px 16px',
|
|
|
|
|
|
'border-radius': '4px',
|
|
|
|
|
|
'cursor': 'pointer',
|
|
|
|
|
|
'margin-bottom': '15px',
|
|
|
|
|
|
'font-weight': 'bold'
|
|
|
|
|
|
}
|
|
|
|
|
|
)
|
|
|
|
|
|
]),
|
|
|
|
|
|
|
|
|
|
|
|
# Strategy Selection
|
|
|
|
|
|
html.Div([
|
|
|
|
|
|
html.Label("Strategy Template:", style={'font-weight': 'bold', 'margin-bottom': '5px'}),
|
|
|
|
|
|
dcc.Dropdown(
|
|
|
|
|
|
id='strategy-dropdown',
|
|
|
|
|
|
options=strategy_options,
|
|
|
|
|
|
value=None,
|
|
|
|
|
|
placeholder="Select a strategy template (optional)",
|
|
|
|
|
|
style={'margin-bottom': '15px'}
|
|
|
|
|
|
)
|
|
|
|
|
|
]),
|
|
|
|
|
|
|
|
|
|
|
|
# Indicator Controls with Edit Buttons
|
|
|
|
|
|
html.Div([
|
|
|
|
|
|
# Overlay Indicators
|
|
|
|
|
|
html.Div([
|
|
|
|
|
|
html.Label("Overlay Indicators:", style={'font-weight': 'bold', 'margin-bottom': '10px', 'display': 'block'}),
|
|
|
|
|
|
html.Div([
|
|
|
|
|
|
# Hidden checklist for callback compatibility
|
|
|
|
|
|
dcc.Checklist(
|
|
|
|
|
|
id='overlay-indicators-checklist',
|
|
|
|
|
|
options=overlay_options,
|
|
|
|
|
|
value=[], # Start with no indicators selected
|
|
|
|
|
|
style={'display': 'none'} # Hide the basic checklist
|
|
|
|
|
|
),
|
|
|
|
|
|
# Custom indicator list with edit buttons
|
|
|
|
|
|
html.Div(id='overlay-indicators-list', children=[
|
|
|
|
|
|
# This will be populated dynamically
|
|
|
|
|
|
])
|
|
|
|
|
|
])
|
|
|
|
|
|
], style={'width': '48%', 'display': 'inline-block', 'margin-right': '4%', 'vertical-align': 'top'}),
|
|
|
|
|
|
|
|
|
|
|
|
# Subplot Indicators
|
|
|
|
|
|
html.Div([
|
|
|
|
|
|
html.Label("Subplot Indicators:", style={'font-weight': 'bold', 'margin-bottom': '10px', 'display': 'block'}),
|
|
|
|
|
|
html.Div([
|
|
|
|
|
|
# Hidden checklist for callback compatibility
|
|
|
|
|
|
dcc.Checklist(
|
|
|
|
|
|
id='subplot-indicators-checklist',
|
|
|
|
|
|
options=subplot_options,
|
|
|
|
|
|
value=[], # Start with no indicators selected
|
|
|
|
|
|
style={'display': 'none'} # Hide the basic checklist
|
|
|
|
|
|
),
|
|
|
|
|
|
# Custom indicator list with edit buttons
|
|
|
|
|
|
html.Div(id='subplot-indicators-list', children=[
|
|
|
|
|
|
# This will be populated dynamically
|
|
|
|
|
|
])
|
|
|
|
|
|
])
|
|
|
|
|
|
], style={'width': '48%', 'display': 'inline-block', 'vertical-align': 'top'})
|
|
|
|
|
|
])
|
|
|
|
|
|
], style={
|
|
|
|
|
|
'border': '1px solid #bdc3c7',
|
|
|
|
|
|
'border-radius': '8px',
|
|
|
|
|
|
'padding': '15px',
|
|
|
|
|
|
'background-color': '#f8f9fa',
|
|
|
|
|
|
'margin-bottom': '20px'
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_auto_update_control():
|
|
|
|
|
|
"""Create the auto-update control section."""
|
|
|
|
|
|
return html.Div([
|
|
|
|
|
|
dcc.Checklist(
|
|
|
|
|
|
id='auto-update-checkbox',
|
|
|
|
|
|
options=[{'label': ' Auto-update charts', 'value': 'auto'}],
|
|
|
|
|
|
value=['auto'],
|
|
|
|
|
|
style={'margin-bottom': '10px'}
|
|
|
|
|
|
),
|
|
|
|
|
|
html.Div(id='update-status', style={'font-size': '12px', 'color': '#7f8c8d'})
|
|
|
|
|
|
])
|