ui fixes
This commit is contained in:
@@ -116,6 +116,8 @@ class TrainingSession:
|
|||||||
error: Optional[str] = None
|
error: Optional[str] = None
|
||||||
gpu_utilization: Optional[float] = None # GPU utilization percentage
|
gpu_utilization: Optional[float] = None # GPU utilization percentage
|
||||||
cpu_utilization: Optional[float] = None # CPU 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:
|
class RealTrainingAdapter:
|
||||||
@@ -208,13 +210,17 @@ class RealTrainingAdapter:
|
|||||||
logger.info(f"Available models for training: {available}")
|
logger.info(f"Available models for training: {available}")
|
||||||
return 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
|
Start REAL training session with test cases
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
model_name: Name of model to train (CNN, DQN, Transformer, COB, Extrema)
|
model_name: Name of model to train (CNN, DQN, Transformer, COB, Extrema)
|
||||||
test_cases: List of test cases from annotations
|
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:
|
Returns:
|
||||||
training_id: Unique ID for this training session
|
training_id: Unique ID for this training session
|
||||||
@@ -224,6 +230,10 @@ class RealTrainingAdapter:
|
|||||||
|
|
||||||
training_id = str(uuid.uuid4())
|
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
|
# Create training session
|
||||||
session = TrainingSession(
|
session = TrainingSession(
|
||||||
training_id=training_id,
|
training_id=training_id,
|
||||||
@@ -233,7 +243,9 @@ class RealTrainingAdapter:
|
|||||||
current_epoch=0,
|
current_epoch=0,
|
||||||
total_epochs=10, # Reasonable for annotation-based training
|
total_epochs=10, # Reasonable for annotation-based training
|
||||||
current_loss=0.0,
|
current_loss=0.0,
|
||||||
start_time=time.time()
|
start_time=time.time(),
|
||||||
|
annotation_count=annotation_count,
|
||||||
|
timeframe=timeframe
|
||||||
)
|
)
|
||||||
|
|
||||||
self.training_sessions[training_id] = session
|
self.training_sessions[training_id] = session
|
||||||
@@ -2358,7 +2370,9 @@ class RealTrainingAdapter:
|
|||||||
'current_epoch': session.current_epoch,
|
'current_epoch': session.current_epoch,
|
||||||
'total_epochs': session.total_epochs,
|
'total_epochs': session.total_epochs,
|
||||||
'current_loss': session.current_loss,
|
'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
|
return None
|
||||||
|
|||||||
@@ -46,29 +46,6 @@
|
|||||||
"exit_state": {}
|
"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",
|
"annotation_id": "479eb310-c963-4837-b712-70e5a42afb53",
|
||||||
"symbol": "ETH/USDT",
|
"symbol": "ETH/USDT",
|
||||||
@@ -137,10 +114,33 @@
|
|||||||
"entry_state": {},
|
"entry_state": {},
|
||||||
"exit_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": {
|
"metadata": {
|
||||||
"total_annotations": 6,
|
"total_annotations": 6,
|
||||||
"last_updated": "2025-11-12T13:11:31.267456"
|
"last_updated": "2025-11-22T15:19:15.521679"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -626,8 +626,7 @@ class AnnotationDashboard:
|
|||||||
if not self.orchestrator:
|
if not self.orchestrator:
|
||||||
logger.info("Initializing TradingOrchestrator...")
|
logger.info("Initializing TradingOrchestrator...")
|
||||||
self.orchestrator = TradingOrchestrator(
|
self.orchestrator = TradingOrchestrator(
|
||||||
data_provider=self.data_provider,
|
data_provider=self.data_provider
|
||||||
config=self.config
|
|
||||||
)
|
)
|
||||||
self.training_adapter.orchestrator = self.orchestrator
|
self.training_adapter.orchestrator = self.orchestrator
|
||||||
logger.info("TradingOrchestrator initialized")
|
logger.info("TradingOrchestrator initialized")
|
||||||
@@ -1709,6 +1708,9 @@ class AnnotationDashboard:
|
|||||||
# CRITICAL: Get current symbol to filter annotations
|
# CRITICAL: Get current symbol to filter annotations
|
||||||
current_symbol = data.get('symbol', 'ETH/USDT')
|
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 no specific annotations provided, use all for current symbol
|
||||||
if not annotation_ids:
|
if not annotation_ids:
|
||||||
annotations = self.annotation_manager.get_annotations(symbol=current_symbol)
|
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!)
|
# Start REAL training (NO SIMULATION!)
|
||||||
training_id = self.training_adapter.start_training(
|
training_id = self.training_adapter.start_training(
|
||||||
model_name=model_name,
|
model_name=model_name,
|
||||||
test_cases=test_cases
|
test_cases=test_cases,
|
||||||
|
annotation_count=len(annotation_ids),
|
||||||
|
timeframe=timeframe
|
||||||
)
|
)
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
/* Chart Panel */
|
/* Chart Panel */
|
||||||
.chart-panel {
|
.chart-panel {
|
||||||
height: calc(100vh - 150px);
|
height: calc(100vh - 150px);
|
||||||
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-panel .card-body {
|
.chart-panel .card-body {
|
||||||
@@ -17,6 +18,29 @@
|
|||||||
overflow: hidden;
|
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 {
|
#chart-container {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
@@ -236,11 +260,32 @@
|
|||||||
padding: 1rem;
|
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 */
|
/* Responsive Adjustments */
|
||||||
@media (max-width: 1200px) {
|
@media (max-width: 1200px) {
|
||||||
.chart-plot {
|
.chart-plot {
|
||||||
height: 250px;
|
height: 250px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chart-panel-maximized .chart-plot {
|
||||||
|
height: 350px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
|||||||
@@ -101,6 +101,23 @@
|
|||||||
if (typeof checkActiveTraining === 'function') {
|
if (typeof checkActiveTraining === 'function') {
|
||||||
checkActiveTraining();
|
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
|
// Setup keyboard shortcuts
|
||||||
setupKeyboardShortcuts();
|
setupKeyboardShortcuts();
|
||||||
|
|||||||
@@ -14,6 +14,9 @@
|
|||||||
<button type="button" class="btn btn-outline-light" id="reset-zoom-btn" title="Reset Zoom">
|
<button type="button" class="btn btn-outline-light" id="reset-zoom-btn" title="Reset Zoom">
|
||||||
<i class="fas fa-expand"></i>
|
<i class="fas fa-expand"></i>
|
||||||
</button>
|
</button>
|
||||||
|
<button type="button" class="btn btn-outline-light" id="maximize-btn" title="Maximize Chart Area">
|
||||||
|
<i class="fas fa-arrows-alt"></i>
|
||||||
|
</button>
|
||||||
<button type="button" class="btn btn-outline-light" id="fullscreen-btn" title="Fullscreen">
|
<button type="button" class="btn btn-outline-light" id="fullscreen-btn" title="Fullscreen">
|
||||||
<i class="fas fa-expand-arrows-alt"></i>
|
<i class="fas fa-expand-arrows-alt"></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -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 () {
|
document.getElementById('fullscreen-btn').addEventListener('click', function () {
|
||||||
const chartContainer = document.getElementById('chart-container');
|
const chartContainer = document.getElementById('chart-container');
|
||||||
if (chartContainer.requestFullscreen) {
|
if (chartContainer.requestFullscreen) {
|
||||||
|
|||||||
@@ -40,9 +40,13 @@
|
|||||||
role="progressbar" style="width: 0%"></div>
|
role="progressbar" style="width: 0%"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="small">
|
<div class="small">
|
||||||
<div>Epoch: <span id="training-epoch">0</span>/<span id="training-total-epochs">0</span></div>
|
<div>Annotations: <span id="training-annotation-count" class="fw-bold text-primary">--</span></div>
|
||||||
<div>Loss: <span id="training-loss">--</span></div>
|
<div>Timeframe: <span id="training-timeframe" class="fw-bold text-info">--</span></div>
|
||||||
<div>GPU: <span id="training-gpu-util">--</span>% | CPU: <span id="training-cpu-util">--</span>%</div>
|
<div class="mt-1 pt-1 border-top">
|
||||||
|
<div>Epoch: <span id="training-epoch">0</span>/<span id="training-total-epochs">0</span></div>
|
||||||
|
<div>Loss: <span id="training-loss">--</span></div>
|
||||||
|
<div>GPU: <span id="training-gpu-util">--</span>% | CPU: <span id="training-cpu-util">--</span>%</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -193,6 +197,15 @@
|
|||||||
// Resume tracking
|
// Resume tracking
|
||||||
activeTrainingId = data.session.training_id;
|
activeTrainingId = data.session.training_id;
|
||||||
showTrainingStatus();
|
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);
|
pollTrainingProgress(activeTrainingId);
|
||||||
} else {
|
} else {
|
||||||
console.log('No active training session');
|
console.log('No active training session');
|
||||||
@@ -408,10 +421,17 @@
|
|||||||
// Show training status
|
// Show training status
|
||||||
showTrainingStatus();
|
showTrainingStatus();
|
||||||
|
|
||||||
|
// Get primary timeframe for training
|
||||||
|
const primaryTimeframe = document.getElementById('primary-timeframe-select').value;
|
||||||
|
|
||||||
// Reset progress
|
// Reset progress
|
||||||
document.getElementById('training-progress-bar').style.width = '0%';
|
document.getElementById('training-progress-bar').style.width = '0%';
|
||||||
document.getElementById('training-epoch').textContent = '0';
|
document.getElementById('training-epoch').textContent = '0';
|
||||||
document.getElementById('training-loss').textContent = '--';
|
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
|
// Start training request
|
||||||
fetch('/api/train-model', {
|
fetch('/api/train-model', {
|
||||||
@@ -420,7 +440,8 @@
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
model_name: modelName,
|
model_name: modelName,
|
||||||
annotation_ids: annotationIds,
|
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())
|
.then(response => response.json())
|
||||||
|
|||||||
Reference in New Issue
Block a user