From 994fb0fab507eb48cc6b3d5b04fa7c31b80f46ca Mon Sep 17 00:00:00 2001 From: JamesTang Date: Wed, 4 Feb 2026 15:59:22 +0800 Subject: [PATCH] Add interactive platform prototype - Complete clickable mockup showing full platform UI/UX - Dashboard with real-time metrics and charts - Data management interface with API connectors - Strategy engine configuration and backtesting - Risk management controls and monitoring - Navigation between all platform sections - Dark theme with professional trading aesthetic - Responsive design for mobile/desktop - Interactive charts using Chart.js with mock data - Reusable HTML/CSS/JavaScript structure - Updated README with prototype documentation --- README.md | 18 + prototype/README.md | 136 +++++++ prototype/css/style.css | 485 ++++++++++++++++++++++ prototype/index.html | 820 ++++++++++++++++++++++++++++++++++++++ prototype/js/app.js | 346 ++++++++++++++++ prototype/js/mock-data.js | 414 +++++++++++++++++++ 6 files changed, 2219 insertions(+) create mode 100644 prototype/README.md create mode 100644 prototype/css/style.css create mode 100644 prototype/index.html create mode 100644 prototype/js/app.js create mode 100644 prototype/js/mock-data.js diff --git a/README.md b/README.md index 2f7dcb9..4908fd8 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,24 @@ The dashboard is built with Flask (backend) and Bootstrap/Chart.js (frontend). - Backend: `app.py` provides REST API endpoints - Frontend: `templates/dashboard.html` with interactive charts +## Interactive Prototype + +A complete clickable mockup of the full platform is available in the `prototype/` directory. This showcases the complete user interface with all major sections: + +**Features demonstrated:** +- Dashboard with real-time metrics +- Data management interface +- Strategy engine configuration +- Risk management controls +- Navigation between all platform sections + +**To use the prototype:** +1. Open `prototype/index.html` in a web browser +2. Click sidebar navigation to explore different sections +3. Interact with charts, forms, and controls + +The prototype uses HTML/CSS/JavaScript with Bootstrap and Chart.js, and can be reused as the foundation for the actual web application. + ## License Proprietary \ No newline at end of file diff --git a/prototype/README.md b/prototype/README.md new file mode 100644 index 0000000..6611b2d --- /dev/null +++ b/prototype/README.md @@ -0,0 +1,136 @@ +# Quantitative Trading Platform - Interactive Mockup + +A complete clickable mockup of the Quantitative Trading Platform showing the full user interface and workflow. + +## Features + +### 1. **Dashboard** +- Real-time portfolio performance metrics +- Interactive charts showing P&L, drawdown, win rate +- Recent trades table +- Top holdings overview + +### 2. **Data Management** +- API connector status (Moomoo, alternative data) +- Data quality monitoring dashboard +- Rate limiting and connectivity indicators + +### 3. **Strategy Engine** +- Active strategies overview (Live/Paper/Paused) +- Backtest results visualization +- Strategy creation interface +- Performance metrics (Sharpe ratio, win rate) + +### 4. **Risk Management** +- Circuit breakers configuration +- Risk metrics dashboard (VaR, CVaR, volatility) +- Real-time risk monitoring +- Alert system for limit breaches + +### 5. **Navigation & Workflow** +- Sidebar navigation with system status +- Responsive design (mobile/desktop) +- Interactive charts with mock data +- Form elements and configuration panels + +## Technology Stack + +- **HTML5** - Semantic markup +- **CSS3** - Custom dark theme with CSS variables +- **JavaScript** - Interactive elements and navigation +- **Bootstrap 5** - Responsive grid and components +- **Chart.js** - Interactive data visualization +- **Bootstrap Icons** - Icon set + +## File Structure + +``` +prototype/ +├── index.html # Main HTML file +├── css/ +│ └── style.css # Custom styles +├── js/ +│ ├── app.js # Main application logic +│ └── mock-data.js # Chart initialization and mock data +└── README.md # This file +``` + +## Design Principles + +### Dark Theme +- Professional trading platform aesthetic +- Reduced eye strain for extended use +- High contrast for data visualization + +### Responsive Layout +- Sidebar collapses on mobile +- Charts resize appropriately +- Touch-friendly interactive elements + +### Interactive Elements +- Clickable navigation between sections +- Form elements for configuration +- Real-time data updates (simulated) +- Toast notifications for user feedback + +## How to Use + +1. Open `index.html` in a modern web browser +2. Click sidebar navigation items to switch between sections +3. Interact with form elements and buttons +4. Charts display mock data that updates automatically + +## Integration with Actual Platform + +This mockup is designed to be reusable for the actual web application: + +### CSS Reusability +- CSS variables for theming (`:root` custom properties) +- Modular class names +- Consistent design system + +### JavaScript Structure +- Modular architecture +- State management pattern +- Chart initialization utilities + +### HTML Templates +- Semantic markup +- Bootstrap classes for consistency +- Component-based structure + +## Mock Data Features + +- **Portfolio Chart**: Simulated 30-day performance +- **Data Quality**: Weekly completeness and latency trends +- **Backtest Results**: Multiple strategy comparisons +- **Risk Metrics**: Radar chart for risk assessment + +## Browser Support + +- Chrome 90+ +- Firefox 88+ +- Safari 14+ +- Edge 90+ + +## Next Steps for Implementation + +1. **Backend Integration** + - Replace mock data with real API calls + - Connect to Moomoo API connector + - Implement user authentication + +2. **Real-time Features** + - WebSocket connections for live data + - Server-sent events for updates + - Push notifications for alerts + +3. **Additional Features** + - User preferences and settings + - Export functionality (CSV, PDF) + - Multi-user collaboration + - Audit logging + +## License + +Proprietary - For internal use only \ No newline at end of file diff --git a/prototype/css/style.css b/prototype/css/style.css new file mode 100644 index 0000000..f287907 --- /dev/null +++ b/prototype/css/style.css @@ -0,0 +1,485 @@ +/* + * Quantitative Trading Platform - Interactive Mockup + * CSS Styles for the complete platform mockup + */ + +:root { + /* Color Palette */ + --primary-dark: #0a1929; + --secondary-dark: #1e2a38; + --tertiary-dark: #2a3a4d; + + /* Accent Colors */ + --accent-blue: #1976d2; + --accent-green: #4caf50; + --accent-red: #f44336; + --accent-purple: #9c27b0; + --accent-orange: #ff9800; + --accent-cyan: #00bcd4; + --accent-yellow: #ffc107; + + /* Text Colors */ + --text-primary: #ffffff; + --text-secondary: #b0bec5; + --text-muted: #78909c; + + /* Border Colors */ + --border-dark: #37474f; + --border-light: #546e7a; + + /* Status Colors */ + --status-success: #4caf50; + --status-warning: #ff9800; + --status-danger: #f44336; + --status-info: #2196f3; + + /* Chart Colors */ + --chart-line: #4caf50; + --chart-area: rgba(76, 175, 80, 0.1); + --chart-grid: #37474f; +} + +/* Base Styles */ +body { + font-family: 'Segoe UI', system-ui, -apple-system, BlinkMacSystemFont, 'Roboto', sans-serif; + background-color: var(--primary-dark); + color: var(--text-primary); + overflow-x: hidden; + font-size: 0.9rem; + line-height: 1.5; +} + +/* Typography */ +h1, h2, h3, h4, h5, h6 { + font-weight: 600; + color: var(--text-primary); +} + +.text-muted { + color: var(--text-muted) !important; +} + +/* Cards */ +.card { + background-color: var(--primary-dark); + border: 1px solid var(--border-dark); + border-radius: 8px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); + transition: all 0.2s ease; +} + +.card:hover { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4); + transform: translateY(-2px); +} + +.card-header { + background-color: rgba(255, 255, 255, 0.03); + border-bottom: 1px solid var(--border-dark); + padding: 0.75rem 1rem; +} + +.card-body { + padding: 1rem; +} + +/* Border accent colors */ +.border-accent-blue { + border-color: var(--accent-blue) !important; +} + +.border-accent-green { + border-color: var(--accent-green) !important; +} + +.border-accent-red { + border-color: var(--accent-red) !important; +} + +.border-accent-purple { + border-color: var(--accent-purple) !important; +} + +.border-accent-orange { + border-color: var(--accent-orange) !important; +} + +.border-secondary-dark { + border-color: var(--secondary-dark) !important; +} + +/* Sidebar Navigation */ +.sidebar { + min-height: calc(100vh - 56px); + padding-top: 1rem; +} + +.nav-link { + color: var(--text-secondary); + padding: 0.75rem 1rem; + margin: 0.125rem 0.5rem; + border-radius: 6px; + transition: all 0.2s ease; +} + +.nav-link:hover { + color: var(--text-primary); + background-color: rgba(255, 255, 255, 0.05); +} + +.nav-link.active { + color: var(--text-primary); + background-color: rgba(25, 118, 210, 0.15); + border-left: 3px solid var(--accent-blue); +} + +.nav-link i { + width: 20px; + text-align: center; +} + +/* Progress Bars */ +.progress { + background-color: var(--tertiary-dark); + border-radius: 4px; +} + +.progress-bar { + border-radius: 4px; +} + +/* Tables */ +.table-dark { + --bs-table-bg: transparent; + --bs-table-striped-bg: rgba(255, 255, 255, 0.03); + --bs-table-hover-bg: rgba(255, 255, 255, 0.05); + color: var(--text-primary); + border-color: var(--border-dark); +} + +.table-dark th { + font-weight: 600; + color: var(--text-secondary); + border-color: var(--border-dark); +} + +.table-dark td { + border-color: var(--border-dark); +} + +/* Forms */ +.form-control, .form-select { + background-color: var(--secondary-dark); + border: 1px solid var(--border-dark); + color: var(--text-primary); +} + +.form-control:focus, .form-select:focus { + background-color: var(--secondary-dark); + border-color: var(--accent-blue); + color: var(--text-primary); + box-shadow: 0 0 0 0.25rem rgba(25, 118, 210, 0.25); +} + +.form-control::placeholder { + color: var(--text-muted); +} + +.input-group-text { + background-color: var(--tertiary-dark); + border: 1px solid var(--border-dark); + color: var(--text-secondary); +} + +/* Buttons */ +.btn { + border-radius: 6px; + font-weight: 500; + transition: all 0.2s ease; +} + +.btn-outline-light { + color: var(--text-secondary); + border-color: var(--border-dark); +} + +.btn-outline-light:hover { + background-color: rgba(255, 255, 255, 0.1); + border-color: var(--border-light); + color: var(--text-primary); +} + +.btn-primary { + background-color: var(--accent-blue); + border-color: var(--accent-blue); +} + +.btn-primary:hover { + background-color: #1565c0; + border-color: #1565c0; +} + +.btn-success { + background-color: var(--accent-green); + border-color: var(--accent-green); +} + +.btn-danger { + background-color: var(--accent-red); + border-color: var(--accent-red); +} + +.btn-warning { + background-color: var(--accent-orange); + border-color: var(--accent-orange); + color: #000; +} + +.btn-info { + background-color: var(--accent-cyan); + border-color: var(--accent-cyan); +} + +/* Badges */ +.badge { + font-weight: 500; + padding: 0.35em 0.65em; + border-radius: 4px; +} + +.bg-purple { + background-color: var(--accent-purple) !important; +} + +/* Alerts */ +.alert { + border-radius: 6px; + border: 1px solid transparent; +} + +.alert-warning { + background-color: rgba(255, 152, 0, 0.1); + border-color: rgba(255, 152, 0, 0.3); + color: var(--accent-orange); +} + +.alert-success { + background-color: rgba(76, 175, 80, 0.1); + border-color: rgba(76, 175, 80, 0.3); + color: var(--accent-green); +} + +.alert-info { + background-color: rgba(33, 150, 243, 0.1); + border-color: rgba(33, 150, 243, 0.3); + color: var(--accent-blue); +} + +/* Charts Container */ +canvas { + max-width: 100%; +} + +/* Section Transitions */ +.section-content { + animation: fadeIn 0.3s ease; +} + +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Responsive Adjustments */ +@media (max-width: 768px) { + .sidebar { + min-height: auto; + border-right: none; + border-bottom: 1px solid var(--border-dark); + } + + .nav-link { + margin: 0.125rem 0; + } + + .display-4 { + font-size: 2.5rem; + } +} + +/* Utility Classes */ +.text-success { + color: var(--accent-green) !important; +} + +.text-danger { + color: var(--accent-red) !important; +} + +.text-warning { + color: var(--accent-orange) !important; +} + +.text-info { + color: var(--accent-cyan) !important; +} + +.bg-primary-dark { + background-color: var(--primary-dark) !important; +} + +.bg-secondary-dark { + background-color: var(--secondary-dark) !important; +} + +.border-secondary-dark { + border-color: var(--secondary-dark) !important; +} + +/* Scrollbar Styling */ +::-webkit-scrollbar { + width: 10px; + height: 10px; +} + +::-webkit-scrollbar-track { + background: var(--secondary-dark); +} + +::-webkit-scrollbar-thumb { + background: var(--tertiary-dark); + border-radius: 5px; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--border-light); +} + +/* List Groups */ +.list-group-item { + background-color: transparent; + color: var(--text-primary); + border-color: var(--border-dark); +} + +.list-group-item:hover { + background-color: rgba(255, 255, 255, 0.03); +} + +/* Hover Effects */ +.hover-lift { + transition: transform 0.2s ease; +} + +.hover-lift:hover { + transform: translateY(-2px); +} + +/* Highlight animation for updated values */ +@keyframes highlight { + 0% { color: var(--text-primary); } + 50% { color: var(--accent-yellow); } + 100% { color: var(--text-primary); } +} + +.text-highlight { + animation: highlight 1s ease; +} + +/* Status Indicators */ +.status-indicator { + display: inline-block; + width: 8px; + height: 8px; + border-radius: 50%; + margin-right: 6px; +} + +.status-indicator.online { + background-color: var(--accent-green); + box-shadow: 0 0 8px var(--accent-green); +} + +.status-indicator.warning { + background-color: var(--accent-orange); + box-shadow: 0 0 8px var(--accent-orange); +} + +.status-indicator.offline { + background-color: var(--accent-red); + box-shadow: 0 0 8px var(--accent-red); +} + +/* Metric Cards */ +.metric-card { + position: relative; + overflow: hidden; +} + +.metric-card::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 3px; + background: linear-gradient(90deg, var(--accent-blue), var(--accent-cyan)); +} + +.metric-card.green::before { + background: linear-gradient(90deg, var(--accent-green), #81c784); +} + +.metric-card.red::before { + background: linear-gradient(90deg, var(--accent-red), #e57373); +} + +.metric-card.orange::before { + background: linear-gradient(90deg, var(--accent-orange), #ffb74d); +} + +/* Loading States */ +.loading-skeleton { + background: linear-gradient(90deg, var(--secondary-dark) 25%, var(--tertiary-dark) 50%, var(--secondary-dark) 75%); + background-size: 200% 100%; + animation: loading 1.5s infinite; +} + +@keyframes loading { + 0% { + background-position: 200% 0; + } + 100% { + background-position: -200% 0; + } +} + +/* Tooltips */ +.tooltip-inner { + background-color: var(--tertiary-dark); + color: var(--text-primary); + border-radius: 4px; + padding: 0.5rem 0.75rem; +} + +.tooltip.bs-tooltip-top .tooltip-arrow::before { + border-top-color: var(--tertiary-dark); +} + +.tooltip.bs-tooltip-bottom .tooltip-arrow::before { + border-bottom-color: var(--tertiary-dark); +} + +.tooltip.bs-tooltip-start .tooltip-arrow::before { + border-left-color: var(--tertiary-dark); +} + +.tooltip.bs-tooltip-end .tooltip-arrow::before { + border-right-color: var(--tertiary-dark); +} \ No newline at end of file diff --git a/prototype/index.html b/prototype/index.html new file mode 100644 index 0000000..ba2c00a --- /dev/null +++ b/prototype/index.html @@ -0,0 +1,820 @@ + + + + + + Quantitative Trading Platform - Interactive Mockup + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+
+

+ + Dashboard +

+
+
+ + +
+
+
+ + +
+
+
+
+
+
+
Total P&L
+

$42,580

+
+ +
+

+ +12.4% MTD +

+
+
+
+
+
+
+
+
+
Max Drawdown
+

-$8,420

+
+ +
+

+ -4.2% from peak +

+
+
+
+
+
+
+
+
+
Win Rate
+

64.8%

+
+ +
+

+ 182 winning trades +

+
+
+
+
+
+
+
+
+
Active Strategies
+

4

+
+ +
+

+ 2 in paper trading +

+
+
+
+
+ + +
+
+
+
+
Portfolio Performance
+
+
+ +
+
+
+
+
+
+
Top Holdings
+
+
+
+
+ AAPL + +12.4% +
+
+ MSFT + +8.7% +
+
+ GOOGL + -2.3% +
+
+ TSLA + +15.2% +
+
+ NVDA + +24.1% +
+
+
+
+
+
+ + +
+
+
+
+
Recent Trades
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TimeSymbolActionQuantityPriceP&LStatus
10:45 AMAAPLBUY50$182.34+$420Filled
10:30 AMTSLASELL25$245.67+$1,250Filled
09:15 AMMSFTBUY100$412.89PendingPending
YesterdayGOOGLSELL75$145.23-$320Filled
+
+
+
+
+
+
+ + +
+
+

+ + Data Management +

+
+
+ + +
+
+
+ + +
+
+
+
+
+
Moomoo API
+ Connected +
+

Real-time market data, historical OHLCV, order execution

+
+ Rate Limit +
+
+
+ 42/60 requests per minute +
+
+ + +
+
+
+
+
+
+
+
+
Alternative Data
+ Partial +
+

Economic calendar, news feeds, sentiment analysis

+
+ Data Quality +
+
+
+ 78% completeness +
+
+ + +
+
+
+
+
+ + +
+
+
+
+
Data Quality Dashboard
+
+
+
+
+
99.2%
+ Uptime +
+
+
12ms
+ Avg Latency +
+
+
0.8%
+ Missing Data +
+
+
3
+ Anomalies Today +
+
+ +
+
+
+
+
+ + +
+
+

+ + Strategy Engine +

+
+
+ + +
+
+
+ + +
+
+
+
+
Active Strategies
+
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StrategyTypeStatusP&LWin RateSharpeActions
+ Dual Momentum +
Large-cap US stocks +
Trend FollowingLive+$18,42068.2%1.85 + + +
+ Mean Reversion +
S&P 500 components +
Mean ReversionPaper Trading+$5,23059.7%1.12 + + +
+ Pairs Trading +
Tech sector pairs +
Statistical ArbitragePaused-$2,15052.4%0.45 + + +
+
+
+
+
+
+ + +
+
+
+
+
Backtest Results
+
+
+ +
+
+
+
+
+
+
Create New Strategy
+
+
+
+
+ + +
+
+ + +
+
+ +
+ $ + +
+
+
+ +
+
+
+
+
+
+
+ + +
+
+

+ + Risk Management +

+
+
+ + +
+
+
+ + +
+
+
+
+
4.2%
+ Max Drawdown +
+
+
+
+
+
+
1.85
+ Sharpe Ratio +
+
+
+
+
+
+
12.4%
+ Volatility (Annual) +
+
+
+
+
+
+
95%
+ VaR (1-day, 95%) +
+
+
+
+ + +
+
+
+
+
Circuit Breakers
+
+
+
+ +
+ + USD +
+
Trading pauses if daily loss exceeds this amount
+
+
+ +
+ + % +
+
Maximum allocation to any single position
+
+
+ +
+ + % +
+
Maximum allocation to any single sector
+
+
+ +
+
+
+
+
+
+
+
Risk Dashboard
+
+
+ +
+
+ + Warning: Tech sector concentration at 38% (limit: 40%) +
+
+ + All Systems Normal: All risk limits within bounds +
+
+
+
+
+
+
+ + + + + +
+
+

+ + Trade Execution +

+
+
+ + Trade Execution interface would show real-time order management, execution quality metrics, and manual trading controls. +
+
+ + +
+
+

+ + Reports & Analytics +

+
+
+ + Reports section would include performance attribution, trade journals, compliance reports, and export functionality. +
+
+ + +
+
+

+ + Alerting System +

+
+
+ + Alerting system would configure Telegram/email notifications for critical events, risk breaches, and performance milestones. +
+
+ + +
+
+

+ + Configuration +

+
+
+ + Configuration interface would manage API keys, system settings, user preferences, and integration settings. +
+
+
+
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/prototype/js/app.js b/prototype/js/app.js new file mode 100644 index 0000000..8e181b8 --- /dev/null +++ b/prototype/js/app.js @@ -0,0 +1,346 @@ +/* + * Quantitative Trading Platform - Interactive Mockup + * Main JavaScript for navigation and interactivity + */ + +// Global state +const AppState = { + currentSection: 'dashboard', + charts: {}, + mockData: {} +}; + +// Initialize the application +function initApp() { + console.log('Quantitative Trading Platform Mockup Initialized'); + + // Set up navigation + setupNavigation(); + + // Load mock data + loadMockData(); + + // Initialize charts + initCharts(); + + // Show default section + showSection('dashboard'); + + // Set up event listeners for interactive elements + setupEventListeners(); +} + +// Set up sidebar navigation +function setupNavigation() { + const navLinks = document.querySelectorAll('.nav-link[data-section]'); + + navLinks.forEach(link => { + link.addEventListener('click', function(e) { + e.preventDefault(); + const section = this.getAttribute('data-section'); + showSection(section); + + // Update active state + navLinks.forEach(l => l.classList.remove('active')); + this.classList.add('active'); + }); + }); +} + +// Show a specific section +function showSection(sectionId) { + // Hide all sections + const sections = document.querySelectorAll('.section-content'); + sections.forEach(section => { + section.classList.add('d-none'); + }); + + // Show the selected section + const targetSection = document.getElementById(`${sectionId}-section`); + if (targetSection) { + targetSection.classList.remove('d-none'); + AppState.currentSection = sectionId; + + // Update page title + const sectionTitle = targetSection.querySelector('h1, h2')?.textContent || 'Quantitative Trading Platform'; + document.title = `${sectionTitle} - Mockup`; + + // Refresh charts for the section if needed + refreshSectionCharts(sectionId); + } +} + +// Refresh charts for a specific section +function refreshSectionCharts(sectionId) { + switch(sectionId) { + case 'dashboard': + if (AppState.charts.portfolioChart) { + updatePortfolioChart(); + } + break; + case 'data-management': + if (AppState.charts.dataQualityChart) { + updateDataQualityChart(); + } + break; + case 'strategy-engine': + if (AppState.charts.backtestChart) { + updateBacktestChart(); + } + break; + case 'risk-management': + if (AppState.charts.riskChart) { + updateRiskChart(); + } + break; + } +} + +// Set up event listeners for buttons and interactive elements +function setupEventListeners() { + // Refresh buttons + const refreshButtons = document.querySelectorAll('button:contains("Refresh"), .btn-refresh'); + refreshButtons.forEach(btn => { + btn.addEventListener('click', function() { + const section = AppState.currentSection; + refreshSectionCharts(section); + + // Show toast notification + showToast('Data refreshed', 'success'); + }); + }); + + // Form submissions + const forms = document.querySelectorAll('form'); + forms.forEach(form => { + form.addEventListener('submit', function(e) { + e.preventDefault(); + showToast('Settings saved successfully', 'success'); + }); + }); + + // Toggle buttons + const toggleButtons = document.querySelectorAll('.btn[data-toggle]'); + toggleButtons.forEach(btn => { + btn.addEventListener('click', function() { + const target = this.getAttribute('data-toggle'); + const state = this.getAttribute('data-state'); + + if (target && state) { + // Toggle state + const newState = state === 'on' ? 'off' : 'on'; + this.setAttribute('data-state', newState); + + // Update button appearance + if (newState === 'on') { + this.classList.remove('btn-outline-secondary'); + this.classList.add('btn-success'); + this.innerHTML = ' ON'; + } else { + this.classList.remove('btn-success'); + this.classList.add('btn-outline-secondary'); + this.innerHTML = ' OFF'; + } + + showToast(`Feature ${newState === 'on' ? 'enabled' : 'disabled'}`, 'info'); + } + }); + }); + + // Tab clicks + const tabs = document.querySelectorAll('[data-bs-toggle="tab"]'); + tabs.forEach(tab => { + tab.addEventListener('shown.bs.tab', function() { + const tabId = this.getAttribute('data-bs-target'); + console.log(`Tab activated: ${tabId}`); + }); + }); + + // Simulate live data updates + setInterval(updateLiveData, 5000); +} + +// Update live data (simulated) +function updateLiveData() { + if (AppState.currentSection === 'dashboard') { + // Update metrics with small random changes + updateDashboardMetrics(); + } +} + +// Update dashboard metrics with random changes +function updateDashboardMetrics() { + const metrics = { + 'total-pnl': { base: 42580, range: 500 }, + 'max-drawdown': { base: 8420, range: 200 }, + 'win-rate': { base: 64.8, range: 1.5 } + }; + + for (const [id, config] of Object.entries(metrics)) { + const element = document.getElementById(id); + if (element) { + const current = parseFloat(element.textContent.replace(/[^\d.-]/g, '')); + const change = (Math.random() - 0.5) * 2 * config.range; + const newValue = config.base + change; + + // Format based on metric type + if (id === 'total-pnl' || id === 'max-drawdown') { + element.textContent = `$${Math.round(newValue).toLocaleString()}`; + } else if (id === 'win-rate') { + element.textContent = `${newValue.toFixed(1)}%`; + } + + // Add subtle animation + element.classList.add('text-highlight'); + setTimeout(() => { + element.classList.remove('text-highlight'); + }, 1000); + } + } +} + +// Show toast notification +function showToast(message, type = 'info') { + // Create toast container if it doesn't exist + let toastContainer = document.getElementById('toast-container'); + if (!toastContainer) { + toastContainer = document.createElement('div'); + toastContainer.id = 'toast-container'; + toastContainer.className = 'toast-container position-fixed bottom-0 end-0 p-3'; + document.body.appendChild(toastContainer); + } + + // Create toast + const toastId = 'toast-' + Date.now(); + const toast = document.createElement('div'); + toast.id = toastId; + toast.className = `toast align-items-center text-bg-${type} border-0`; + toast.setAttribute('role', 'alert'); + toast.setAttribute('aria-live', 'assertive'); + toast.setAttribute('aria-atomic', 'true'); + + toast.innerHTML = ` +
+
+ ${message} +
+ +
+ `; + + toastContainer.appendChild(toast); + + // Initialize and show toast + const bsToast = new bootstrap.Toast(toast, { delay: 3000 }); + bsToast.show(); + + // Remove toast after it's hidden + toast.addEventListener('hidden.bs.toast', function() { + toast.remove(); + }); +} + +// Load mock data +function loadMockData() { + // Generate mock data for charts + AppState.mockData = { + portfolioData: generatePortfolioData(), + dataQualityData: generateDataQualityData(), + backtestData: generateBacktestData(), + riskData: generateRiskData() + }; +} + +// Generate mock portfolio data +function generatePortfolioData() { + const data = []; + let value = 100000; + + for (let i = 0; i < 30; i++) { + const date = new Date(); + date.setDate(date.getDate() - (30 - i)); + + // Random walk with drift + const change = (Math.random() - 0.4) * 0.02 * value; + value += change; + + data.push({ + date: date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }), + value: Math.max(90000, value) + }); + } + + return data; +} + +// Generate mock data quality data +function generateDataQualityData() { + const data = []; + + for (let i = 0; i < 7; i++) { + const date = new Date(); + date.setDate(date.getDate() - (7 - i)); + + data.push({ + date: date.toLocaleDateString('en-US', { weekday: 'short' }), + completeness: 90 + Math.random() * 8, + latency: 5 + Math.random() * 15, + errors: Math.floor(Math.random() * 5) + }); + } + + return data; +} + +// Generate mock backtest data +function generateBacktestData() { + const strategies = ['Dual Momentum', 'Mean Reversion', 'Pairs Trading']; + const data = []; + + strategies.forEach(strategy => { + let returns = 100; + const returnsData = []; + + for (let i = 0; i < 12; i++) { + const monthlyReturn = (Math.random() - 0.2) * 0.1; + returns *= (1 + monthlyReturn); + returnsData.push(returns); + } + + data.push({ + strategy, + returns: returnsData, + sharpe: 0.8 + Math.random() * 1.5, + winRate: 50 + Math.random() * 30 + }); + }); + + return data; +} + +// Generate mock risk data +function generateRiskData() { + const metrics = ['VaR', 'CVaR', 'Max Drawdown', 'Volatility']; + const data = []; + + metrics.forEach(metric => { + const values = []; + for (let i = 0; i < 10; i++) { + values.push(Math.random() * 10); + } + data.push({ metric, values }); + }); + + return data; +} + +// Initialize when DOM is loaded +document.addEventListener('DOMContentLoaded', initApp); + +// Export for use in other scripts +window.App = { + showSection, + showToast, + refreshSectionCharts, + state: AppState +}; \ No newline at end of file diff --git a/prototype/js/mock-data.js b/prototype/js/mock-data.js new file mode 100644 index 0000000..04af5d6 --- /dev/null +++ b/prototype/js/mock-data.js @@ -0,0 +1,414 @@ +/* + * Quantitative Trading Platform - Interactive Mockup + * Mock data generation for charts and displays + */ + +// Chart initialization +function initCharts() { + // Initialize Portfolio Chart + initPortfolioChart(); + + // Initialize Data Quality Chart + initDataQualityChart(); + + // Initialize Backtest Chart + initBacktestChart(); + + // Initialize Risk Chart + initRiskChart(); +} + +// Portfolio Performance Chart +function initPortfolioChart() { + const ctx = document.getElementById('portfolioChart'); + if (!ctx) return; + + const data = generatePortfolioData(); + + AppState.charts.portfolioChart = new Chart(ctx, { + type: 'line', + data: { + labels: data.map(d => d.date), + datasets: [{ + label: 'Portfolio Value', + data: data.map(d => d.value), + borderColor: '#4caf50', + backgroundColor: 'rgba(76, 175, 80, 0.1)', + fill: true, + tension: 0.4, + pointRadius: 2, + pointHoverRadius: 5 + }] + }, + options: { + responsive: true, + maintainAspectRatio: false, + plugins: { + legend: { + display: false + }, + tooltip: { + mode: 'index', + intersect: false, + callbacks: { + label: function(context) { + return `$${context.parsed.y.toLocaleString()}`; + } + } + } + }, + scales: { + x: { + grid: { + color: 'rgba(255, 255, 255, 0.05)' + }, + ticks: { + color: '#b0bec5' + } + }, + y: { + grid: { + color: 'rgba(255, 255, 255, 0.05)' + }, + ticks: { + color: '#b0bec5', + callback: function(value) { + return '$' + (value / 1000).toFixed(0) + 'k'; + } + } + } + } + } + }); +} + +// Data Quality Chart +function initDataQualityChart() { + const ctx = document.getElementById('dataQualityChart'); + if (!ctx) return; + + const data = generateDataQualityData(); + + AppState.charts.dataQualityChart = new Chart(ctx, { + type: 'line', + data: { + labels: data.map(d => d.date), + datasets: [ + { + label: 'Completeness (%)', + data: data.map(d => d.completeness), + borderColor: '#4caf50', + backgroundColor: 'rgba(76, 175, 80, 0.1)', + fill: true, + tension: 0.4, + yAxisID: 'y' + }, + { + label: 'Latency (ms)', + data: data.map(d => d.latency), + borderColor: '#2196f3', + backgroundColor: 'rgba(33, 150, 243, 0.1)', + fill: true, + tension: 0.4, + yAxisID: 'y1' + } + ] + }, + options: { + responsive: true, + maintainAspectRatio: false, + plugins: { + legend: { + position: 'top', + labels: { + color: '#b0bec5' + } + } + }, + scales: { + x: { + grid: { + color: 'rgba(255, 255, 255, 0.05)' + }, + ticks: { + color: '#b0bec5' + } + }, + y: { + type: 'linear', + display: true, + position: 'left', + min: 80, + max: 100, + grid: { + color: 'rgba(255, 255, 255, 0.05)' + }, + ticks: { + color: '#b0bec5', + callback: function(value) { + return value + '%'; + } + } + }, + y1: { + type: 'linear', + display: true, + position: 'right', + min: 0, + max: 30, + grid: { + drawOnChartArea: false + }, + ticks: { + color: '#b0bec5', + callback: function(value) { + return value + 'ms'; + } + } + } + } + } + }); +} + +// Backtest Results Chart +function initBacktestChart() { + const ctx = document.getElementById('backtestChart'); + if (!ctx) return; + + const data = generateBacktestData(); + + AppState.charts.backtestChart = new Chart(ctx, { + type: 'line', + data: { + labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + datasets: data.map((strategy, index) => { + const colors = ['#4caf50', '#2196f3', '#9c27b0']; + return { + label: strategy.strategy, + data: strategy.returns, + borderColor: colors[index], + backgroundColor: colors[index] + '20', + fill: false, + tension: 0.4 + }; + }) + }, + options: { + responsive: true, + maintainAspectRatio: false, + plugins: { + legend: { + position: 'top', + labels: { + color: '#b0bec5' + } + } + }, + scales: { + x: { + grid: { + color: 'rgba(255, 255, 255, 0.05)' + }, + ticks: { + color: '#b0bec5' + } + }, + y: { + grid: { + color: 'rgba(255, 255, 255, 0.05)' + }, + ticks: { + color: '#b0bec5', + callback: function(value) { + return '$' + value.toLocaleString(); + } + } + } + } + } + }); +} + +// Risk Management Chart +function initRiskChart() { + const ctx = document.getElementById('riskChart'); + if (!ctx) return; + + const data = generateRiskData(); + + AppState.charts.riskChart = new Chart(ctx, { + type: 'radar', + data: { + labels: data.map(d => d.metric), + datasets: [{ + label: 'Risk Metrics', + data: data.map(d => d.values[0]), + backgroundColor: 'rgba(255, 152, 0, 0.2)', + borderColor: 'rgba(255, 152, 0, 1)', + pointBackgroundColor: 'rgba(255, 152, 0, 1)', + pointBorderColor: '#fff', + pointHoverBackgroundColor: '#fff', + pointHoverBorderColor: 'rgba(255, 152, 0, 1)' + }] + }, + options: { + responsive: true, + maintainAspectRatio: false, + plugins: { + legend: { + display: false + } + }, + scales: { + r: { + angleLines: { + color: 'rgba(255, 255, 255, 0.1)' + }, + grid: { + color: 'rgba(255, 255, 255, 0.1)' + }, + pointLabels: { + color: '#b0bec5' + }, + ticks: { + color: '#b0bec5', + backdropColor: 'transparent' + }, + min: 0, + max: 10 + } + } + } + }); +} + +// Update functions for live data +function updatePortfolioChart() { + if (!AppState.charts.portfolioChart) return; + + const newData = generatePortfolioData(); + AppState.charts.portfolioChart.data.labels = newData.map(d => d.date); + AppState.charts.portfolioChart.data.datasets[0].data = newData.map(d => d.value); + AppState.charts.portfolioChart.update('none'); +} + +function updateDataQualityChart() { + if (!AppState.charts.dataQualityChart) return; + + const newData = generateDataQualityData(); + AppState.charts.dataQualityChart.data.labels = newData.map(d => d.date); + AppState.charts.dataQualityChart.data.datasets[0].data = newData.map(d => d.completeness); + AppState.charts.dataQualityChart.data.datasets[1].data = newData.map(d => d.latency); + AppState.charts.dataQualityChart.update('none'); +} + +function updateBacktestChart() { + if (!AppState.charts.backtestChart) return; + + const newData = generateBacktestData(); + newData.forEach((strategy, index) => { + AppState.charts.backtestChart.data.datasets[index].data = strategy.returns; + }); + AppState.charts.backtestChart.update('none'); +} + +function updateRiskChart() { + if (!AppState.charts.riskChart) return; + + const newData = generateRiskData(); + AppState.charts.riskChart.data.datasets[0].data = newData.map(d => d.values[0]); + AppState.charts.riskChart.update('none'); +} + +// Data generation functions (same as in app.js but exported for use) +function generatePortfolioData() { + const data = []; + let value = 100000; + + for (let i = 0; i < 30; i++) { + const date = new Date(); + date.setDate(date.getDate() - (30 - i)); + + const change = (Math.random() - 0.4) * 0.02 * value; + value += change; + + data.push({ + date: date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }), + value: Math.max(90000, value) + }); + } + + return data; +} + +function generateDataQualityData() { + const data = []; + + for (let i = 0; i < 7; i++) { + const date = new Date(); + date.setDate(date.getDate() - (7 - i)); + + data.push({ + date: date.toLocaleDateString('en-US', { weekday: 'short' }), + completeness: 90 + Math.random() * 8, + latency: 5 + Math.random() * 15, + errors: Math.floor(Math.random() * 5) + }); + } + + return data; +} + +function generateBacktestData() { + const strategies = ['Dual Momentum', 'Mean Reversion', 'Pairs Trading']; + const data = []; + + strategies.forEach(strategy => { + let returns = 100; + const returnsData = []; + + for (let i = 0; i < 12; i++) { + const monthlyReturn = (Math.random() - 0.2) * 0.1; + returns *= (1 + monthlyReturn); + returnsData.push(returns); + } + + data.push({ + strategy, + returns: returnsData, + sharpe: 0.8 + Math.random() * 1.5, + winRate: 50 + Math.random() * 30 + }); + }); + + return data; +} + +function generateRiskData() { + const metrics = ['VaR', 'CVaR', 'Max Drawdown', 'Volatility']; + const data = []; + + metrics.forEach(metric => { + const values = []; + for (let i = 0; i < 10; i++) { + values.push(Math.random() * 10); + } + data.push({ metric, values }); + }); + + return data; +} + +// Export for use in other scripts +window.MockData = { + initCharts, + updatePortfolioChart, + updateDataQualityChart, + updateBacktestChart, + updateRiskChart, + generatePortfolioData, + generateDataQualityData, + generateBacktestData, + generateRiskData +}; \ No newline at end of file