diff --git a/ANNOTATE/core/real_training_adapter.py b/ANNOTATE/core/real_training_adapter.py index 316bb1b..64d59b5 100644 --- a/ANNOTATE/core/real_training_adapter.py +++ b/ANNOTATE/core/real_training_adapter.py @@ -116,6 +116,8 @@ class TrainingSession: error: Optional[str] = None gpu_utilization: Optional[float] = None # GPU utilization percentage cpu_utilization: Optional[float] = None # CPU utilization percentage + annotation_count: Optional[int] = None # Number of annotations used + timeframe: Optional[str] = None # Primary timeframe (e.g., '1m', '5m') class RealTrainingAdapter: @@ -208,13 +210,17 @@ class RealTrainingAdapter: logger.info(f"Available models for training: {available}") return available - def start_training(self, model_name: str, test_cases: List[Dict]) -> str: + def start_training(self, model_name: str, test_cases: List[Dict], + annotation_count: Optional[int] = None, + timeframe: Optional[str] = None) -> str: """ Start REAL training session with test cases Args: model_name: Name of model to train (CNN, DQN, Transformer, COB, Extrema) test_cases: List of test cases from annotations + annotation_count: Number of annotations used (optional) + timeframe: Primary timeframe for training (optional, e.g., '1m', '5m') Returns: training_id: Unique ID for this training session @@ -224,6 +230,10 @@ class RealTrainingAdapter: training_id = str(uuid.uuid4()) + # Use annotation_count if provided, otherwise use test_cases count + if annotation_count is None: + annotation_count = len(test_cases) + # Create training session session = TrainingSession( training_id=training_id, @@ -233,7 +243,9 @@ class RealTrainingAdapter: current_epoch=0, total_epochs=10, # Reasonable for annotation-based training current_loss=0.0, - start_time=time.time() + start_time=time.time(), + annotation_count=annotation_count, + timeframe=timeframe ) self.training_sessions[training_id] = session @@ -2358,7 +2370,9 @@ class RealTrainingAdapter: 'current_epoch': session.current_epoch, 'total_epochs': session.total_epochs, 'current_loss': session.current_loss, - 'start_time': session.start_time + 'start_time': session.start_time, + 'annotation_count': session.annotation_count, + 'timeframe': session.timeframe } return None diff --git a/ANNOTATE/data/annotations/annotations_db.json b/ANNOTATE/data/annotations/annotations_db.json index 4a88ccb..4afa356 100644 --- a/ANNOTATE/data/annotations/annotations_db.json +++ b/ANNOTATE/data/annotations/annotations_db.json @@ -46,29 +46,6 @@ "exit_state": {} } }, - { - "annotation_id": "91847a37-6315-4546-b5a0-573118311322", - "symbol": "ETH/USDT", - "timeframe": "1s", - "entry": { - "timestamp": "2025-10-25 13:08:04", - "price": 3940.24, - "index": 25 - }, - "exit": { - "timestamp": "2025-10-25 13:15:12", - "price": 3942.59, - "index": 57 - }, - "direction": "LONG", - "profit_loss_pct": 0.05964103709419639, - "notes": "", - "created_at": "2025-10-25T16:17:02.931920", - "market_context": { - "entry_state": {}, - "exit_state": {} - } - }, { "annotation_id": "479eb310-c963-4837-b712-70e5a42afb53", "symbol": "ETH/USDT", @@ -137,10 +114,33 @@ "entry_state": {}, "exit_state": {} } + }, + { + "annotation_id": "46cc0e20-0bfb-498c-9358-71b52a003d0f", + "symbol": "ETH/USDT", + "timeframe": "1s", + "entry": { + "timestamp": "2025-11-22 12:50", + "price": 2712.11, + "index": 26 + }, + "exit": { + "timestamp": "2025-11-22 12:53:06", + "price": 2721.44, + "index": 45 + }, + "direction": "LONG", + "profit_loss_pct": 0.3440125953593301, + "notes": "", + "created_at": "2025-11-22T15:19:00.480166", + "market_context": { + "entry_state": {}, + "exit_state": {} + } } ], "metadata": { "total_annotations": 6, - "last_updated": "2025-11-12T13:11:31.267456" + "last_updated": "2025-11-22T15:19:15.521679" } } \ No newline at end of file diff --git a/ANNOTATE/web/app.py b/ANNOTATE/web/app.py index 2d22553..109a153 100644 --- a/ANNOTATE/web/app.py +++ b/ANNOTATE/web/app.py @@ -626,8 +626,7 @@ class AnnotationDashboard: if not self.orchestrator: logger.info("Initializing TradingOrchestrator...") self.orchestrator = TradingOrchestrator( - data_provider=self.data_provider, - config=self.config + data_provider=self.data_provider ) self.training_adapter.orchestrator = self.orchestrator logger.info("TradingOrchestrator initialized") @@ -1709,6 +1708,9 @@ class AnnotationDashboard: # CRITICAL: Get current symbol to filter annotations current_symbol = data.get('symbol', 'ETH/USDT') + # Get primary timeframe for display (optional) + timeframe = data.get('timeframe', '1m') + # If no specific annotations provided, use all for current symbol if not annotation_ids: annotations = self.annotation_manager.get_annotations(symbol=current_symbol) @@ -1737,12 +1739,14 @@ class AnnotationDashboard: } }) - logger.info(f"Starting REAL training with {len(test_cases)} test cases for model {model_name}") + logger.info(f"Starting REAL training with {len(test_cases)} test cases ({len(annotation_ids)} annotations) for model {model_name} on {timeframe}") # Start REAL training (NO SIMULATION!) training_id = self.training_adapter.start_training( model_name=model_name, - test_cases=test_cases + test_cases=test_cases, + annotation_count=len(annotation_ids), + timeframe=timeframe ) return jsonify({ diff --git a/ANNOTATE/web/static/css/annotation_ui.css b/ANNOTATE/web/static/css/annotation_ui.css index c95a43c..d9c5809 100644 --- a/ANNOTATE/web/static/css/annotation_ui.css +++ b/ANNOTATE/web/static/css/annotation_ui.css @@ -10,6 +10,7 @@ /* Chart Panel */ .chart-panel { height: calc(100vh - 150px); + transition: all 0.3s ease; } .chart-panel .card-body { @@ -17,6 +18,29 @@ overflow: hidden; } +/* Maximized Chart View */ +.chart-maximized { + width: 100% !important; + max-width: 100% !important; + flex: 0 0 100% !important; + transition: all 0.3s ease; +} + +.chart-panel-maximized { + height: calc(100vh - 80px) !important; + position: fixed; + top: 60px; + left: 0; + right: 0; + z-index: 1040; + margin: 0 !important; + border-radius: 0 !important; +} + +.chart-panel-maximized .card-body { + height: calc(100% - 60px); +} + #chart-container { height: 100%; overflow-y: auto; @@ -236,11 +260,32 @@ padding: 1rem; } +/* Maximized View - Larger Charts */ +.chart-panel-maximized .chart-plot { + height: 400px; +} + +@media (min-width: 1400px) { + .chart-panel-maximized .chart-plot { + height: 450px; + } +} + +@media (min-width: 1920px) { + .chart-panel-maximized .chart-plot { + height: 500px; + } +} + /* Responsive Adjustments */ @media (max-width: 1200px) { .chart-plot { height: 250px; } + + .chart-panel-maximized .chart-plot { + height: 350px; + } } @media (max-width: 768px) { diff --git a/ANNOTATE/web/templates/annotation_dashboard.html b/ANNOTATE/web/templates/annotation_dashboard.html index 95b51f5..8d97844 100644 --- a/ANNOTATE/web/templates/annotation_dashboard.html +++ b/ANNOTATE/web/templates/annotation_dashboard.html @@ -101,6 +101,23 @@ if (typeof checkActiveTraining === 'function') { checkActiveTraining(); } + + // Keyboard shortcuts for chart maximization + document.addEventListener('keydown', function(e) { + // ESC key to exit maximized mode + if (e.key === 'Escape') { + const chartArea = document.querySelector('.chart-maximized'); + if (chartArea) { + document.getElementById('maximize-btn').click(); + } + } + + // F key to toggle maximize (when not typing in input) + if (e.key === 'f' && !e.ctrlKey && !e.metaKey && + !['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement.tagName)) { + document.getElementById('maximize-btn').click(); + } + }); // Setup keyboard shortcuts setupKeyboardShortcuts(); diff --git a/ANNOTATE/web/templates/components/chart_panel.html b/ANNOTATE/web/templates/components/chart_panel.html index 46ada4f..d3207d3 100644 --- a/ANNOTATE/web/templates/components/chart_panel.html +++ b/ANNOTATE/web/templates/components/chart_panel.html @@ -14,6 +14,9 @@ + @@ -110,6 +113,41 @@ } }); + document.getElementById('maximize-btn').addEventListener('click', function () { + const mainRow = document.querySelector('.row.mt-3'); + const leftSidebar = mainRow.querySelector('.col-md-2:first-child'); + const chartArea = mainRow.querySelector('.col-md-8'); + const rightSidebar = mainRow.querySelector('.col-md-2:last-child'); + const chartPanel = document.querySelector('.chart-panel'); + const maximizeIcon = this.querySelector('i'); + + // Toggle maximize state + if (chartArea.classList.contains('chart-maximized')) { + // Restore normal view + leftSidebar.style.display = ''; + rightSidebar.style.display = ''; + chartArea.classList.remove('chart-maximized'); + chartPanel.classList.remove('chart-panel-maximized'); + maximizeIcon.className = 'fas fa-arrows-alt'; + this.title = 'Maximize Chart Area'; + } else { + // Maximize chart area + leftSidebar.style.display = 'none'; + rightSidebar.style.display = 'none'; + chartArea.classList.add('chart-maximized'); + chartPanel.classList.add('chart-panel-maximized'); + maximizeIcon.className = 'fas fa-compress-arrows-alt'; + this.title = 'Restore Normal View'; + } + + // Update chart layouts after transition + setTimeout(() => { + if (window.appState && window.appState.chartManager) { + window.appState.chartManager.updateChartLayout(); + } + }, 350); + }); + document.getElementById('fullscreen-btn').addEventListener('click', function () { const chartContainer = document.getElementById('chart-container'); if (chartContainer.requestFullscreen) { diff --git a/ANNOTATE/web/templates/components/training_panel.html b/ANNOTATE/web/templates/components/training_panel.html index 3c76555..4c616cd 100644 --- a/ANNOTATE/web/templates/components/training_panel.html +++ b/ANNOTATE/web/templates/components/training_panel.html @@ -40,9 +40,13 @@ role="progressbar" style="width: 0%">
-
Epoch: 0/0
-
Loss: --
-
GPU: --% | CPU: --%
+
Annotations: --
+
Timeframe: --
+
+
Epoch: 0/0
+
Loss: --
+
GPU: --% | CPU: --%
+
@@ -193,6 +197,15 @@ // Resume tracking activeTrainingId = data.session.training_id; showTrainingStatus(); + + // Populate annotation count and timeframe if available + if (data.session.annotation_count) { + document.getElementById('training-annotation-count').textContent = data.session.annotation_count; + } + if (data.session.timeframe) { + document.getElementById('training-timeframe').textContent = data.session.timeframe.toUpperCase(); + } + pollTrainingProgress(activeTrainingId); } else { console.log('No active training session'); @@ -408,10 +421,17 @@ // Show training status showTrainingStatus(); + // Get primary timeframe for training + const primaryTimeframe = document.getElementById('primary-timeframe-select').value; + // Reset progress document.getElementById('training-progress-bar').style.width = '0%'; document.getElementById('training-epoch').textContent = '0'; document.getElementById('training-loss').textContent = '--'; + + // Set annotation count and timeframe + document.getElementById('training-annotation-count').textContent = annotationIds.length; + document.getElementById('training-timeframe').textContent = primaryTimeframe.toUpperCase(); // Start training request fetch('/api/train-model', { @@ -420,7 +440,8 @@ body: JSON.stringify({ model_name: modelName, annotation_ids: annotationIds, - symbol: appState.currentSymbol // CRITICAL: Filter by current symbol + symbol: appState.currentSymbol, // CRITICAL: Filter by current symbol + timeframe: primaryTimeframe // Primary timeframe for display }) }) .then(response => response.json())