ParallelLLC/algorithmic_trading
2732
1"""2Dash UI for Algorithmic Trading System3 4Enterprise-grade interactive dashboard with:5- Real-time market data visualization6- Advanced trading analytics7- Portfolio management8- Risk monitoring9- Strategy backtesting10"""11 12import dash13from dash import dcc, html, Input, Output, State, callback_context14import dash_bootstrap_components as dbc15from dash_bootstrap_components import themes16import plotly.graph_objects as go17import plotly.express as px18import pandas as pd19import numpy as np20import yaml21import os22import sys23from datetime import datetime, timedelta24import asyncio25import threading26import time27from typing import Dict, Any, Optional28 29# Add project root to path30sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))31 32from agentic_ai_system.main import load_config33from agentic_ai_system.data_ingestion import load_data, validate_data, add_technical_indicators34from agentic_ai_system.finrl_agent import FinRLAgent, FinRLConfig35from agentic_ai_system.alpaca_broker import AlpacaBroker36from agentic_ai_system.orchestrator import run_backtest, run_live_trading37 38class TradingDashApp:39 def __init__(self):40 self.app = dash.Dash(41 __name__,42 external_stylesheets=[43 themes.BOOTSTRAP,44 "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"45 ],46 suppress_callback_exceptions=True47 )48 49 self.config = None50 self.data = None51 self.alpaca_broker = None52 self.finrl_agent = None53 54 self.setup_layout()55 self.setup_callbacks()56 57 def setup_layout(self):58 """Setup the main application layout"""59 self.app.layout = dbc.Container([60 # Header61 dbc.Row([62 dbc.Col([63 html.H1([64 html.I(className="fas fa-chart-line me-3"),65 "Algorithmic Trading System"66 ], className="text-primary mb-4 text-center")67 ])68 ]),69 70 # Navigation tabs71 dbc.Tabs([72 dbc.Tab(self.create_dashboard_tab(), label="Dashboard", tab_id="dashboard"),73 dbc.Tab(self.create_data_tab(), label="Data", tab_id="data"),74 dbc.Tab(self.create_trading_tab(), label="Trading", tab_id="trading"),75 dbc.Tab(self.create_analytics_tab(), label="Analytics", tab_id="analytics"),76 dbc.Tab(self.create_portfolio_tab(), label="Portfolio", tab_id="portfolio"),77 dbc.Tab(self.create_settings_tab(), label="Settings", tab_id="settings")78 ], id="tabs", active_tab="dashboard"),79 80 # Store components for data persistence81 dcc.Store(id="config-store"),82 dcc.Store(id="data-store"),83 dcc.Store(id="alpaca-store"),84 dcc.Store(id="finrl-store"),85 dcc.Store(id="trading-status-store"),86 87 # Interval for real-time updates88 dcc.Interval(89 id="interval-component",90 interval=5*1000, # 5 seconds91 n_intervals=092 )93 ], fluid=True)94 95 def create_dashboard_tab(self):96 """Create the main dashboard tab"""97 return dbc.Container([98 # System status cards99 dbc.Row([100 dbc.Col(self.create_status_card("Trading Status", "Active", "success"), width=3),101 dbc.Col(self.create_status_card("Portfolio Value", "$100,000", "info"), width=3),102 dbc.Col(self.create_status_card("Daily P&L", "+$1,250", "success"), width=3),103 dbc.Col(self.create_status_card("Risk Level", "Low", "warning"), width=3)104 ], className="mb-4"),105 106 # Charts row107 dbc.Row([108 dbc.Col([109 dbc.Card([110 dbc.CardHeader("Price Chart"),111 dbc.CardBody([112 dcc.Graph(id="price-chart", style={"height": "400px"})113 ])114 ])115 ], width=8),116 dbc.Col([117 dbc.Card([118 dbc.CardHeader("Portfolio Allocation"),119 dbc.CardBody([120 dcc.Graph(id="allocation-chart", style={"height": "400px"})121 ])122 ])123 ], width=4)124 ], className="mb-4"),125 126 # Trading activity and alerts127 dbc.Row([128 dbc.Col([129 dbc.Card([130 dbc.CardHeader("Recent Trades"),131 dbc.CardBody([132 html.Div(id="trades-table")133 ])134 ])135 ], width=6),136 dbc.Col([137 dbc.Card([138 dbc.CardHeader("System Alerts"),139 dbc.CardBody([140 html.Div(id="alerts-list")141 ])142 ])143 ], width=6)144 ])145 ])146 147 def create_data_tab(self):148 """Create the data management tab"""149 return dbc.Container([150 dbc.Row([151 dbc.Col([152 dbc.Card([153 dbc.CardHeader("Data Configuration"),154 dbc.CardBody([155 dbc.Row([156 dbc.Col([157 dbc.Label("Data Source"),158 dbc.Select(159 id="data-source-select",160 options=[161 {"label": "Yahoo Finance", "value": "yahoo"},162 {"label": "CSV File", "value": "csv"},163 {"label": "Alpaca API", "value": "alpaca"},164 {"label": "Synthetic Data", "value": "synthetic"}165 ],166 value="yahoo"167 )168 ], width=4),169 dbc.Col([170 dbc.Label("Symbol"),171 dbc.Input(172 id="symbol-input",173 type="text",174 value="AAPL",175 placeholder="Enter symbol"176 )177 ], width=4),178 dbc.Col([179 dbc.Label("Timeframe"),180 dbc.Select(181 id="timeframe-select",182 options=[183 {"label": "1 Minute", "value": "1m"},184 {"label": "5 Minutes", "value": "5m"},185 {"label": "15 Minutes", "value": "15m"},186 {"label": "1 Hour", "value": "1h"},187 {"label": "1 Day", "value": "1d"}188 ],189 value="1m"190 )191 ], width=4)192 ], className="mb-3"),193 dbc.Row([194 dbc.Col([195 dbc.Button("Load Data", id="load-data-btn", color="primary", className="me-2"),196 dbc.Button("Refresh Data", id="refresh-data-btn", color="secondary")197 ])198 ])199 ])200 ])201 ], width=6),202 dbc.Col([203 dbc.Card([204 dbc.CardHeader("Data Statistics"),205 dbc.CardBody([206 html.Div(id="data-stats")207 ])208 ])209 ], width=6)210 ], className="mb-4"),211 212 # Data visualization213 dbc.Row([214 dbc.Col([215 dbc.Card([216 dbc.CardHeader([217 html.Span("Market Data Visualization"),218 dbc.ButtonGroup([219 dbc.Button("Candlestick", id="candlestick-btn", size="sm"),220 dbc.Button("Line", id="line-btn", size="sm"),221 dbc.Button("Volume", id="volume-btn", size="sm")222 ], className="float-end")223 ]),224 dbc.CardBody([225 dcc.Graph(id="market-chart", style={"height": "500px"})226 ])227 ])228 ])229 ])230 ])231 232 def create_trading_tab(self):233 """Create the trading controls tab"""234 return dbc.Container([235 # Trading configuration236 dbc.Row([237 dbc.Col([238 dbc.Card([239 dbc.CardHeader("Trading Configuration"),240 dbc.CardBody([241 dbc.Row([242 dbc.Col([243 dbc.Label("Capital"),244 dbc.Input(245 id="capital-input",246 type="number",247 value=100000,248 step=1000249 )250 ], width=3),251 dbc.Col([252 dbc.Label("Order Size"),253 dbc.Input(254 id="order-size-input",255 type="number",256 value=10,257 step=1258 )259 ], width=3),260 dbc.Col([261 dbc.Label("Max Position"),262 dbc.Input(263 id="max-position-input",264 type="number",265 value=100,266 step=10267 )268 ], width=3),269 dbc.Col([270 dbc.Label("Max Drawdown"),271 dbc.Input(272 id="max-drawdown-input",273 type="number",274 value=0.05,275 step=0.01,276 min=0,277 max=1278 )279 ], width=3)280 ], className="mb-3"),281 dbc.Row([282 dbc.Col([283 dbc.Button("Start Trading", id="start-trading-btn", color="success", className="me-2"),284 dbc.Button("Stop Trading", id="stop-trading-btn", color="danger", className="me-2"),285 dbc.Button("Emergency Stop", id="emergency-stop-btn", color="warning")286 ])287 ])288 ])289 ])290 ], width=6),291 dbc.Col([292 dbc.Card([293 dbc.CardHeader("Alpaca Connection"),294 dbc.CardBody([295 dbc.Row([296 dbc.Col([297 dbc.Label("API Key"),298 dbc.Input(299 id="alpaca-api-key",300 type="password",301 placeholder="Enter Alpaca API key"302 )303 ], width=6),304 dbc.Col([305 dbc.Label("Secret Key"),306 dbc.Input(307 id="alpaca-secret-key",308 type="password",309 placeholder="Enter Alpaca secret key"310 )311 ], width=6)312 ], className="mb-3"),313 dbc.Row([314 dbc.Col([315 dbc.Button("Connect", id="connect-alpaca-btn", color="primary", className="me-2"),316 dbc.Button("Disconnect", id="disconnect-alpaca-btn", color="secondary")317 ])318 ])319 ])320 ])321 ], width=6)322 ], className="mb-4"),323 324 # Trading activity325 dbc.Row([326 dbc.Col([327 dbc.Card([328 dbc.CardHeader("Live Trading Activity"),329 dbc.CardBody([330 html.Div(id="trading-activity")331 ])332 ])333 ])334 ])335 ])336 337 def create_analytics_tab(self):338 """Create the analytics tab"""339 return dbc.Container([340 # FinRL training341 dbc.Row([342 dbc.Col([343 dbc.Card([344 dbc.CardHeader("FinRL Model Training"),345 dbc.CardBody([346 dbc.Row([347 dbc.Col([348 dbc.Label("Algorithm"),349 dbc.Select(350 id="finrl-algorithm-select",351 options=[352 {"label": "PPO", "value": "PPO"},353 {"label": "A2C", "value": "A2C"},354 {"label": "DDPG", "value": "DDPG"},355 {"label": "TD3", "value": "TD3"}356 ],357 value="PPO"358 )359 ], width=3),360 dbc.Col([361 dbc.Label("Learning Rate"),362 dbc.Input(363 id="learning-rate-input",364 type="number",365 value=0.0003,366 step=0.0001,367 min=0.0001,368 max=0.01369 )370 ], width=3),371 dbc.Col([372 dbc.Label("Training Steps"),373 dbc.Input(374 id="training-steps-input",375 type="number",376 value=100000,377 step=1000378 )379 ], width=3),380 dbc.Col([381 dbc.Label("Batch Size"),382 dbc.Select(383 id="batch-size-select",384 options=[385 {"label": "32", "value": 32},386 {"label": "64", "value": 64},387 {"label": "128", "value": 128},388 {"label": "256", "value": 256}389 ],390 value=64391 )392 ], width=3)393 ], className="mb-3"),394 dbc.Row([395 dbc.Col([396 dbc.Button("Start Training", id="start-training-btn", color="primary", className="me-2"),397 dbc.Button("Stop Training", id="stop-training-btn", color="danger")398 ])399 ])400 ])401 ])402 ], width=6),403 dbc.Col([404 dbc.Card([405 dbc.CardHeader("Training Progress"),406 dbc.CardBody([407 dbc.Progress(id="training-progress", value=0, className="mb-3"),408 html.Div(id="training-metrics")409 ])410 ])411 ], width=6)412 ], className="mb-4"),413 414 # Backtesting415 dbc.Row([416 dbc.Col([417 dbc.Card([418 dbc.CardHeader("Strategy Backtesting"),419 dbc.CardBody([420 dbc.Row([421 dbc.Col([422 dbc.Button("Run Backtest", id="run-backtest-btn", color="primary", className="me-2"),423 dbc.Button("Export Results", id="export-backtest-btn", color="secondary")424 ])425 ]),426 html.Div(id="backtest-results")427 ])428 ])429 ])430 ])431 ])432 433 def create_portfolio_tab(self):434 """Create the portfolio management tab"""435 return dbc.Container([436 # Portfolio overview437 dbc.Row([438 dbc.Col([439 dbc.Card([440 dbc.CardHeader("Portfolio Overview"),441 dbc.CardBody([442 dbc.Row([443 dbc.Col([444 html.H4("Total Value", className="text-muted"),445 html.H3(id="total-value", children="$100,000")446 ], width=3),447 dbc.Col([448 html.H4("Cash", className="text-muted"),449 html.H3(id="cash-value", children="$25,000")450 ], width=3),451 dbc.Col([452 html.H4("Invested", className="text-muted"),453 html.H3(id="invested-value", children="$75,000")454 ], width=3),455 dbc.Col([456 html.H4("P&L", className="text-muted"),457 html.H3(id="pnl-value", children="+$1,250", className="text-success")458 ], width=3)459 ])460 ])461 ])462 ])463 ], className="mb-4"),464 465 # Positions and allocation466 dbc.Row([467 dbc.Col([468 dbc.Card([469 dbc.CardHeader("Current Positions"),470 dbc.CardBody([471 html.Div(id="positions-table")472 ])473 ])474 ], width=8),475 dbc.Col([476 dbc.Card([477 dbc.CardHeader("Allocation Chart"),478 dbc.CardBody([479 dcc.Graph(id="portfolio-allocation-chart", style={"height": "300px"})480 ])481 ])482 ], width=4)483 ])484 ])485 486 def create_settings_tab(self):487 """Create the settings tab"""488 return dbc.Container([489 dbc.Row([490 dbc.Col([491 dbc.Card([492 dbc.CardHeader("System Configuration"),493 dbc.CardBody([494 dbc.Row([495 dbc.Col([496 dbc.Label("Config File"),497 dbc.Input(498 id="config-file-input",499 type="text",500 value="config.yaml",501 placeholder="Enter config file path"502 )503 ], width=6),504 dbc.Col([505 dbc.Label("Log Level"),506 dbc.Select(507 id="log-level-select",508 options=[509 {"label": "DEBUG", "value": "DEBUG"},510 {"label": "INFO", "value": "INFO"},511 {"label": "WARNING", "value": "WARNING"},512 {"label": "ERROR", "value": "ERROR"}513 ],514 value="INFO"515 )516 ], width=6)517 ], className="mb-3"),518 dbc.Row([519 dbc.Col([520 dbc.Button("Load Config", id="load-config-btn", color="primary", className="me-2"),521 dbc.Button("Save Config", id="save-config-btn", color="success")522 ])523 ])524 ])525 ])526 ], width=6),527 dbc.Col([528 dbc.Card([529 dbc.CardHeader("System Status"),530 dbc.CardBody([531 html.Div(id="system-status")532 ])533 ])534 ], width=6)535 ])536 ])537 538 def create_status_card(self, title, value, color):539 """Create a status card component"""540 return dbc.Card([541 dbc.CardBody([542 html.H5(title, className="card-title text-muted"),543 html.H3(value, className=f"text-{color}")544 ])545 ])546 547 def setup_callbacks(self):548 """Setup all Dash callbacks"""549 550 @self.app.callback(551 Output("config-store", "data"),552 Input("load-config-btn", "n_clicks"),553 State("config-file-input", "value"),554 prevent_initial_call=True555 )556 def load_configuration(n_clicks, config_file):557 if n_clicks:558 try:559 config = load_config(config_file)560 return config561 except Exception as e:562 return {"error": str(e)}563 return dash.no_update564 565 @self.app.callback(566 Output("data-store", "data"),567 Input("load-data-btn", "n_clicks"),568 State("config-store", "data"),569 prevent_initial_call=True570 )571 def load_market_data(n_clicks, config):572 if n_clicks and config:573 try:574 data = load_data(config)575 if data is not None:576 return data.to_dict('records')577 except Exception as e:578 return {"error": str(e)}579 return dash.no_update580 581 @self.app.callback(582 Output("price-chart", "figure"),583 Input("data-store", "data"),584 Input("interval-component", "n_intervals")585 )586 def update_price_chart(data, n_intervals):587 if data and isinstance(data, list):588 df = pd.DataFrame(data)589 if not df.empty:590 fig = go.Figure(data=[go.Candlestick(591 x=df['timestamp'],592 open=df['open'],593 high=df['high'],594 low=df['low'],595 close=df['close']596 )])597 fig.update_layout(598 title="Market Data",599 xaxis_title="Date",600 yaxis_title="Price ($)",601 height=400602 )603 return fig604 return go.Figure()605 606 @self.app.callback(607 Output("allocation-chart", "figure"),608 Input("alpaca-store", "data"),609 Input("interval-component", "n_intervals")610 )611 def update_allocation_chart(alpaca_data, n_intervals):612 # Mock portfolio allocation data613 labels = ['AAPL', 'GOOGL', 'MSFT', 'TSLA', 'Cash']614 values = [30, 25, 20, 15, 10]615 616 fig = go.Figure(data=[go.Pie(labels=labels, values=values)])617 fig.update_layout(618 title="Portfolio Allocation",619 height=400620 )621 return fig622 623 @self.app.callback(624 Output("trading-activity", "children"),625 Input("interval-component", "n_intervals")626 )627 def update_trading_activity(n_intervals):628 # Mock trading activity629 trades = [630 {"time": "09:30:15", "symbol": "AAPL", "action": "BUY", "quantity": 10, "price": 150.25},631 {"time": "09:35:22", "symbol": "GOOGL", "action": "SELL", "quantity": 5, "price": 2750.50},632 {"time": "09:40:08", "symbol": "MSFT", "action": "BUY", "quantity": 15, "price": 320.75}633 ]634 635 table_rows = []636 for trade in trades:637 color = "success" if trade["action"] == "BUY" else "danger"638 table_rows.append(639 dbc.Row([640 dbc.Col(trade["time"], width=2),641 dbc.Col(trade["symbol"], width=2),642 dbc.Col(trade["action"], width=2, className=f"text-{color}"),643 dbc.Col(str(trade["quantity"]), width=2),644 dbc.Col(f"${trade['price']:.2f}", width=2),645 dbc.Col(f"${trade['quantity'] * trade['price']:.2f}", width=2)646 ], className="mb-2")647 )648 649 return table_rows650 651def create_dash_app():652 """Create and return the Dash application"""653 app = TradingDashApp()654 return app.app655 656if __name__ == "__main__":657 app = create_dash_app()658 app.run_server(debug=True, host="0.0.0.0", port=8050) 