fix pred candles viz
This commit is contained in:
@@ -15,6 +15,16 @@ class ChartManager {
|
||||
this.lastPredictionUpdate = {}; // Track last prediction update per timeframe
|
||||
this.predictionUpdateThrottle = 500; // Min ms between prediction updates
|
||||
this.lastPredictionHash = null; // Track if predictions actually changed
|
||||
this.ghostCandleHistory = {}; // Store ghost candles per timeframe (max 10 each)
|
||||
this.maxGhostCandles = 10; // Maximum number of ghost candles to keep
|
||||
|
||||
// Helper to ensure all timestamps are in UTC
|
||||
this.normalizeTimestamp = (timestamp) => {
|
||||
if (!timestamp) return null;
|
||||
// Parse and convert to UTC ISO string
|
||||
const date = new Date(timestamp);
|
||||
return date.toISOString(); // Always returns UTC with Z suffix
|
||||
};
|
||||
|
||||
console.log('ChartManager initialized with timeframes:', timeframes);
|
||||
}
|
||||
@@ -2008,12 +2018,37 @@ class ChartManager {
|
||||
targetTimestamp = new Date(inferenceTime.getTime() + 60000);
|
||||
}
|
||||
|
||||
// 1. Next Candle Prediction (Ghost)
|
||||
// Show the prediction at its proper timestamp
|
||||
this._addGhostCandlePrediction(candleData, timeframe, predictionTraces, targetTimestamp);
|
||||
// 1. Initialize ghost candle history for this timeframe if needed
|
||||
if (!this.ghostCandleHistory[timeframe]) {
|
||||
this.ghostCandleHistory[timeframe] = [];
|
||||
}
|
||||
|
||||
// 2. Store as "Last Prediction" for this timeframe
|
||||
// This allows us to visualize the "Shadow" (prediction vs actual) on the next tick
|
||||
// 2. Add new ghost candle to history
|
||||
const year = targetTimestamp.getUTCFullYear();
|
||||
const month = String(targetTimestamp.getUTCMonth() + 1).padStart(2, '0');
|
||||
const day = String(targetTimestamp.getUTCDate()).padStart(2, '0');
|
||||
const hours = String(targetTimestamp.getUTCHours()).padStart(2, '0');
|
||||
const minutes = String(targetTimestamp.getUTCMinutes()).padStart(2, '0');
|
||||
const seconds = String(targetTimestamp.getUTCSeconds()).padStart(2, '0');
|
||||
const formattedTimestamp = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
|
||||
this.ghostCandleHistory[timeframe].push({
|
||||
timestamp: formattedTimestamp,
|
||||
candle: candleData,
|
||||
targetTime: targetTimestamp
|
||||
});
|
||||
|
||||
// 3. Keep only last 10 ghost candles
|
||||
if (this.ghostCandleHistory[timeframe].length > this.maxGhostCandles) {
|
||||
this.ghostCandleHistory[timeframe] = this.ghostCandleHistory[timeframe].slice(-this.maxGhostCandles);
|
||||
}
|
||||
|
||||
// 4. Add all ghost candles from history to traces
|
||||
for (const ghost of this.ghostCandleHistory[timeframe]) {
|
||||
this._addGhostCandlePrediction(ghost.candle, timeframe, predictionTraces, ghost.targetTime);
|
||||
}
|
||||
|
||||
// 5. Store as "Last Prediction" for shadow rendering
|
||||
if (!this.lastPredictions) this.lastPredictions = {};
|
||||
|
||||
this.lastPredictions[timeframe] = {
|
||||
@@ -2022,7 +2057,7 @@ class ChartManager {
|
||||
inferenceTime: predictionTimestamp
|
||||
};
|
||||
|
||||
console.log(`[${timeframe}] Ghost candle prediction placed at ${targetTimestamp.toISOString()} (inference at ${predictionTimestamp})`);
|
||||
console.log(`[${timeframe}] Ghost candle added (${this.ghostCandleHistory[timeframe].length}/${this.maxGhostCandles}) at ${targetTimestamp.toISOString()}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2166,6 +2201,15 @@ class ChartManager {
|
||||
}
|
||||
}
|
||||
|
||||
// Format timestamp to match real candles: 'YYYY-MM-DD HH:MM:SS'
|
||||
const year = nextTimestamp.getUTCFullYear();
|
||||
const month = String(nextTimestamp.getUTCMonth() + 1).padStart(2, '0');
|
||||
const day = String(nextTimestamp.getUTCDate()).padStart(2, '0');
|
||||
const hours = String(nextTimestamp.getUTCHours()).padStart(2, '0');
|
||||
const minutes = String(nextTimestamp.getUTCMinutes()).padStart(2, '0');
|
||||
const seconds = String(nextTimestamp.getUTCSeconds()).padStart(2, '0');
|
||||
const formattedTimestamp = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
|
||||
const open = candleData[0];
|
||||
const high = candleData[1];
|
||||
const low = candleData[2];
|
||||
@@ -2174,9 +2218,10 @@ class ChartManager {
|
||||
// Determine color
|
||||
const color = close >= open ? '#10b981' : '#ef4444';
|
||||
|
||||
// Create ghost candle trace
|
||||
// Create ghost candle trace with formatted timestamp string (same as real candles)
|
||||
// 150% wider than normal candles
|
||||
const ghostTrace = {
|
||||
x: [nextTimestamp],
|
||||
x: [formattedTimestamp],
|
||||
open: [open],
|
||||
high: [high],
|
||||
low: [low],
|
||||
@@ -2184,26 +2229,39 @@ class ChartManager {
|
||||
type: 'candlestick',
|
||||
name: 'Ghost Prediction',
|
||||
increasing: {
|
||||
line: { color: color, width: 1 },
|
||||
line: { color: color, width: 3 }, // 150% wider (normal is 2, so 3)
|
||||
fillcolor: color
|
||||
},
|
||||
decreasing: {
|
||||
line: { color: color, width: 1 },
|
||||
line: { color: color, width: 3 }, // 150% wider
|
||||
fillcolor: color
|
||||
},
|
||||
opacity: 0.6, // 60% transparent
|
||||
hoverinfo: 'x+y+text',
|
||||
text: ['Predicted Next Candle']
|
||||
text: ['Predicted Next Candle'],
|
||||
width: 1.5 // 150% width multiplier
|
||||
};
|
||||
|
||||
traces.push(ghostTrace);
|
||||
console.log('Added ghost candle prediction:', ghostTrace);
|
||||
console.log('Added ghost candle prediction at:', formattedTimestamp, ghostTrace);
|
||||
}
|
||||
|
||||
_addShadowCandlePrediction(candleData, timestamp, traces) {
|
||||
// candleData is [Open, High, Low, Close, Volume]
|
||||
// timestamp is the time where this shadow should appear (matches current candle)
|
||||
|
||||
// Format timestamp to match real candles if it's a Date object
|
||||
let formattedTimestamp = timestamp;
|
||||
if (timestamp instanceof Date) {
|
||||
const year = timestamp.getUTCFullYear();
|
||||
const month = String(timestamp.getUTCMonth() + 1).padStart(2, '0');
|
||||
const day = String(timestamp.getUTCDate()).padStart(2, '0');
|
||||
const hours = String(timestamp.getUTCHours()).padStart(2, '0');
|
||||
const minutes = String(timestamp.getUTCMinutes()).padStart(2, '0');
|
||||
const seconds = String(timestamp.getUTCSeconds()).padStart(2, '0');
|
||||
formattedTimestamp = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
const open = candleData[0];
|
||||
const high = candleData[1];
|
||||
const low = candleData[2];
|
||||
@@ -2212,8 +2270,9 @@ class ChartManager {
|
||||
// Shadow color (purple to distinguish from ghost)
|
||||
const color = '#8b5cf6'; // Violet
|
||||
|
||||
// Shadow candles also 150% wider
|
||||
const shadowTrace = {
|
||||
x: [timestamp],
|
||||
x: [formattedTimestamp],
|
||||
open: [open],
|
||||
high: [high],
|
||||
low: [low],
|
||||
@@ -2221,16 +2280,17 @@ class ChartManager {
|
||||
type: 'candlestick',
|
||||
name: 'Shadow Prediction',
|
||||
increasing: {
|
||||
line: { color: color, width: 1 },
|
||||
line: { color: color, width: 3 }, // 150% wider
|
||||
fillcolor: 'rgba(139, 92, 246, 0.0)' // Hollow
|
||||
},
|
||||
decreasing: {
|
||||
line: { color: color, width: 1 },
|
||||
line: { color: color, width: 3 }, // 150% wider
|
||||
fillcolor: 'rgba(139, 92, 246, 0.0)' // Hollow
|
||||
},
|
||||
opacity: 0.7,
|
||||
hoverinfo: 'x+y+text',
|
||||
text: ['Past Prediction']
|
||||
text: ['Past Prediction'],
|
||||
width: 1.5 // 150% width multiplier
|
||||
};
|
||||
|
||||
traces.push(shadowTrace);
|
||||
|
||||
Reference in New Issue
Block a user