more metrics - WIP

This commit is contained in:
Dobromir Popov
2025-12-10 15:09:27 +02:00
parent 50506bb40e
commit da0c6628ff
3 changed files with 297 additions and 1 deletions

View File

@@ -2934,6 +2934,87 @@ class AnnotationDashboard:
'error': str(e) 'error': str(e)
}), 500 }), 500
@self.server.route('/api/trading-stats', methods=['GET'])
def get_trading_stats():
"""Get current trading statistics (positions, PnL, win rate)"""
try:
stats = {
'success': True,
'position': 'NO POSITION',
'session_pnl': 0.0,
'win_rate': '0% (0/0)',
'floating_pnl': 0.0,
'total_trades': 0,
'winning_trades': 0,
'trading_active': False,
'model_accuracy': '--',
'model_loss': '--'
}
# Get stats from trading executor if available
if self.orchestrator and hasattr(self.orchestrator, 'trading_executor') and self.orchestrator.trading_executor:
executor = self.orchestrator.trading_executor
# Check if there are any positions
if hasattr(executor, 'positions') and executor.positions:
# Get first position (assuming single position trading)
symbol, position = next(iter(executor.positions.items()))
stats['position'] = f"{position.side} {symbol}"
stats['trading_active'] = True
# Calculate floating PnL if we have current price
try:
current_price = self.data_provider.get_current_price(symbol)
if current_price:
floating_pnl = position.calculate_pnl(current_price)
stats['floating_pnl'] = floating_pnl
except Exception as e:
logger.debug(f"Could not calculate floating PnL: {e}")
# Get session stats
if hasattr(executor, 'session_pnl'):
stats['session_pnl'] = executor.session_pnl
if hasattr(executor, 'trade_records') and executor.trade_records:
stats['total_trades'] = len(executor.trade_records)
stats['winning_trades'] = sum(1 for trade in executor.trade_records if trade.pnl > 0)
if stats['total_trades'] > 0:
win_rate = (stats['winning_trades'] / stats['total_trades']) * 100
stats['win_rate'] = f"{win_rate:.1f}% ({stats['winning_trades']}/{stats['total_trades']})"
# Check if trading is active (has executor and is enabled)
if hasattr(executor, 'trading_enabled') and executor.trading_enabled:
stats['trading_active'] = True
# Get model performance stats from orchestrator
if self.orchestrator:
# Try to get transformer trainer stats
if hasattr(self.orchestrator, 'primary_transformer_trainer') and self.orchestrator.primary_transformer_trainer:
trainer = self.orchestrator.primary_transformer_trainer
# Get latest training history
if hasattr(trainer, 'training_history') and trainer.training_history:
latest = trainer.training_history[-1]
if 'loss' in latest:
stats['model_loss'] = f"{latest['loss']:.4f}"
if 'accuracy' in latest:
stats['model_accuracy'] = f"{latest['accuracy']:.1%}"
# Fallback to current metrics if available
if stats['model_loss'] == '--' and hasattr(trainer, 'current_loss') and trainer.current_loss is not None:
stats['model_loss'] = f"{trainer.current_loss:.4f}"
if stats['model_accuracy'] == '--' and hasattr(trainer, 'current_accuracy') and trainer.current_accuracy is not None:
stats['model_accuracy'] = f"{trainer.current_accuracy:.1%}"
return jsonify(stats)
except Exception as e:
logger.error(f"Error getting trading stats: {e}")
return jsonify({
'success': False,
'error': str(e)
})
@self.server.route('/api/realtime-inference/train-manual', methods=['POST']) @self.server.route('/api/realtime-inference/train-manual', methods=['POST'])
@@ -3235,7 +3316,7 @@ class AnnotationDashboard:
try: try:
with torch.enable_grad(): with torch.enable_grad():
trainer.model.train() trainer.model.train()
result = trainer.train_step(batch, accumulate_gradients=False, sample_weight=sample_weight) result = trainer.train_step(batch, accumulate_gradients=False)
if result: if result:
loss = result.get('total_loss', 0) loss = result.get('total_loss', 0)

View File

@@ -1805,4 +1805,136 @@
console.log('Signal displayed:', signal.action, '@', signal.price); console.log('Signal displayed:', signal.action, '@', signal.price);
} }
// Trading Stats Polling
let tradingStatsInterval = null;
function startTradingStatsPolling() {
if (tradingStatsInterval) {
clearInterval(tradingStatsInterval);
}
// Poll every 2 seconds
tradingStatsInterval = setInterval(updateTradingStats, 2000);
// Update immediately
updateTradingStats();
}
function stopTradingStatsPolling() {
if (tradingStatsInterval) {
clearInterval(tradingStatsInterval);
tradingStatsInterval = null;
}
}
function updateTradingStats() {
fetch('/api/trading-stats')
.then(response => response.json())
.then(data => {
if (data.success) {
// Update position status
const positionEl = document.getElementById('position-status');
if (positionEl) {
positionEl.textContent = data.position;
positionEl.className = data.position === 'NO POSITION' ? 'fw-bold text-info' : 'fw-bold text-warning';
}
// Update session PnL
const sessionPnlEl = document.getElementById('session-pnl');
if (sessionPnlEl) {
const pnl = data.session_pnl || 0;
const pnlColor = pnl >= 0 ? 'text-success' : 'text-danger';
const pnlSign = pnl >= 0 ? '+' : '';
sessionPnlEl.textContent = `${pnlSign}$${pnl.toFixed(2)}`;
sessionPnlEl.className = `fw-bold ${pnlColor}`;
}
// Update win rate
const winRateEl = document.getElementById('win-rate');
if (winRateEl) {
winRateEl.textContent = data.win_rate;
}
// Update model performance stats
const liveAccuracyEl = document.getElementById('live-accuracy');
if (liveAccuracyEl && data.model_accuracy !== '--') {
liveAccuracyEl.textContent = data.model_accuracy;
}
const liveLossEl = document.getElementById('live-loss');
if (liveLossEl && data.model_loss !== '--') {
liveLossEl.textContent = data.model_loss;
}
// Update floating PnL if position exists
const floatingPnlRow = document.getElementById('floating-pnl-row');
const floatingPnlEl = document.getElementById('floating-pnl');
if (data.position !== 'NO POSITION' && data.floating_pnl !== undefined) {
if (floatingPnlRow) floatingPnlRow.style.display = 'flex';
if (floatingPnlEl) {
const floatingPnl = data.floating_pnl || 0;
const pnlColor = floatingPnl >= 0 ? 'text-success' : 'text-danger';
const pnlSign = floatingPnl >= 0 ? '+' : '';
floatingPnlEl.textContent = `${pnlSign}$${floatingPnl.toFixed(2)}`;
floatingPnlEl.className = `fw-bold ${pnlColor}`;
}
} else {
if (floatingPnlRow) floatingPnlRow.style.display = 'none';
}
// Show/hide trading status based on activity
const tradingActiveStatus = document.getElementById('trading-active-status');
const tradingInactiveWarning = document.getElementById('trading-inactive-warning');
if (data.trading_active) {
if (tradingActiveStatus) tradingActiveStatus.style.display = 'block';
if (tradingInactiveWarning) tradingInactiveWarning.style.display = 'none';
} else {
if (tradingActiveStatus) tradingActiveStatus.style.display = 'none';
if (tradingInactiveWarning) tradingInactiveWarning.style.display = 'block';
}
}
})
.catch(error => {
console.error('Error updating trading stats:', error);
});
}
// Start polling when inference is active
function startInferenceWithTrading() {
startTradingStatsPolling();
}
function stopInferenceWithTrading() {
stopTradingStatsPolling();
}
// Hook into existing inference start/stop functions
const originalStartInference = window.startRealTimeInference;
if (originalStartInference) {
window.startRealTimeInference = function(...args) {
const result = originalStartInference.apply(this, args);
startTradingStatsPolling();
return result;
};
}
const originalStopInference = window.stopRealTimeInference;
if (originalStopInference) {
window.stopRealTimeInference = function(...args) {
const result = originalStopInference.apply(this, args);
stopTradingStatsPolling();
return result;
};
}
// Start polling on page load if inference is already active
document.addEventListener('DOMContentLoaded', function() {
// Check if inference is already running and start polling
const inferenceStatus = document.getElementById('inference-status');
if (inferenceStatus && inferenceStatus.style.display !== 'none') {
startTradingStatsPolling();
}
});
</script> </script>

View File

@@ -0,0 +1,83 @@
# Trading Stats Display Fix - Complete
## Problem Identified
The ANNOTATE app was showing static placeholder values for trading stats:
- Position: "NO POSITION" (never updated)
- Session PnL: "+$0.00" (never updated)
- Win Rate: "0% (0/0)" (never updated)
- Model Accuracy/Loss: "--" (never updated)
## Root Cause
The HTML template had the UI elements but there was no backend API or JavaScript to:
1. Fetch real trading statistics from the orchestrator/trading executor
2. Update the UI elements with live data
3. Poll for updates during active trading
## Fixes Applied
### 1. Added Trading Stats API Endpoint
```python
@self.server.route('/api/trading-stats', methods=['GET'])
def get_trading_stats():
```
This endpoint provides:
- **Position status**: Current open positions from TradingExecutor
- **Session PnL**: Total profit/loss for the session
- **Win rate**: Percentage of winning trades
- **Floating PnL**: Unrealized P&L for open positions
- **Model performance**: Latest accuracy and loss from transformer trainer
- **Trading activity**: Whether trading is active or just predictions
### 2. Added JavaScript Polling System
- **Automatic polling**: Updates every 2 seconds during active inference
- **Smart UI updates**: Shows/hides elements based on trading state
- **Color coding**: Green for profits, red for losses
- **Integration**: Hooks into existing inference start/stop functions
### 3. Enhanced UI Display Logic
- **Position display**: Shows "LONG ETH/USDT" instead of "NO POSITION" when trading
- **PnL formatting**: Proper +/- signs and color coding
- **Floating PnL**: Shows unrealized P&L for open positions
- **Model stats**: Live accuracy and loss updates
- **Trading status**: Clear indication of active vs inactive trading
## Expected Behavior Now
### During Active Trading:
-**Position**: Shows actual position (e.g., "LONG ETH/USDT")
-**Session PnL**: Updates with real profit/loss (e.g., "+$15.23" in green)
-**Win Rate**: Shows actual performance (e.g., "75.0% (3/4)")
-**Floating PnL**: Shows unrealized P&L for open positions
-**Model Stats**: Live accuracy and loss from training
### During Predictions Only:
-**Position**: "NO POSITION"
-**Session PnL**: "$0.00"
-**Win Rate**: "0% (0/0)"
-**Warning**: "PREDICTIONS ONLY" message shown
-**Model Stats**: Still shows model performance
## API Response Format
```json
{
"success": true,
"position": "LONG ETH/USDT",
"session_pnl": 15.23,
"win_rate": "75.0% (3/4)",
"floating_pnl": 8.45,
"total_trades": 4,
"winning_trades": 3,
"trading_active": true,
"model_accuracy": "73.2%",
"model_loss": "0.1234"
}
```
## Verification Steps
1. **Start inference**: Trading stats should begin updating every 2 seconds
2. **Execute trades**: Position and PnL should reflect actual trades
3. **Model training**: Accuracy and loss should update with training progress
4. **Stop inference**: Polling should stop, stats should reset to defaults
The trading dashboard now provides real-time visibility into both trading performance and model learning progress!