Spaces:
Sleeping
Sleeping
| """AlphaForge Dashboard - Live Quant System Monitor.""" | |
| import gradio as gr | |
| import numpy as np | |
| import pandas as pd | |
| import plotly.graph_objects as go | |
| from plotly.subplots import make_subplots | |
| def create_metrics_panel(): | |
| """Create top-level metrics panel.""" | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| sharpe = gr.Number(label="Sharpe Ratio", value=1.85, interactive=False) | |
| sortino = gr.Number(label="Sortino Ratio", value=2.34, interactive=False) | |
| with gr.Column(scale=1): | |
| pnl = gr.Number(label="Total Return (%)", value=32.5, interactive=False) | |
| max_dd = gr.Number(label="Max Drawdown (%)", value=-12.3, interactive=False) | |
| with gr.Column(scale=1): | |
| var95 = gr.Number(label="VaR 95% (daily)", value=-1.87, interactive=False) | |
| cvar95 = gr.Number(label="CVaR 95% (daily)", value=-2.91, interactive=False) | |
| with gr.Column(scale=1): | |
| regime = gr.Textbox(label="Current Regime", value="Bull", interactive=False) | |
| exposure = gr.Number(label="Current Exposure (%)", value=85.0, interactive=False) | |
| def create_equity_curve_chart(): | |
| """Create interactive equity curve with drawdown.""" | |
| dates = pd.date_range('2023-01-01', periods=252, freq='B') | |
| np.random.seed(42) | |
| returns = np.random.normal(0.0008, 0.008, 252) | |
| equity = 1_000_000 * np.cumprod(1 + returns) | |
| cumulative = np.cumprod(1 + returns) | |
| running_max = np.maximum.accumulate(cumulative) | |
| drawdown = (cumulative - running_max) / running_max * 100 | |
| fig = make_subplots( | |
| rows=2, cols=1, | |
| shared_xaxes=True, | |
| vertical_spacing=0.05, | |
| row_heights=[0.7, 0.3], | |
| subplot_titles=("Portfolio Equity", "Drawdown") | |
| ) | |
| fig.add_trace( | |
| go.Scatter(x=dates, y=equity, mode='lines', | |
| fill='tozeroy', name='Portfolio Value', | |
| line=dict(color='#00ff88', width=2)), | |
| row=1, col=1 | |
| ) | |
| fig.add_trace( | |
| go.Scatter(x=dates, y=drawdown, mode='lines', | |
| fill='tozeroy', name='Drawdown %', | |
| line=dict(color='#ff4444', width=1), | |
| fillcolor='rgba(255, 0, 0, 0.2)'), | |
| row=2, col=1 | |
| ) | |
| fig.update_layout( | |
| height=500, | |
| showlegend=False, | |
| template='plotly_dark', | |
| margin=dict(l=20, r=20, t=40, b=20) | |
| ) | |
| fig.update_yaxes(title_text="Value ($)", row=1, col=1) | |
| fig.update_yaxes(title_text="DD (%)", row=2, col=1) | |
| return fig | |
| def create_portfolio_weights_chart(): | |
| """Create portfolio weights sunburst/bar chart.""" | |
| assets = ['SPY', 'QQQ', 'AAPL', 'MSFT', 'GOOGL', 'AMZN', 'META', 'NVDA', 'TSLA', 'JPM'] | |
| np.random.seed(123) | |
| weights = np.random.dirichlet(np.ones(10), size=1)[0] | |
| weights.sort() | |
| weights = weights[::-1] | |
| fig = go.Figure(data=[ | |
| go.Bar( | |
| x=assets, y=weights * 100, | |
| marker=dict( | |
| color=weights * 100, | |
| colorscale='Viridis', | |
| showscale=False | |
| ), | |
| text=[f'{w:.1f}%' for w in weights * 100], | |
| textposition='outside' | |
| ) | |
| ]) | |
| fig.update_layout( | |
| height=400, | |
| template='plotly_dark', | |
| title="Portfolio Weights", | |
| xaxis_title="Asset", | |
| yaxis_title="Weight (%)", | |
| margin=dict(l=20, r=20, t=50, b=20) | |
| ) | |
| return fig | |
| def create_risk_heatmap(): | |
| """Create correlation heatmap.""" | |
| assets = ['SPY', 'QQQ', 'AAPL', 'MSFT', 'GOOGL', 'AMZN', 'META', 'NVDA', 'TSLA', 'JPM'] | |
| n = len(assets) | |
| np.random.seed(42) | |
| corr = np.zeros((n, n)) | |
| for i in range(n): | |
| for j in range(n): | |
| if i == j: | |
| corr[i, j] = 1.0 | |
| else: | |
| corr[i, j] = 0.3 + np.random.random() * 0.5 | |
| corr = (corr + corr.T) / 2 | |
| fig = go.Figure(data=go.Heatmap( | |
| z=corr, | |
| x=assets, | |
| y=assets, | |
| colorscale='RdBu_r', | |
| zmin=-1, zmax=1, | |
| text=np.round(corr, 2), | |
| texttemplate='%{text}', | |
| textfont=dict(size=10) | |
| )) | |
| fig.update_layout( | |
| height=400, | |
| template='plotly_dark', | |
| title="Covariance Matrix", | |
| margin=dict(l=20, r=20, t=50, b=20) | |
| ) | |
| return fig | |
| def create_factor_exposure_chart(): | |
| """Create factor exposure bar chart.""" | |
| factors = ['Market', 'Momentum', 'Value', 'Size', 'Volatility', 'Quality'] | |
| exposures = np.random.normal(0.3, 0.15, 6) | |
| exposures[0] = 0.95 # Market beta | |
| colors = ['#00ff88' if e > 0 else '#ff4444' for e in exposures] | |
| fig = go.Figure(data=[ | |
| go.Bar( | |
| x=factors, y=exposures, | |
| marker_color=colors, | |
| text=[f'{e:.2f}' for e in exposures], | |
| textposition='outside' | |
| ) | |
| ]) | |
| fig.update_layout( | |
| height=350, | |
| template='plotly_dark', | |
| title="Factor Exposures", | |
| xaxis_title="Factor", | |
| yaxis_title="Beta", | |
| margin=dict(l=20, r=20, t=50, b=20), | |
| showlegend=False | |
| ) | |
| return fig | |
| def create_ic_chart(): | |
| """Create IC tracking chart.""" | |
| dates = pd.date_range('2023-01-01', periods=252, freq='B') | |
| np.random.seed(42) | |
| ic = np.random.normal(0.05, 0.15, 252) | |
| rolling_ic = pd.Series(ic).rolling(21).mean() | |
| fig = go.Figure() | |
| fig.add_trace(go.Scatter( | |
| x=dates, y=ic, mode='markers', | |
| name='Daily IC', marker=dict(size=3, opacity=0.3, color='gray') | |
| )) | |
| fig.add_trace(go.Scatter( | |
| x=dates, y=rolling_ic, mode='lines', | |
| name='21d Rolling IC', line=dict(width=2, color='#00ffff') | |
| )) | |
| fig.add_hline(y=0, line_dash="dash", line_color="gray", opacity=0.5) | |
| fig.update_layout( | |
| height=350, | |
| template='plotly_dark', | |
| title="Information Coefficient (IC) Tracking", | |
| xaxis_title="Date", | |
| yaxis_title="IC", | |
| margin=dict(l=20, r=20, t=50, b=20), | |
| legend=dict(orientation='h', yanchor='bottom', y=1.02) | |
| ) | |
| return fig | |
| def create_regime_timeline(): | |
| """Create regime timeline chart.""" | |
| dates = pd.date_range('2023-01-01', periods=120, freq='B') | |
| np.random.seed(42) | |
| regimes = np.random.choice(['Bull', 'Bear', 'Neutral', 'High Vol'], 120, p=[0.5, 0.15, 0.25, 0.1]) | |
| regime_colors = {'Bull': '#00ff88', 'Bear': '#ff4444', 'Neutral': '#888888', 'High Vol': '#ffaa00'} | |
| regime_nums = {'Bull': 3, 'Neutral': 2, 'Bear': 1, 'High Vol': 0} | |
| y = [regime_nums[r] for r in regimes] | |
| colors = [regime_colors[r] for r in regimes] | |
| fig = go.Figure() | |
| for i in range(len(dates) - 1): | |
| fig.add_trace(go.Scatter( | |
| x=[dates[i], dates[i+1]], | |
| y=[y[i], y[i]], | |
| mode='lines', | |
| line=dict(color=colors[i], width=8), | |
| showlegend=False | |
| )) | |
| fig.update_layout( | |
| height=200, | |
| template='plotly_dark', | |
| title="Market Regime", | |
| yaxis=dict( | |
| tickmode='array', | |
| tickvals=[0, 1, 2, 3], | |
| ticktext=['High Vol', 'Bear', 'Neutral', 'Bull'] | |
| ), | |
| margin=dict(l=20, r=20, t=50, b=20) | |
| ) | |
| return fig | |
| def create_risk_decomposition(): | |
| """Create risk decomposition pie/donut chart.""" | |
| risk_sources = ['Equity Beta', 'Sector', 'Momentum', 'Value', 'Volatility', 'Residual'] | |
| np.random.seed(42) | |
| contribution = np.random.dirichlet(np.ones(6), size=1)[0] * 100 | |
| fig = go.Figure(data=[go.Pie( | |
| labels=risk_sources, | |
| values=contribution, | |
| hole=0.4, | |
| marker=dict(colors=['#00ff88', '#00ccff', '#ffaa00', '#ff4444', '#aa44ff', '#888888']) | |
| )]) | |
| fig.update_layout( | |
| height=350, | |
| template='plotly_dark', | |
| title="Risk Decomposition", | |
| margin=dict(l=20, r=20, t=50, b=20) | |
| ) | |
| return fig | |
| def create_anomaly_tracker(): | |
| """Create anomaly detection tracker.""" | |
| dates = pd.date_range('2023-01-01', periods=120, freq='B') | |
| np.random.seed(42) | |
| anomaly_score = np.random.exponential(0.5, 120) | |
| # Mark anomalies | |
| threshold = np.percentile(anomaly_score, 95) | |
| colors = ['#ff4444' if s > threshold else '#00ff88' for s in anomaly_score] | |
| fig = go.Figure(data=go.Bar( | |
| x=dates, y=anomaly_score, | |
| marker_color=colors, | |
| name='Anomaly Score' | |
| )) | |
| fig.add_hline(y=threshold, line_dash="dash", line_color="orange", | |
| annotation_text=f"Threshold: {threshold:.2f}") | |
| fig.update_layout( | |
| height=300, | |
| template='plotly_dark', | |
| title="Anomaly Detection", | |
| xaxis_title="Date", | |
| yaxis_title="Score", | |
| margin=dict(l=20, r=20, t=50, b=20), | |
| showlegend=False | |
| ) | |
| return fig | |
| def create_options_surface(): | |
| """Create options volatility surface.""" | |
| S_range = np.arange(50, 200, 5) | |
| T_range = np.arange(30, 365, 30) | |
| X, Y = np.meshgrid(S_range, T_range) | |
| Z = 0.2 + 0.05 * (X - 100) / 50 - 0.03 * (Y - 180) / 180 + \ | |
| np.random.normal(0, 0.02, X.shape) | |
| fig = go.Figure(data=[go.Surface( | |
| x=X, y=Y, z=Z, | |
| colorscale='Viridis', | |
| contours=dict(z=dict(show=True, usecolormap=True)) | |
| )]) | |
| fig.update_layout( | |
| height=400, | |
| template='plotly_dark', | |
| title="Implied Volatility Surface", | |
| scene=dict( | |
| xaxis_title='Spot Price', | |
| yaxis_title='Days to Expiry', | |
| zaxis_title='IV' | |
| ), | |
| margin=dict(l=20, r=20, t=50, b=20) | |
| ) | |
| return fig | |
| # Build Gradio UI | |
| with gr.Blocks(theme=gr.themes.Soft(), title="AlphaForge Dashboard") as demo: | |
| gr.Markdown(""" | |
| # π¦ AlphaForge - Autonomous Quant Fund OS | |
| Real-time multi-asset alpha signals | Sentiment analysis | Risk engine | Portfolio optimizer | Options pricing | |
| """) | |
| with gr.Tabs(): | |
| with gr.TabItem("π Overview"): | |
| create_metrics_panel() | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| eq_chart = gr.Plot(label="Equity Curve", value=create_equity_curve_chart()) | |
| with gr.Column(scale=1): | |
| regime_chart = gr.Plot(label="Regime Timeline", value=create_regime_timeline()) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| weights_chart = gr.Plot(label="Portfolio Weights", value=create_portfolio_weights_chart()) | |
| with gr.Column(scale=1): | |
| risk_chart = gr.Plot(label="Risk Decomposition", value=create_risk_decomposition()) | |
| with gr.TabItem("π Alpha Signals"): | |
| gr.Markdown("### Alpha Model Performance") | |
| with gr.Row(): | |
| ic_chart = gr.Plot(label="IC Tracking", value=create_ic_chart()) | |
| with gr.Row(): | |
| factor_chart = gr.Plot(label="Factor Exposures", value=create_factor_exposure_chart()) | |
| gr.Dataframe( | |
| label="Recent Alpha Signals", | |
| value=pd.DataFrame({ | |
| 'Date': pd.date_range('2025-05-01', periods=10), | |
| 'Ticker': ['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'META', 'NVDA', 'TSLA', 'JPM', 'V', 'WMT'], | |
| 'Predicted Return': [0.0021, 0.0018, 0.0009, -0.0003, 0.0015, 0.0032, -0.0012, 0.0007, 0.0011, -0.0005], | |
| 'Confidence': [0.85, 0.78, 0.62, 0.55, 0.81, 0.92, 0.48, 0.71, 0.65, 0.52], | |
| 'Sentiment': [0.7, 0.5, 0.3, -0.2, 0.6, 0.9, -0.4, 0.1, 0.4, -0.1] | |
| }) | |
| ) | |
| with gr.TabItem("β οΈ Risk Analytics"): | |
| gr.Markdown("### Risk Dashboard (VaR, CVaR, Stress Tests)") | |
| with gr.Row(): | |
| risk_heatmap = gr.Plot(label="Covariance Matrix", value=create_risk_heatmap()) | |
| with gr.Row(): | |
| anomaly_chart = gr.Plot(label="Anomaly Detection", value=create_anomaly_tracker()) | |
| gr.Dataframe( | |
| label="Stress Test Results", | |
| value=pd.DataFrame({ | |
| 'Scenario': ['2008 Crisis', 'COVID Crash', 'Rate Hike', 'Vol Spike', 'Flash Crash'], | |
| 'PnL Impact': ['-24.3%', '-18.7%', '-8.2%', '-15.1%', '-12.8%'], | |
| 'VaR Breach': ['Yes', 'Yes', 'No', 'Yes', 'No'], | |
| 'Recovery Days': [145, 89, 32, 67, 15] | |
| }) | |
| ) | |
| with gr.TabItem("π Options"): | |
| options_chart = gr.Plot(label="IV Surface", value=create_options_surface()) | |
| gr.Dataframe( | |
| label="Options Mispricing Signals", | |
| value=pd.DataFrame({ | |
| 'Option': ['SPY 550C 30d', 'QQQ 480P 45d', 'AAPL 220C 60d'], | |
| 'Market IV': [0.18, 0.22, 0.25], | |
| 'ML IV': [0.15, 0.26, 0.21], | |
| 'Mispricing %': [16.7, 18.2, -16.0], | |
| 'Signal': ['OVERPRICED', 'UNDERPRICED', 'UNDERPRICED'], | |
| 'PnL Estimate': [340, -250, -180] | |
| }) | |
| ) | |
| with gr.TabItem("π§ Model Insights"): | |
| gr.Markdown("### Meta-Model & Explainability") | |
| gr.Dataframe( | |
| label="Model Performance", | |
| value=pd.DataFrame({ | |
| 'Model': ['LSTM', 'Transformer', 'XGBoost', 'Sentiment', 'Meta-Model'], | |
| 'IC': [0.042, 0.038, 0.055, 0.028, 0.061], | |
| 'IC Std': [0.12, 0.14, 0.10, 0.16, 0.09], | |
| 'Weight': [0.25, 0.20, 0.35, 0.05, 0.15], | |
| 'Recent IC': [0.048, 0.032, 0.058, 0.031, 0.063] | |
| }) | |
| ) | |
| gr.Dataframe( | |
| label="Feature Importance (Top 10)", | |
| value=pd.DataFrame({ | |
| 'Feature': ['rsi_14', 'sma_ratio', 'rvol_21d', 'macd', 'volume_change', | |
| 'return_5d', 'bb_position', 'SPY_beta', 'intraday_range', 'return_21d'], | |
| 'Importance': [0.18, 0.15, 0.12, 0.10, 0.09, 0.08, 0.07, 0.06, 0.05, 0.04], | |
| 'Direction': ['Negative', 'Positive', 'Negative', 'Positive', 'Neutral', | |
| 'Positive', 'Neutral', 'Negative', 'Neutral', 'Positive'] | |
| }) | |
| ) | |
| with gr.TabItem("βοΈ Configuration"): | |
| gr.Markdown("### System Configuration") | |
| with gr.Row(): | |
| tickers = gr.Textbox(label="Tickers", value="SPY QQQ AAPL MSFT GOOGL AMZN META NVDA TSLA JPM", lines=1) | |
| rebalance_freq = gr.Slider(minimum=1, maximum=20, value=5, step=1, label="Rebalance Frequency (days)") | |
| with gr.Row(): | |
| risk_aversion = gr.Slider(minimum=0.5, maximum=5.0, value=2.0, step=0.5, label="Risk Aversion") | |
| max_weight = gr.Slider(minimum=0.05, maximum=0.40, value=0.25, step=0.05, label="Max Weight Per Asset") | |
| with gr.Row(): | |
| tc_cost = gr.Slider(minimum=0.0001, maximum=0.01, value=0.0003, step=0.0001, label="Transaction Cost (bps)") | |
| lookback = gr.Slider(minimum=20, maximum=120, value=60, step=5, label="Lookback Window") | |
| run_btn = gr.Button("π Run Backtest", variant="primary") | |
| progress = gr.Progress() | |
| run_btn.click( | |
| fn=lambda *args: "Backtest complete. Check Overview tab for results.", | |
| outputs=[gr.Textbox(label="Status", visible=False)] | |
| ) | |
| demo.launch(server_name="0.0.0.0") | |