/** * MLDashboard Page * Main dashboard for ML predictions and signals * Enhanced with ICT/SMC Analysis and Ensemble Signals */ import React, { useEffect, useState, useCallback } from 'react'; import { SparklesIcon, FunnelIcon, ArrowPathIcon, ExclamationTriangleIcon, ChartBarIcon, BeakerIcon, CpuChipIcon, } from '@heroicons/react/24/solid'; import { getActiveSignals, getAMDPhase, getICTAnalysis, getEnsembleSignal, scanSymbols, type MLSignal, type AMDPhase, type ICTAnalysis, type EnsembleSignal, type ScanResult, } from '../../../services/mlService'; import { AMDPhaseIndicator } from '../components/AMDPhaseIndicator'; import { PredictionCard } from '../components/PredictionCard'; import { SignalsTimeline } from '../components/SignalsTimeline'; import { AccuracyMetrics } from '../components/AccuracyMetrics'; import { ICTAnalysisCard } from '../components/ICTAnalysisCard'; import { EnsembleSignalCard } from '../components/EnsembleSignalCard'; import EnsemblePanel, { type EnsembleConfig } from '../components/EnsemblePanel'; // Mock accuracy metrics (replace with API call) const mockMetrics = { overall_accuracy: 68.5, win_rate: 62.3, total_signals: 156, successful_signals: 97, failed_signals: 59, avg_risk_reward: 2.3, avg_confidence: 72, best_performing_phase: 'accumulation', sharpe_ratio: 1.8, profit_factor: 1.7, }; // Available symbols and timeframes - Configurable list // Includes Forex majors, commodities, and crypto const SYMBOLS = [ 'EURUSD', // EUR/USD - Forex major 'GBPUSD', // GBP/USD - Forex major 'USDJPY', // USD/JPY - Forex major 'XAUUSD', // XAU/USD - Gold 'BTCUSD', // BTC/USD - Bitcoin 'ETHUSD', // ETH/USD - Ethereum 'USDCHF', // USD/CHF - Forex major 'AUDUSD', // AUD/USD - Forex major ]; const TIMEFRAMES = ['15M', '30M', '1H', '4H', '1D']; // Default ensemble configuration for model weights const DEFAULT_ENSEMBLE_CONFIG: EnsembleConfig = { votingMethod: 'weighted', minimumAgreement: 2, confidenceThreshold: 60, weights: [ { modelId: 'amd', modelName: 'AMD Phase Detector', weight: 25, accuracy: 72 }, { modelId: 'ict', modelName: 'ICT/SMC Analyzer', weight: 30, accuracy: 75 }, { modelId: 'range', modelName: 'Range Predictor', weight: 25, accuracy: 68 }, { modelId: 'tpsl', modelName: 'TP/SL Optimizer', weight: 20, accuracy: 70 }, ], }; export default function MLDashboard() { const [signals, setSignals] = useState([]); const [amdPhases, setAmdPhases] = useState>(new Map()); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [lastUpdate, setLastUpdate] = useState(null); // ICT/SMC and Ensemble data const [ictAnalysis, setIctAnalysis] = useState(null); const [ensembleSignal, setEnsembleSignal] = useState(null); const [scanResults, setScanResults] = useState([]); const [activeTab, setActiveTab] = useState<'signals' | 'ict' | 'ensemble'>('signals'); // Filters const [selectedSymbol, setSelectedSymbol] = useState('EURUSD'); const [selectedTimeframe, setSelectedTimeframe] = useState('1H'); const [showOnlyActive, setShowOnlyActive] = useState(true); // Ensemble configuration state const [ensembleConfig, setEnsembleConfig] = useState(DEFAULT_ENSEMBLE_CONFIG); const [showEnsembleConfig, setShowEnsembleConfig] = useState(false); // Fetch all ML data const fetchMLData = useCallback(async () => { setLoading(true); setError(null); try { // Fetch active signals const activeSignals = await getActiveSignals(); setSignals(activeSignals); // Fetch AMD phases for each unique symbol const uniqueSymbols = [...new Set(activeSignals.map(s => s.symbol))]; const amdPhasesMap = new Map(); await Promise.all( uniqueSymbols.map(async (symbol) => { try { const phase = await getAMDPhase(symbol); if (phase) { amdPhasesMap.set(symbol, phase); } } catch (err) { console.error(`Failed to fetch AMD phase for ${symbol}:`, err); } }) ); setAmdPhases(amdPhasesMap); setLastUpdate(new Date()); } catch (err) { setError('Failed to fetch ML data'); console.error('ML data fetch error:', err); } finally { setLoading(false); } }, []); // Fetch ICT and Ensemble data for selected symbol const fetchAdvancedAnalysis = useCallback(async () => { try { const [ict, ensemble, scan] = await Promise.all([ getICTAnalysis(selectedSymbol, selectedTimeframe), getEnsembleSignal(selectedSymbol, selectedTimeframe), scanSymbols(SYMBOLS, 0.5), ]); setIctAnalysis(ict); setEnsembleSignal(ensemble); setScanResults(scan); } catch (err) { console.error('Failed to fetch advanced analysis:', err); } }, [selectedSymbol, selectedTimeframe]); // Handle symbol/timeframe change useEffect(() => { fetchAdvancedAnalysis(); }, [selectedSymbol, selectedTimeframe, fetchAdvancedAnalysis]); // Initial fetch useEffect(() => { fetchMLData(); // Auto-refresh every 60 seconds const interval = setInterval(fetchMLData, 60000); return () => clearInterval(interval); }, [fetchMLData]); // Filter signals const filteredSignals = signals.filter((signal) => { if (selectedSymbol !== 'all' && signal.symbol !== selectedSymbol) return false; if (showOnlyActive) { const isValid = new Date(signal.valid_until) > new Date(); if (!isValid) return false; } return true; }); // Get unique symbols for filter const uniqueSymbols = [...new Set(signals.map(s => s.symbol))]; // Get primary AMD phase (most common or highest confidence) const getPrimaryAMDPhase = (): AMDPhase | null => { const phases = Array.from(amdPhases.values()); if (phases.length === 0) return null; // Return the phase with highest confidence return phases.reduce((prev, current) => (current.confidence > prev.confidence) ? current : prev ); }; const primaryPhase = getPrimaryAMDPhase(); // Handle trade execution const handleExecuteTrade = (signal: MLSignal) => { // Navigate to trading page with pre-filled signal window.location.href = `/trading?symbol=${signal.symbol}&signal=${signal.signal_id}`; }; // Handle advanced trade execution (ICT/Ensemble) const handleAdvancedTrade = (direction: 'buy' | 'sell', data: unknown) => { console.log('Execute trade:', direction, data); alert(`Would execute ${direction.toUpperCase()} trade for ${selectedSymbol}`); }; // Handle ensemble config changes const handleEnsembleConfigChange = (newConfig: EnsembleConfig) => { setEnsembleConfig(newConfig); }; const handleSaveEnsembleConfig = () => { // Save ensemble config to localStorage for persistence localStorage.setItem('ensembleConfig', JSON.stringify(ensembleConfig)); setShowEnsembleConfig(false); // Refetch ensemble signal with new weights fetchAdvancedAnalysis(); }; const handleResetEnsembleConfig = () => { setEnsembleConfig(DEFAULT_ENSEMBLE_CONFIG); }; // Calculate combined ensemble prediction based on current weights const getWeightedEnsemblePrediction = useCallback(() => { if (!ensembleSignal) return null; const strategies = ensembleSignal.strategy_signals; const weights = ensembleConfig.weights; let totalWeightedScore = 0; let totalWeight = 0; let agreementCount = 0; const action = ensembleSignal.action; // Calculate weighted score based on user-configured weights weights.forEach((w) => { const strategyKey = w.modelId as keyof typeof strategies; const strategy = strategies[strategyKey]; if (strategy) { const normalizedWeight = w.weight / 100; totalWeightedScore += strategy.score * normalizedWeight; totalWeight += normalizedWeight; // Count agreement if ( (action === 'BUY' && strategy.action === 'BUY') || (action === 'SELL' && strategy.action === 'SELL') ) { agreementCount++; } } }); const adjustedConfidence = totalWeight > 0 ? totalWeightedScore / totalWeight : 0; const meetsAgreement = agreementCount >= ensembleConfig.minimumAgreement; const meetsConfidence = Math.abs(adjustedConfidence) * 100 >= ensembleConfig.confidenceThreshold; return { adjustedScore: adjustedConfidence, agreementCount, meetsAgreement, meetsConfidence, isValidSignal: meetsAgreement && meetsConfidence, }; }, [ensembleSignal, ensembleConfig]); return (
{/* Header */}

ML Predictions Dashboard

AI-powered trading signals and market analysis

{lastUpdate && ( Updated {lastUpdate.toLocaleTimeString()} )}
{/* Error Message */} {error && (

{error}

Please try again or contact support

)} {/* Primary AMD Phase Indicator */} {primaryPhase && (
)} {/* Symbol and Timeframe Selector */}
{/* Symbol Selector */}
{SYMBOLS.map((sym) => ( ))}
{/* Timeframe Selector */}
{TIMEFRAMES.map((tf) => ( ))}
{/* Analysis Tabs */}
{/* Tab Content - ICT Analysis */} {activeTab === 'ict' && (
{ictAnalysis ? ( ) : (
Loading ICT analysis...
)} {/* Scanner Results */}

Market Scanner ({scanResults.length} opportunities)

{scanResults.length > 0 ? (
{scanResults.map((result, idx) => ( ))}
) : (
No opportunities found
)}
)} {/* Tab Content - Ensemble Signal */} {activeTab === 'ensemble' && (
{/* Ensemble Controls */}

Ensemble Analysis

{/* Weighted Prediction Summary */} {ensembleSignal && (

Weighted Ensemble Prediction

{ensembleSignal.action} {Math.round(ensembleSignal.confidence * 100)}% confidence
{(() => { const prediction = getWeightedEnsemblePrediction(); if (!prediction) return null; return (
{prediction.isValidSignal ? 'Signal Valid' : 'Signal Weak'}
{prediction.agreementCount}/{ensembleConfig.weights.length} models agree
); })()}
)} {/* Ensemble Configuration Panel */} {showEnsembleConfig && ( )}
{ensembleSignal ? ( ) : (
Loading ensemble signal...
)} {/* Quick comparison of all symbols */}

All Symbols Overview

{scanResults.map((result, idx) => ( ))}
)} {/* Tab Content - Original ML Signals */} {activeTab === 'signals' && ( <> {/* Filters and Stats Bar */}
{/* Filters */}
{/* Active Only Toggle */}
{/* Stats */}
Total Signals: {signals.length}
Active: {filteredSignals.length}
{/* Main Content Grid */}
{/* Left Column - Active Signals */}

Active Predictions

{loading ? (
Loading signals...
) : filteredSignals.length > 0 ? (
{filteredSignals.map((signal) => ( ))}
) : (

No active signals found

{selectedSymbol !== 'all' ? `No signals for ${selectedSymbol}` : 'Try adjusting your filters or refresh to load new signals'}

)}
{/* Signals Timeline */}
{/* Right Column - Metrics and Info */}
{/* Accuracy Metrics */} {/* AMD Phases by Symbol */} {amdPhases.size > 0 && (

AMD Phases by Symbol

{Array.from(amdPhases.entries()).map(([symbol, phase]) => (
{symbol} {Math.round(phase.confidence * 100)}% confidence
))}
)} {/* Quick Stats Card */}

Quick Stats

Avg Confidence {signals.length > 0 ? Math.round( signals.reduce((sum, s) => sum + s.confidence_score, 0) / signals.length * 100 ) : 0} %
Avg Risk:Reward {signals.length > 0 ? ( signals.reduce((sum, s) => sum + s.risk_reward_ratio, 0) / signals.length ).toFixed(1) : '0.0'}
Tracked Symbols {uniqueSymbols.length}
)}
); }