2025-06-04 13:30:16 +08:00
|
|
|
|
"""
|
|
|
|
|
|
Chart control components for the market data layout.
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
from dash import html, dcc
|
2025-06-06 13:33:59 +08:00
|
|
|
|
import dash_bootstrap_components as dbc
|
2025-06-04 13:30:16 +08:00
|
|
|
|
from utils.logger import get_logger
|
2025-06-11 18:36:34 +08:00
|
|
|
|
from utils.time_range_utils import load_time_range_options
|
2025-06-04 13:30:16 +08:00
|
|
|
|
|
2025-06-12 13:27:30 +08:00
|
|
|
|
logger = get_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."""
|
2025-06-06 13:33:59 +08:00
|
|
|
|
return dbc.Card([
|
|
|
|
|
|
dbc.CardHeader(html.H5("🎯 Chart Configuration")),
|
|
|
|
|
|
dbc.CardBody([
|
|
|
|
|
|
dbc.Button("➕ Add New Indicator", id="add-indicator-btn-visible", color="primary", className="mb-3"),
|
|
|
|
|
|
|
2025-06-04 13:30:16 +08:00
|
|
|
|
html.Div([
|
2025-06-06 13:33:59 +08:00
|
|
|
|
html.Label("Strategy Template:", className="form-label"),
|
|
|
|
|
|
dcc.Dropdown(
|
|
|
|
|
|
id='strategy-dropdown',
|
|
|
|
|
|
options=strategy_options,
|
|
|
|
|
|
value=None,
|
|
|
|
|
|
placeholder="Select a strategy template (optional)",
|
|
|
|
|
|
)
|
|
|
|
|
|
], className="mb-3"),
|
|
|
|
|
|
|
|
|
|
|
|
dbc.Row([
|
|
|
|
|
|
dbc.Col([
|
|
|
|
|
|
html.Label("Overlay Indicators:", className="form-label"),
|
2025-06-04 13:30:16 +08:00
|
|
|
|
dcc.Checklist(
|
|
|
|
|
|
id='overlay-indicators-checklist',
|
|
|
|
|
|
options=overlay_options,
|
2025-06-06 13:33:59 +08:00
|
|
|
|
value=[],
|
|
|
|
|
|
style={'display': 'none'}
|
2025-06-04 13:30:16 +08:00
|
|
|
|
),
|
2025-06-06 13:33:59 +08:00
|
|
|
|
html.Div(id='overlay-indicators-list')
|
|
|
|
|
|
], width=6),
|
|
|
|
|
|
|
|
|
|
|
|
dbc.Col([
|
|
|
|
|
|
html.Label("Subplot Indicators:", className="form-label"),
|
2025-06-04 13:30:16 +08:00
|
|
|
|
dcc.Checklist(
|
|
|
|
|
|
id='subplot-indicators-checklist',
|
|
|
|
|
|
options=subplot_options,
|
2025-06-06 13:33:59 +08:00
|
|
|
|
value=[],
|
|
|
|
|
|
style={'display': 'none'}
|
2025-06-04 13:30:16 +08:00
|
|
|
|
),
|
2025-06-06 13:33:59 +08:00
|
|
|
|
html.Div(id='subplot-indicators-list')
|
|
|
|
|
|
], width=6)
|
|
|
|
|
|
])
|
2025-06-04 13:30:16 +08:00
|
|
|
|
])
|
2025-06-06 13:33:59 +08:00
|
|
|
|
], className="mb-4")
|
2025-06-04 13:30:16 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_auto_update_control():
|
|
|
|
|
|
"""Create the auto-update control section."""
|
|
|
|
|
|
return html.Div([
|
2025-06-06 13:33:59 +08:00
|
|
|
|
dbc.Checkbox(
|
2025-06-04 13:30:16 +08:00
|
|
|
|
id='auto-update-checkbox',
|
2025-06-06 13:33:59 +08:00
|
|
|
|
label='Auto-update charts',
|
|
|
|
|
|
value=True,
|
2025-06-04 13:30:16 +08:00
|
|
|
|
),
|
|
|
|
|
|
html.Div(id='update-status', style={'font-size': '12px', 'color': '#7f8c8d'})
|
2025-06-06 13:33:59 +08:00
|
|
|
|
], className="mb-3")
|
2025-06-05 12:54:41 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_time_range_controls():
|
|
|
|
|
|
"""Create the time range control panel."""
|
2025-06-06 13:33:59 +08:00
|
|
|
|
return dbc.Card([
|
|
|
|
|
|
dbc.CardHeader(html.H5("⏰ Time Range Controls")),
|
|
|
|
|
|
dbc.CardBody([
|
|
|
|
|
|
html.Div([
|
|
|
|
|
|
html.Label("Quick Select:", className="form-label"),
|
|
|
|
|
|
dcc.Dropdown(
|
|
|
|
|
|
id='time-range-quick-select',
|
2025-06-11 18:36:34 +08:00
|
|
|
|
options=load_time_range_options(),
|
2025-06-06 13:33:59 +08:00
|
|
|
|
value='7d',
|
|
|
|
|
|
placeholder="Select time range",
|
|
|
|
|
|
)
|
|
|
|
|
|
], className="mb-3"),
|
|
|
|
|
|
|
|
|
|
|
|
html.Div([
|
|
|
|
|
|
html.Label("Custom Date Range:", className="form-label"),
|
|
|
|
|
|
dbc.InputGroup([
|
|
|
|
|
|
dcc.DatePickerRange(
|
|
|
|
|
|
id='custom-date-range',
|
|
|
|
|
|
display_format='YYYY-MM-DD',
|
|
|
|
|
|
),
|
|
|
|
|
|
dbc.Button("Clear", id="clear-date-range-btn", color="secondary", outline=True, size="sm")
|
|
|
|
|
|
])
|
|
|
|
|
|
], className="mb-3"),
|
|
|
|
|
|
|
2025-06-05 12:54:41 +08:00
|
|
|
|
html.Div([
|
2025-06-06 13:33:59 +08:00
|
|
|
|
html.Label("Analysis Mode:", className="form-label"),
|
|
|
|
|
|
dbc.RadioItems(
|
|
|
|
|
|
id='analysis-mode-toggle',
|
|
|
|
|
|
options=[
|
|
|
|
|
|
{'label': '🔴 Real-time Updates', 'value': 'realtime'},
|
|
|
|
|
|
{'label': '🔒 Analysis Mode (Locked)', 'value': 'locked'}
|
|
|
|
|
|
],
|
|
|
|
|
|
value='realtime',
|
|
|
|
|
|
inline=True,
|
2025-06-05 12:54:41 +08:00
|
|
|
|
)
|
2025-06-06 13:33:59 +08:00
|
|
|
|
]),
|
|
|
|
|
|
|
|
|
|
|
|
html.Div(id='time-range-status', className="text-muted fst-italic mt-2")
|
|
|
|
|
|
])
|
|
|
|
|
|
], className="mb-4")
|
2025-06-06 12:57:35 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_export_controls():
|
|
|
|
|
|
"""Create the data export control panel."""
|
2025-06-06 13:33:59 +08:00
|
|
|
|
return dbc.Card([
|
|
|
|
|
|
dbc.CardHeader(html.H5("💾 Data Export")),
|
|
|
|
|
|
dbc.CardBody([
|
|
|
|
|
|
dbc.ButtonGroup([
|
|
|
|
|
|
dbc.Button("Export to CSV", id="export-csv-btn", color="primary"),
|
|
|
|
|
|
dbc.Button("Export to JSON", id="export-json-btn", color="secondary"),
|
|
|
|
|
|
]),
|
|
|
|
|
|
dcc.Download(id="download-chart-data")
|
|
|
|
|
|
])
|
|
|
|
|
|
], className="mb-4")
|