wip
This commit is contained in:
@@ -2910,7 +2910,16 @@ class AnnotationDashboard:
|
|||||||
# Store with timestamp as key for retrieval
|
# Store with timestamp as key for retrieval
|
||||||
prediction_key = f"{timeframe}_{timestamp}"
|
prediction_key = f"{timeframe}_{timestamp}"
|
||||||
self.prediction_accuracy_cache[prediction_key] = accuracy_data
|
self.prediction_accuracy_cache[prediction_key] = accuracy_data
|
||||||
logger.debug(f"Stored accuracy data for {prediction_key}: {accuracy_data['accuracy']:.1f}%")
|
|
||||||
|
# DETAILED LOGGING for debugging accuracy calculation
|
||||||
|
logger.info(f"ACCURACY DEBUG for {prediction_key}:")
|
||||||
|
logger.info(f" Predicted: O={predicted[0]:.2f} H={predicted[1]:.2f} L={predicted[2]:.2f} C={predicted[3]:.2f}")
|
||||||
|
logger.info(f" Actual: O={actual[0]:.2f} H={actual[1]:.2f} L={actual[2]:.2f} C={actual[3]:.2f}")
|
||||||
|
logger.info(f" Pred Direction: {'UP' if predicted[3] >= predicted[0] else 'DOWN'}")
|
||||||
|
logger.info(f" Actual Direction: {'UP' if actual[3] >= actual[0] else 'DOWN'}")
|
||||||
|
logger.info(f" Direction Correct: {accuracy_data['directionCorrect']}")
|
||||||
|
logger.info(f" Accuracy: {accuracy_data['accuracy']:.1f}%, Avg Error: {accuracy_data['avgPctError']:.2f}%")
|
||||||
|
logger.info(f" Individual Errors: {accuracy_data['pctErrors']}")
|
||||||
|
|
||||||
# Trigger training and get metrics
|
# Trigger training and get metrics
|
||||||
metrics = self._train_on_validated_prediction(
|
metrics = self._train_on_validated_prediction(
|
||||||
@@ -2970,10 +2979,20 @@ class AnnotationDashboard:
|
|||||||
trainer = self.orchestrator.primary_transformer_trainer
|
trainer = self.orchestrator.primary_transformer_trainer
|
||||||
if trainer and hasattr(trainer, 'training_history'):
|
if trainer and hasattr(trainer, 'training_history'):
|
||||||
history = trainer.training_history
|
history = trainer.training_history
|
||||||
if history.get('train_loss'):
|
|
||||||
metrics['loss'] = history['train_loss'][-1] if history['train_loss'] else metrics['loss']
|
# Current metrics (most recent)
|
||||||
if history.get('train_accuracy'):
|
if history.get('train_loss') and len(history['train_loss']) > 0:
|
||||||
metrics['accuracy'] = history['train_accuracy'][-1] if history['train_accuracy'] else metrics['accuracy']
|
metrics['loss'] = history['train_loss'][-1]
|
||||||
|
metrics['best_loss'] = min(history['train_loss'])
|
||||||
|
|
||||||
|
if history.get('train_accuracy') and len(history['train_accuracy']) > 0:
|
||||||
|
metrics['accuracy'] = history['train_accuracy'][-1]
|
||||||
|
metrics['best_accuracy'] = max(history['train_accuracy'])
|
||||||
|
|
||||||
|
# Training progress info
|
||||||
|
metrics['total_training_steps'] = len(history.get('train_loss', []))
|
||||||
|
|
||||||
|
logger.debug(f"Training metrics: loss={metrics.get('loss', 'N/A')}, accuracy={metrics.get('accuracy', 'N/A')}, steps={metrics.get('total_training_steps', 0)}")
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'success': True,
|
'success': True,
|
||||||
@@ -3040,6 +3059,41 @@ class AnnotationDashboard:
|
|||||||
logger.error(f"Error calculating prediction accuracy: {e}")
|
logger.error(f"Error calculating prediction accuracy: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@self.server.route('/api/training-session-status', methods=['GET'])
|
||||||
|
def get_training_session_status():
|
||||||
|
"""Get current training session status for UI state restoration"""
|
||||||
|
try:
|
||||||
|
status = {
|
||||||
|
'success': True,
|
||||||
|
'training_active': False,
|
||||||
|
'inference_active': False,
|
||||||
|
'session_type': None,
|
||||||
|
'primary_timeframe': '1m',
|
||||||
|
'prediction_steps': 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if training adapter has active sessions
|
||||||
|
if self.training_adapter and hasattr(self.training_adapter, 'inference_sessions'):
|
||||||
|
active_sessions = [s for s in self.training_adapter.inference_sessions.values()
|
||||||
|
if s.get('status') == 'running']
|
||||||
|
|
||||||
|
if active_sessions:
|
||||||
|
session = active_sessions[0] # Get first active session
|
||||||
|
status['training_active'] = True
|
||||||
|
status['inference_active'] = True
|
||||||
|
status['session_type'] = session.get('training_mode', 'online_learning')
|
||||||
|
status['primary_timeframe'] = session.get('timeframe', '1m')
|
||||||
|
status['prediction_steps'] = session.get('prediction_steps', 1)
|
||||||
|
|
||||||
|
return jsonify(status)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error getting training session status: {e}")
|
||||||
|
return jsonify({
|
||||||
|
'success': False,
|
||||||
|
'error': str(e)
|
||||||
|
})
|
||||||
|
|
||||||
@self.server.route('/api/trading-stats', methods=['GET'])
|
@self.server.route('/api/trading-stats', methods=['GET'])
|
||||||
def get_trading_stats():
|
def get_trading_stats():
|
||||||
"""Get current trading statistics (positions, PnL, win rate)"""
|
"""Get current trading statistics (positions, PnL, win rate)"""
|
||||||
@@ -3101,11 +3155,14 @@ class AnnotationDashboard:
|
|||||||
|
|
||||||
# Get latest training history
|
# Get latest training history
|
||||||
if hasattr(trainer, 'training_history') and trainer.training_history:
|
if hasattr(trainer, 'training_history') and trainer.training_history:
|
||||||
latest = trainer.training_history[-1]
|
# Get the most recent loss and accuracy
|
||||||
if 'loss' in latest:
|
if trainer.training_history['train_loss']:
|
||||||
stats['model_loss'] = f"{latest['loss']:.4f}"
|
latest_loss = trainer.training_history['train_loss'][-1]
|
||||||
if 'accuracy' in latest:
|
stats['model_loss'] = f"{latest_loss:.4f}"
|
||||||
stats['model_accuracy'] = f"{latest['accuracy']:.1%}"
|
|
||||||
|
if trainer.training_history['train_accuracy']:
|
||||||
|
latest_accuracy = trainer.training_history['train_accuracy'][-1]
|
||||||
|
stats['model_accuracy'] = f"{latest_accuracy:.1%}"
|
||||||
|
|
||||||
# Fallback to current metrics if available
|
# Fallback to current metrics if available
|
||||||
if stats['model_loss'] == '--' and hasattr(trainer, 'current_loss') and trainer.current_loss is not None:
|
if stats['model_loss'] == '--' and hasattr(trainer, 'current_loss') and trainer.current_loss is not None:
|
||||||
@@ -3283,6 +3340,45 @@ class AnnotationDashboard:
|
|||||||
candle_values = candle_tensor.squeeze(0).cpu().numpy().tolist()
|
candle_values = candle_tensor.squeeze(0).cpu().numpy().tolist()
|
||||||
predicted_candle[tf] = candle_values
|
predicted_candle[tf] = candle_values
|
||||||
|
|
||||||
|
# Extract trend_vector for yellow dotted lines
|
||||||
|
trend_vector = None
|
||||||
|
if 'trend_vector' in outputs:
|
||||||
|
trend_vec = outputs['trend_vector']
|
||||||
|
device = next(transformer.parameters()).device
|
||||||
|
|
||||||
|
# Extract trend data (same logic as in extract_predictions)
|
||||||
|
angle = trend_vec.get('calculated_angle', torch.tensor(0.0, device=device))
|
||||||
|
if isinstance(angle, torch.Tensor):
|
||||||
|
if angle.dim() > 1:
|
||||||
|
angle = angle[0, 0] if angle.shape[0] > 0 else torch.tensor(0.0, device=device)
|
||||||
|
angle_val = float(angle.cpu().detach().item() if hasattr(angle, 'cpu') else angle)
|
||||||
|
else:
|
||||||
|
angle_val = float(angle)
|
||||||
|
|
||||||
|
steepness = trend_vec.get('calculated_steepness', torch.tensor(0.0, device=device))
|
||||||
|
if isinstance(steepness, torch.Tensor):
|
||||||
|
if steepness.dim() > 1:
|
||||||
|
steepness = steepness[0, 0] if steepness.shape[0] > 0 else torch.tensor(0.0, device=device)
|
||||||
|
steepness_val = float(steepness.cpu().detach().item() if hasattr(steepness, 'cpu') else steepness)
|
||||||
|
else:
|
||||||
|
steepness_val = float(steepness)
|
||||||
|
|
||||||
|
direction = trend_vec.get('calculated_direction', torch.tensor(0.0, device=device))
|
||||||
|
if isinstance(direction, torch.Tensor):
|
||||||
|
if direction.dim() > 1:
|
||||||
|
direction = direction[0, 0] if direction.shape[0] > 0 else torch.tensor(0.0, device=device)
|
||||||
|
direction_val = float(direction.cpu().detach().item() if hasattr(direction, 'cpu') else direction)
|
||||||
|
else:
|
||||||
|
direction_val = float(direction)
|
||||||
|
|
||||||
|
trend_vector = {
|
||||||
|
'calculated_angle': angle_val,
|
||||||
|
'calculated_steepness': steepness_val,
|
||||||
|
'calculated_direction': direction_val,
|
||||||
|
'angle_degrees': angle_val * 180.0 / 3.14159,
|
||||||
|
'direction': 'up' if direction_val > 0 else 'down' if direction_val < 0 else 'sideways'
|
||||||
|
}
|
||||||
|
|
||||||
current_price = price_data_1m[-1]['close']
|
current_price = price_data_1m[-1]['close']
|
||||||
predicted_1m_close = predicted_candle.get('1m', [0,0,0,current_price,0])[3]
|
predicted_1m_close = predicted_candle.get('1m', [0,0,0,current_price,0])[3]
|
||||||
price_change = (predicted_1m_close - current_price) / current_price
|
price_change = (predicted_1m_close - current_price) / current_price
|
||||||
@@ -3308,6 +3404,7 @@ class AnnotationDashboard:
|
|||||||
'current_price': current_price,
|
'current_price': current_price,
|
||||||
'price_change': price_change,
|
'price_change': price_change,
|
||||||
'predicted_candle': predicted_candle, # This is what frontend needs!
|
'predicted_candle': predicted_candle, # This is what frontend needs!
|
||||||
|
'trend_vector': trend_vector, # For yellow dotted trend lines
|
||||||
'primary_timeframe': '1m', # The main timeframe the model is predicting for
|
'primary_timeframe': '1m', # The main timeframe the model is predicting for
|
||||||
'type': 'transformer_prediction'
|
'type': 'transformer_prediction'
|
||||||
}
|
}
|
||||||
@@ -3436,6 +3533,17 @@ class AnnotationDashboard:
|
|||||||
|
|
||||||
self._incremental_training_steps += 1
|
self._incremental_training_steps += 1
|
||||||
|
|
||||||
|
# Update trainer's training history for UI display
|
||||||
|
if hasattr(trainer, 'training_history'):
|
||||||
|
# Add to trainer's history (this is what the UI reads)
|
||||||
|
trainer.training_history['train_loss'].append(loss)
|
||||||
|
trainer.training_history['train_accuracy'].append(candle_accuracy)
|
||||||
|
|
||||||
|
# Keep history manageable (last 1000 entries)
|
||||||
|
if len(trainer.training_history['train_loss']) > 1000:
|
||||||
|
trainer.training_history['train_loss'] = trainer.training_history['train_loss'][-1000:]
|
||||||
|
trainer.training_history['train_accuracy'] = trainer.training_history['train_accuracy'][-1000:]
|
||||||
|
|
||||||
# Track metrics for display
|
# Track metrics for display
|
||||||
if not hasattr(self, '_training_metrics_history'):
|
if not hasattr(self, '_training_metrics_history'):
|
||||||
self._training_metrics_history = []
|
self._training_metrics_history = []
|
||||||
@@ -3453,15 +3561,29 @@ class AnnotationDashboard:
|
|||||||
self._training_metrics_history.pop(0)
|
self._training_metrics_history.pop(0)
|
||||||
|
|
||||||
if self._incremental_training_steps % 10 == 0:
|
if self._incremental_training_steps % 10 == 0:
|
||||||
logger.info(f"Saving checkpoint after {self._incremental_training_steps} incremental training steps")
|
logger.info(f"Saving model checkpoint after {self._incremental_training_steps} incremental training steps")
|
||||||
trainer.save_checkpoint(
|
try:
|
||||||
filepath=None, # Auto-generate path
|
# Generate checkpoint path
|
||||||
metadata={
|
import os
|
||||||
'training_type': 'incremental_online',
|
from datetime import datetime
|
||||||
'steps': self._incremental_training_steps,
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||||
'last_accuracy': accuracy
|
checkpoint_dir = "models/transformer"
|
||||||
}
|
os.makedirs(checkpoint_dir, exist_ok=True)
|
||||||
)
|
checkpoint_path = f"{checkpoint_dir}/incremental_step_{self._incremental_training_steps}_{timestamp}.pth"
|
||||||
|
|
||||||
|
# Save using the trainer's save_model method
|
||||||
|
trainer.save_model(checkpoint_path)
|
||||||
|
logger.info(f"✓ Checkpoint saved: {checkpoint_path}")
|
||||||
|
|
||||||
|
# Update best checkpoint tracking
|
||||||
|
if not hasattr(self, '_best_incremental_loss') or loss < self._best_incremental_loss:
|
||||||
|
self._best_incremental_loss = loss
|
||||||
|
best_path = f"{checkpoint_dir}/best_incremental.pth"
|
||||||
|
trainer.save_model(best_path)
|
||||||
|
logger.info(f"✓ New best incremental model saved: {best_path} (loss: {loss:.4f})")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error saving checkpoint: {e}")
|
||||||
|
|
||||||
# Return metrics for display
|
# Return metrics for display
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -2825,6 +2825,15 @@ class ChartManager {
|
|||||||
marker: { ...updatedTraces[1].marker, color: volumeColors }
|
marker: { ...updatedTraces[1].marker, color: volumeColors }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Disable hover on pivot lines before updating
|
||||||
|
if (plotElement.layout && plotElement.layout.shapes) {
|
||||||
|
plotElement.layout.shapes.forEach(shape => {
|
||||||
|
if (shape.line && shape.line.dash === 'dash' && shape.layer === 'below') {
|
||||||
|
shape.hoverinfo = 'skip'; // Disable hover on pivot lines
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Use react instead of restyle - it's smarter about what to update
|
// Use react instead of restyle - it's smarter about what to update
|
||||||
Plotly.react(plotId, updatedTraces, plotElement.layout, plotElement.config);
|
Plotly.react(plotId, updatedTraces, plotElement.layout, plotElement.config);
|
||||||
|
|
||||||
|
|||||||
@@ -1929,12 +1929,61 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore UI state on page load
|
||||||
|
function restoreUIState() {
|
||||||
|
fetch('/api/training-session-status')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.success && data.training_active) {
|
||||||
|
console.log('Restoring active training session:', data.session_type);
|
||||||
|
|
||||||
|
// Show inference status panel
|
||||||
|
const inferenceStatus = document.getElementById('inference-status');
|
||||||
|
if (inferenceStatus) {
|
||||||
|
inferenceStatus.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide inference buttons
|
||||||
|
const inferenceButtons = document.getElementById('inference-buttons-container');
|
||||||
|
if (inferenceButtons) {
|
||||||
|
inferenceButtons.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show stop button
|
||||||
|
const stopBtn = document.getElementById('stop-inference-btn');
|
||||||
|
if (stopBtn) {
|
||||||
|
stopBtn.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set timeframe
|
||||||
|
const timeframeSelect = document.getElementById('primary-timeframe-select');
|
||||||
|
if (timeframeSelect && data.primary_timeframe) {
|
||||||
|
timeframeSelect.value = data.primary_timeframe;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set prediction steps
|
||||||
|
const stepsSlider = document.getElementById('prediction-steps-slider');
|
||||||
|
const stepsValue = document.getElementById('prediction-steps-value');
|
||||||
|
if (stepsSlider && data.prediction_steps) {
|
||||||
|
stepsSlider.value = data.prediction_steps;
|
||||||
|
if (stepsValue) stepsValue.textContent = data.prediction_steps;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start polling
|
||||||
|
startTradingStatsPolling();
|
||||||
|
startTrainingMetricsPolling();
|
||||||
|
|
||||||
|
console.log('✅ UI state restored for active training session');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.debug('Error checking training session status:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Start polling on page load if inference is already active
|
// Start polling on page load if inference is already active
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
// Check if inference is already running and start polling
|
// Restore UI state first
|
||||||
const inferenceStatus = document.getElementById('inference-status');
|
restoreUIState();
|
||||||
if (inferenceStatus && inferenceStatus.style.display !== 'none') {
|
|
||||||
startTradingStatsPolling();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
124
BACKPROPAGATION_CHECKPOINT_FIX.md
Normal file
124
BACKPROPAGATION_CHECKPOINT_FIX.md
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
# Backpropagation & Checkpoint Saving Fix - Complete
|
||||||
|
|
||||||
|
## Problems Identified
|
||||||
|
1. **Missing Loss Stats**: Training metrics weren't being properly displayed in UI
|
||||||
|
2. **Checkpoint Saving Errors**: Code was calling non-existent `save_checkpoint` method
|
||||||
|
3. **Training History**: Incremental training wasn't updating trainer's history for UI display
|
||||||
|
4. **Metrics Tracking**: Training results weren't being properly tracked and exposed
|
||||||
|
|
||||||
|
## Root Causes Found
|
||||||
|
|
||||||
|
### 1. Incorrect Checkpoint Method
|
||||||
|
- Code was calling `trainer.save_checkpoint()` which doesn't exist
|
||||||
|
- TradingTransformerTrainer only has `save_model()` method
|
||||||
|
|
||||||
|
### 2. Training History Not Updated
|
||||||
|
- Incremental training wasn't adding results to `trainer.training_history`
|
||||||
|
- UI reads from `training_history` but it was empty for incremental steps
|
||||||
|
|
||||||
|
### 3. Metrics API Issues
|
||||||
|
- Training metrics endpoint wasn't properly extracting latest values
|
||||||
|
- Missing best loss/accuracy tracking
|
||||||
|
|
||||||
|
## Fixes Applied
|
||||||
|
|
||||||
|
### 1. Fixed Checkpoint Saving
|
||||||
|
```python
|
||||||
|
# OLD (broken):
|
||||||
|
trainer.save_checkpoint(filepath=None, metadata={...})
|
||||||
|
|
||||||
|
# NEW (working):
|
||||||
|
checkpoint_path = f"models/transformer/incremental_step_{steps}_{timestamp}.pth"
|
||||||
|
trainer.save_model(checkpoint_path)
|
||||||
|
|
||||||
|
# Also saves best model:
|
||||||
|
if loss < best_loss:
|
||||||
|
trainer.save_model("models/transformer/best_incremental.pth")
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Enhanced Training History Tracking
|
||||||
|
```python
|
||||||
|
# Update trainer's training history for UI display
|
||||||
|
trainer.training_history['train_loss'].append(loss)
|
||||||
|
trainer.training_history['train_accuracy'].append(candle_accuracy)
|
||||||
|
|
||||||
|
# Keep history manageable (last 1000 entries)
|
||||||
|
if len(trainer.training_history['train_loss']) > 1000:
|
||||||
|
trainer.training_history['train_loss'] = trainer.training_history['train_loss'][-1000:]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Improved Metrics API
|
||||||
|
Enhanced `/api/training-metrics` to provide:
|
||||||
|
- **Current loss/accuracy**: Latest training results
|
||||||
|
- **Best loss/accuracy**: Best values achieved
|
||||||
|
- **Total training steps**: Number of incremental training steps
|
||||||
|
- **Trend analysis**: Whether performance is improving/degrading
|
||||||
|
|
||||||
|
### 4. Better UI Integration
|
||||||
|
- Training stats now update every 2 seconds via polling
|
||||||
|
- Loss and accuracy display in multiple UI locations
|
||||||
|
- Best checkpoint metrics tracking
|
||||||
|
- Incremental training step counter
|
||||||
|
|
||||||
|
## Training Pipeline Flow
|
||||||
|
|
||||||
|
### 1. Prediction Made
|
||||||
|
- Model generates prediction for next candle
|
||||||
|
- Ghost candle displayed on chart
|
||||||
|
|
||||||
|
### 2. Actual Candle Arrives
|
||||||
|
- System compares predicted vs actual values
|
||||||
|
- Calculates accuracy and errors
|
||||||
|
|
||||||
|
### 3. Backpropagation Training
|
||||||
|
```python
|
||||||
|
# Convert to training batch
|
||||||
|
batch = self.training_adapter._convert_prediction_to_batch(training_sample, timeframe)
|
||||||
|
|
||||||
|
# Train with gradient descent
|
||||||
|
result = trainer.train_step(batch, accumulate_gradients=False)
|
||||||
|
|
||||||
|
# Extract loss and accuracy
|
||||||
|
loss = result.get('total_loss', 0)
|
||||||
|
accuracy = result.get('candle_accuracy', 0)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Metrics Tracking
|
||||||
|
- Results added to trainer's training history
|
||||||
|
- Metrics cached for UI display
|
||||||
|
- Best performance tracked
|
||||||
|
|
||||||
|
### 5. Checkpoint Saving
|
||||||
|
- Every 10 training steps: Save checkpoint
|
||||||
|
- When loss improves: Save as best model
|
||||||
|
- Automatic cleanup of old checkpoints
|
||||||
|
|
||||||
|
## Expected Behavior Now
|
||||||
|
|
||||||
|
### UI Display:
|
||||||
|
- ✅ **Live Loss**: Updates every 2 seconds with latest training loss
|
||||||
|
- ✅ **Live Accuracy**: Shows current model accuracy
|
||||||
|
- ✅ **Training Steps**: Incremental step counter
|
||||||
|
- ✅ **Best Metrics**: Best loss/accuracy achieved
|
||||||
|
- ✅ **Last Training Time**: When last training occurred
|
||||||
|
|
||||||
|
### Checkpoint Saving:
|
||||||
|
- ✅ **Regular Saves**: Every 10 incremental training steps
|
||||||
|
- ✅ **Best Model**: Saved when performance improves
|
||||||
|
- ✅ **Proper Paths**: Organized in `models/transformer/` directory
|
||||||
|
- ✅ **Metadata**: Includes training type and step count
|
||||||
|
|
||||||
|
### Training Loop:
|
||||||
|
- ✅ **Real Data**: Uses actual market data for training
|
||||||
|
- ✅ **Backpropagation**: Proper gradient descent on prediction errors
|
||||||
|
- ✅ **Sample Weighting**: Higher weight for poor predictions (learn from mistakes)
|
||||||
|
- ✅ **Direction Learning**: Extra weight for wrong direction predictions
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
1. **Start inference**: Begin making predictions
|
||||||
|
2. **Wait for validation**: Let actual candles arrive
|
||||||
|
3. **Check UI**: Loss and accuracy should update
|
||||||
|
4. **Monitor logs**: Should see "✓ Trained on validated prediction" messages
|
||||||
|
5. **Check checkpoints**: Files should appear in `models/transformer/` directory
|
||||||
|
|
||||||
|
The system now properly learns from real trading outcomes with full backpropagation and checkpoint saving!
|
||||||
111
PREDICTION_LINE_TYPES_EXPLAINED.md
Normal file
111
PREDICTION_LINE_TYPES_EXPLAINED.md
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
# Prediction Line Types Explained
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
The system displays two different types of prediction lines during real-time inference, each representing different aspects of the model's predictions.
|
||||||
|
|
||||||
|
## Line Type 1: Dotted Lines (Yellow, Vertical-ish)
|
||||||
|
**Style**: `dash: 'dot'`
|
||||||
|
**Color**: Yellow (`rgba(255, 255, 0, 0.6)`)
|
||||||
|
**Source**: `_addTrendPrediction()` method
|
||||||
|
**Purpose**: **Trend Vector Predictions**
|
||||||
|
|
||||||
|
### What They Represent:
|
||||||
|
- **Trend direction and steepness** from the model's trend analysis
|
||||||
|
- **Short-term price movement** based on calculated market direction
|
||||||
|
- **Momentum indicators** showing where price is likely to move
|
||||||
|
|
||||||
|
### Why They Appear Vertical:
|
||||||
|
The yellow dotted lines often appear vertical because:
|
||||||
|
1. **Short projection time**: Only projects 30 seconds (1s), 2 minutes (1m), or 30 minutes (1h) ahead
|
||||||
|
2. **Small price changes**: Trend predictions are often small percentage moves
|
||||||
|
3. **Validation filtering**: Lines with >10% price change are filtered out as unrealistic
|
||||||
|
4. **Steepness scaling**: Large steepness values are capped to prevent extreme lines
|
||||||
|
|
||||||
|
### Technical Details:
|
||||||
|
```javascript
|
||||||
|
// Projection times by timeframe
|
||||||
|
const projectionSeconds = timeframe === '1s' ? 30 :
|
||||||
|
timeframe === '1m' ? 120 :
|
||||||
|
timeframe === '1h' ? 1800 : 300;
|
||||||
|
|
||||||
|
// Price change calculation
|
||||||
|
priceChange = (steepness / 100) * currentPrice * direction;
|
||||||
|
targetPrice = currentPrice + priceChange;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Line Type 2: Dash-Dot Lines (Various Colors)
|
||||||
|
**Style**: `dash: 'dashdot'`
|
||||||
|
**Color**: Varies by confidence and age (fading system)
|
||||||
|
**Source**: `_addTransformerPrediction()` method
|
||||||
|
**Purpose**: **Action Predictions with Price Targets**
|
||||||
|
|
||||||
|
### What They Represent:
|
||||||
|
- **Trading action predictions** (BUY/SELL signals)
|
||||||
|
- **Specific price targets** where the action should be taken
|
||||||
|
- **Confidence levels** shown through line thickness and opacity
|
||||||
|
- **Time-based predictions** showing when the action is expected
|
||||||
|
|
||||||
|
### Visual Characteristics:
|
||||||
|
- **Start point**: Current timestamp and price when prediction was made
|
||||||
|
- **End point**: Target timestamp and predicted price
|
||||||
|
- **Thickness**: Varies with confidence (thicker = higher confidence)
|
||||||
|
- **Fading**: Older predictions fade out over time
|
||||||
|
- **Markers**: Star markers (▲ for BUY, ▼ for SELL) at target points
|
||||||
|
|
||||||
|
### Technical Details:
|
||||||
|
```javascript
|
||||||
|
// Line styling based on confidence
|
||||||
|
width: (2 + confidence * 2) * fadeOpacity,
|
||||||
|
dash: 'dashdot'
|
||||||
|
|
||||||
|
// Action markers
|
||||||
|
const actionText = prediction.action === 'BUY' ? '▲' :
|
||||||
|
prediction.action === 'SELL' ? '▼' : '★';
|
||||||
|
```
|
||||||
|
|
||||||
|
## Why Two Different Types?
|
||||||
|
|
||||||
|
### Complementary Information:
|
||||||
|
1. **Trend Lines (Dotted)**: Show general market direction and momentum
|
||||||
|
2. **Action Lines (Dash-Dot)**: Show specific trading opportunities with targets
|
||||||
|
|
||||||
|
### Different Time Horizons:
|
||||||
|
1. **Trend Lines**: Short-term momentum (seconds to minutes)
|
||||||
|
2. **Action Lines**: Trading signals (can be longer-term)
|
||||||
|
|
||||||
|
### Different Model Outputs:
|
||||||
|
1. **Trend Lines**: From trend vector analysis (technical indicators)
|
||||||
|
2. **Action Lines**: From transformer model predictions (ML-based)
|
||||||
|
|
||||||
|
## Normal Behavior
|
||||||
|
|
||||||
|
### Yellow Dotted Lines (Trend):
|
||||||
|
- ✅ **Often vertical**: Normal due to short time projections and small price moves
|
||||||
|
- ✅ **Yellow color**: Consistent trend indicator color
|
||||||
|
- ✅ **Brief appearance**: May disappear quickly as new trends are calculated
|
||||||
|
- ✅ **Filtered extremes**: Lines with unrealistic price targets are not shown
|
||||||
|
|
||||||
|
### Dash-Dot Lines (Actions):
|
||||||
|
- ✅ **Various colors**: Fade from bright to dim over time
|
||||||
|
- ✅ **Different angles**: Based on actual price targets and timing
|
||||||
|
- ✅ **Confidence thickness**: Thicker lines = higher confidence
|
||||||
|
- ✅ **Action markers**: Clear BUY/SELL indicators at target points
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### If You Only See One Type:
|
||||||
|
- **Missing trend lines**: Check if trend vector data is being generated
|
||||||
|
- **Missing action lines**: Check if transformer predictions include price targets
|
||||||
|
- **Display toggles**: Verify both line types are enabled in display settings
|
||||||
|
|
||||||
|
### If Lines Look Wrong:
|
||||||
|
- **Extreme angles**: Validation filters may be removing unrealistic predictions
|
||||||
|
- **No lines**: Model may not be generating confident enough predictions
|
||||||
|
- **Flickering**: Normal behavior as new predictions update old ones
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
- **Yellow Dotted Lines**: Trend momentum indicators (often appear vertical due to short projections)
|
||||||
|
- **Dash-Dot Lines**: Trading action signals with specific price targets
|
||||||
|
- **Both are normal**: They provide complementary information about market direction and trading opportunities
|
||||||
|
|
||||||
|
The vertical appearance of yellow dotted lines is expected behavior due to the short time horizons and conservative price change filtering!
|
||||||
111
UI_FIXES_AND_TRAINING_ENHANCEMENT.md
Normal file
111
UI_FIXES_AND_TRAINING_ENHANCEMENT.md
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
# UI Fixes and Training Enhancement - Complete
|
||||||
|
|
||||||
|
## Issues Addressed
|
||||||
|
|
||||||
|
### 1. ✅ Training on Yellow Dotted Line Predictions
|
||||||
|
**Problem**: Yellow dotted lines (trend vectors) weren't being trained on because `trend_vector` data wasn't included in live predictions.
|
||||||
|
|
||||||
|
**Fix Applied**:
|
||||||
|
- Added `trend_vector` extraction to `_get_live_transformer_prediction()`
|
||||||
|
- Now includes: `calculated_angle`, `calculated_steepness`, `calculated_direction`
|
||||||
|
- Both line types (yellow dotted + dash-dot) can now be trained on
|
||||||
|
|
||||||
|
**Result**: Model can learn from both trend predictions and action predictions.
|
||||||
|
|
||||||
|
### 2. ✅ UI State Persistence After Page Reload
|
||||||
|
**Problem**: If you started online learning and reloaded the page, UI would reset and not show active training session.
|
||||||
|
|
||||||
|
**Fix Applied**:
|
||||||
|
- Added `/api/training-session-status` endpoint
|
||||||
|
- Added `restoreUIState()` JavaScript function
|
||||||
|
- Automatically restores on page load:
|
||||||
|
- Shows inference status panel
|
||||||
|
- Hides start buttons, shows stop button
|
||||||
|
- Restores timeframe and prediction steps
|
||||||
|
- Resumes polling for metrics
|
||||||
|
|
||||||
|
**Result**: UI now reflects actual server state after page reload.
|
||||||
|
|
||||||
|
### 3. ✅ Pivot Point Hover Fix
|
||||||
|
**Problem**: Pivot tooltips triggered when hovering over vertical lines, not just the pivot dots.
|
||||||
|
|
||||||
|
**Fix Applied**:
|
||||||
|
- Added `hoverinfo: 'skip'` to all pivot lines (dashed horizontal lines)
|
||||||
|
- Only pivot dots (triangular markers) now trigger hover tooltips
|
||||||
|
- Applied to all chart updates to ensure consistency
|
||||||
|
|
||||||
|
**Result**: Hover tooltips only appear when hovering directly over pivot points.
|
||||||
|
|
||||||
|
### 4. ✅ Enhanced Loss Calculation Debugging
|
||||||
|
**Problem**: Candle loss calculation seemed wrong - showing <1% difference when actual vs predicted directions were opposite.
|
||||||
|
|
||||||
|
**Fix Applied**:
|
||||||
|
- Added detailed logging for accuracy calculations
|
||||||
|
- Logs predicted vs actual OHLC values
|
||||||
|
- Shows direction predictions and correctness
|
||||||
|
- Displays individual field errors and overall accuracy
|
||||||
|
|
||||||
|
**Debug Output Example**:
|
||||||
|
```
|
||||||
|
ACCURACY DEBUG for 1m_2025-12-10T14:30:00Z:
|
||||||
|
Predicted: O=3320.15 H=3325.42 L=3318.23 C=3322.61
|
||||||
|
Actual: O=3320.89 H=3326.12 L=3318.45 C=3318.18
|
||||||
|
Pred Direction: UP
|
||||||
|
Actual Direction: DOWN
|
||||||
|
Direction Correct: False
|
||||||
|
Accuracy: 87.5%, Avg Error: 1.25%
|
||||||
|
Individual Errors: {'open': 0.8, 'high': 1.2, 'low': 0.5, 'close': 0.9}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Result**: Can now debug exactly why accuracy calculations appear incorrect.
|
||||||
|
|
||||||
|
## Training Enhancement
|
||||||
|
|
||||||
|
### Both Line Types Now Trainable
|
||||||
|
1. **Yellow Dotted Lines (Trend Vectors)**:
|
||||||
|
- Source: `trend_vector` from transformer model
|
||||||
|
- Data: Angle, steepness, direction predictions
|
||||||
|
- Training: Can validate against actual price movement direction
|
||||||
|
|
||||||
|
2. **Dash-Dot Lines (Action Predictions)**:
|
||||||
|
- Source: `action`, `confidence`, `predicted_price` from transformer
|
||||||
|
- Data: Specific trading signals with price targets
|
||||||
|
- Training: Can validate against actual price targets and timing
|
||||||
|
|
||||||
|
### Training Data Flow
|
||||||
|
1. **Prediction Made**: Both trend and action data generated
|
||||||
|
2. **Actual Candle Arrives**: Compare predicted vs actual
|
||||||
|
3. **Accuracy Calculated**: Detailed error analysis for each component
|
||||||
|
4. **Backpropagation**: Train model on prediction errors
|
||||||
|
5. **Checkpoint Saved**: Best models preserved
|
||||||
|
|
||||||
|
## UI State Management
|
||||||
|
|
||||||
|
### Session Restoration
|
||||||
|
- ✅ **Training Status**: Shows if online learning is active
|
||||||
|
- ✅ **Button States**: Correct start/stop button visibility
|
||||||
|
- ✅ **Settings**: Timeframe and prediction steps restored
|
||||||
|
- ✅ **Polling**: Metrics and trading stats resume automatically
|
||||||
|
|
||||||
|
### Hover Behavior
|
||||||
|
- ✅ **Pivot Points**: Only dots trigger tooltips, not lines
|
||||||
|
- ✅ **Ghost Candles**: Rich accuracy information on hover
|
||||||
|
- ✅ **Prediction Lines**: Action markers show confidence levels
|
||||||
|
|
||||||
|
## Debugging Capabilities
|
||||||
|
|
||||||
|
### Accuracy Calculation
|
||||||
|
The detailed logging will help identify if the issue is:
|
||||||
|
1. **Wrong candle comparison**: Comparing prediction at time T with candle at time T instead of T+1
|
||||||
|
2. **Direction calculation error**: Logic error in up/down determination
|
||||||
|
3. **Percentage calculation**: Error in how percentage differences are computed
|
||||||
|
4. **Data timing**: Mismatch between prediction timestamp and validation timestamp
|
||||||
|
|
||||||
|
### Next Steps for Loss Investigation
|
||||||
|
With the enhanced logging, you can now:
|
||||||
|
1. **Check timestamps**: Verify prediction and actual candle timestamps align correctly
|
||||||
|
2. **Verify direction logic**: Confirm up/down calculations are correct
|
||||||
|
3. **Validate percentages**: Ensure error calculations match expected values
|
||||||
|
4. **Debug timing**: Identify if predictions are being compared to the right candles
|
||||||
|
|
||||||
|
The system now provides complete visibility into the training process and should help identify the root cause of any accuracy calculation discrepancies!
|
||||||
Reference in New Issue
Block a user