This commit is contained in:
Dobromir Popov
2025-11-22 02:39:23 +02:00
parent 47840a5f8e
commit 7a219b5ebc
5 changed files with 534 additions and 88 deletions

View File

@@ -517,7 +517,16 @@
// Real-time inference controls
let currentInferenceId = null;
let signalPollInterval = null;
let predictionHistory = []; // Store last 5 predictions
let predictionHistory = []; // Store last 15 predictions
// PnL tracking for simulated trading ($100 position size)
let pnlTracker = {
positions: [], // Open positions: {action, entryPrice, entryTime, size}
closedTrades: [], // Completed trades with PnL
totalPnL: 0,
winRate: 0,
positionSize: 100 // $100 per trade
};
// Prediction steps slider handler
document.getElementById('prediction-steps-slider').addEventListener('input', function() {
@@ -563,9 +572,17 @@
document.getElementById('inference-status').style.display = 'block';
document.getElementById('inference-controls').style.display = 'block';
// Clear prediction history
// Clear prediction history and reset PnL tracker
predictionHistory = [];
pnlTracker = {
positions: [],
closedTrades: [],
totalPnL: 0,
winRate: 0,
positionSize: 100
};
updatePredictionHistory();
updatePnLDisplay();
// Show live mode banner
const banner = document.getElementById('live-mode-banner');
@@ -636,9 +653,10 @@
// Stop polling
stopSignalPolling();
// Stop chart auto-update
// Stop chart auto-update and remove metrics overlay
if (window.appState && window.appState.chartManager) {
window.appState.chartManager.stopAutoUpdate();
window.appState.chartManager.removeLiveMetrics();
}
currentInferenceId = null;
@@ -842,6 +860,109 @@
}
}
function updatePnLTracking(action, currentPrice, timestamp) {
// Simple trading simulation: BUY opens long, SELL opens short, HOLD closes positions
if (action === 'BUY' && pnlTracker.positions.length === 0) {
// Open long position
pnlTracker.positions.push({
action: 'BUY',
entryPrice: currentPrice,
entryTime: timestamp,
size: pnlTracker.positionSize
});
} else if (action === 'SELL' && pnlTracker.positions.length === 0) {
// Open short position
pnlTracker.positions.push({
action: 'SELL',
entryPrice: currentPrice,
entryTime: timestamp,
size: pnlTracker.positionSize
});
} else if (action === 'HOLD' && pnlTracker.positions.length > 0) {
// Close all positions
pnlTracker.positions.forEach(pos => {
let pnl = 0;
if (pos.action === 'BUY') {
// Long: profit if price went up
pnl = (currentPrice - pos.entryPrice) / pos.entryPrice * pos.size;
} else if (pos.action === 'SELL') {
// Short: profit if price went down
pnl = (pos.entryPrice - currentPrice) / pos.entryPrice * pos.size;
}
pnlTracker.closedTrades.push({
entryPrice: pos.entryPrice,
exitPrice: currentPrice,
pnl: pnl,
entryTime: pos.entryTime,
exitTime: timestamp
});
pnlTracker.totalPnL += pnl;
});
pnlTracker.positions = [];
// Calculate win rate
const wins = pnlTracker.closedTrades.filter(t => t.pnl > 0).length;
pnlTracker.winRate = pnlTracker.closedTrades.length > 0
? (wins / pnlTracker.closedTrades.length * 100)
: 0;
}
// Update PnL display
updatePnLDisplay();
}
function updatePnLDisplay() {
const pnlColor = pnlTracker.totalPnL >= 0 ? 'text-success' : 'text-danger';
const pnlSign = pnlTracker.totalPnL >= 0 ? '+' : '';
// Update PnL metric
const pnlElement = document.getElementById('metric-pnl');
if (pnlElement) {
pnlElement.textContent = `${pnlSign}$${pnlTracker.totalPnL.toFixed(2)}`;
pnlElement.className = `h4 mb-0 ${pnlColor}`;
}
// Update Win Rate
const winrateElement = document.getElementById('metric-winrate');
if (winrateElement) {
winrateElement.textContent = pnlTracker.closedTrades.length > 0
? `${pnlTracker.winRate.toFixed(1)}%`
: '--';
}
// Update Total Trades
const tradesElement = document.getElementById('metric-trades');
if (tradesElement) {
tradesElement.textContent = pnlTracker.closedTrades.length;
}
// Update Open Positions
const positionsElement = document.getElementById('metric-positions');
if (positionsElement) {
positionsElement.textContent = pnlTracker.positions.length;
}
// Update in live banner if exists
const banner = document.getElementById('inference-status');
if (banner) {
let pnlDiv = document.getElementById('live-banner-pnl');
if (!pnlDiv) {
const metricsDiv = document.getElementById('live-banner-metrics');
if (metricsDiv) {
pnlDiv = document.createElement('span');
pnlDiv.id = 'live-banner-pnl';
metricsDiv.appendChild(pnlDiv);
}
}
if (pnlDiv) {
pnlDiv.innerHTML = `<span class="${pnlColor}">PnL: ${pnlSign}$${pnlTracker.totalPnL.toFixed(2)}</span>`;
}
}
}
function updatePredictionHistory() {
const historyDiv = document.getElementById('prediction-history');
if (predictionHistory.length === 0) {
@@ -932,22 +1053,48 @@
timestamp = latest.timestamp;
}
// Get current price from signal (backend uses 'price' field)
const currentPrice = latest.price || latest.current_price;
// Add to prediction history (keep last 15)
const newPrediction = {
timestamp: timestamp,
action: latest.action,
confidence: latest.confidence,
predicted_price: latest.predicted_price,
current_price: currentPrice,
timeframe: appState.currentTimeframes ? appState.currentTimeframes[0] : '1m'
};
// Filter out undefined/invalid predictions before adding
if (latest.action && !isNaN(latest.confidence)) {
// Strengthen filter: only add valid signals
const validActions = ['BUY', 'SELL', 'HOLD'];
if (latest.action &&
validActions.includes(latest.action) &&
!isNaN(latest.confidence) &&
latest.confidence > 0 &&
currentPrice &&
!isNaN(currentPrice)) {
// Update PnL tracking
updatePnLTracking(latest.action, currentPrice, timestamp);
predictionHistory.unshift(newPrediction);
if (predictionHistory.length > 15) {
predictionHistory = predictionHistory.slice(0, 15);
}
updatePredictionHistory();
} else {
console.warn('Signal filtered out:', {
action: latest.action,
confidence: latest.confidence,
price: currentPrice,
reason: !latest.action ? 'no action' :
!validActions.includes(latest.action) ? 'invalid action' :
isNaN(latest.confidence) ? 'NaN confidence' :
latest.confidence <= 0 ? 'zero confidence' :
!currentPrice ? 'no price' :
isNaN(currentPrice) ? 'NaN price' : 'unknown'
});
}
// Update chart with signal markers and predictions
@@ -960,6 +1107,11 @@
predictions[modelKey] = latest;
window.appState.chartManager.updatePredictions(predictions);
// Display live metrics on the active chart
if (data.metrics) {
window.appState.chartManager.updateLiveMetrics(data.metrics);
}
}
}
})