LIVE CHART WORKS ON ANNOTATE APP

This commit is contained in:
Dobromir Popov
2025-11-22 01:26:25 +02:00
parent 6ad09acc19
commit a1d3d6a865
2 changed files with 169 additions and 27 deletions

View File

@@ -30,7 +30,7 @@ class ChartManager {
// Update 1s chart every 2 seconds (was 20s)
if (this.timeframes.includes('1s')) {
this.updateTimers['1s'] = setInterval(() => {
this.updateChart('1s');
this.updateChartIncremental('1s');
}, 2000); // 2 seconds
}
@@ -42,11 +42,11 @@ class ChartManager {
// Update on next whole minute
setTimeout(() => {
this.updateChart('1m');
this.updateChartIncremental('1m');
// Then update every 5s
this.updateTimers['1m'] = setInterval(() => {
this.updateChart('1m');
this.updateChartIncremental('1m');
}, 5000); // 5 seconds
}, msUntilNextMinute);
}
@@ -111,6 +111,118 @@ class ChartManager {
}
}
/**
* Update chart incrementally by appending only new data
* This is much lighter than full chart refresh
*/
async updateChartIncremental(timeframe) {
const chart = this.charts[timeframe];
if (!chart || !chart.data || !chart.data.timestamps || chart.data.timestamps.length === 0) {
// Fallback to full update if no existing data
return this.updateChart(timeframe);
}
try {
// Get last timestamp from current data
const lastTimestamp = chart.data.timestamps[chart.data.timestamps.length - 1];
// Fetch only data AFTER last timestamp
const response = await fetch('/api/chart-data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
symbol: window.appState?.currentSymbol || 'ETH/USDT',
timeframes: [timeframe],
start_time: lastTimestamp,
limit: 50, // Small limit for incremental update
direction: 'after'
})
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const result = await response.json();
if (result.success && result.chart_data && result.chart_data[timeframe]) {
const newData = result.chart_data[timeframe];
// If we got new data
if (newData.timestamps.length > 0) {
// Filter out duplicates just in case
const uniqueIndices = [];
const lastTime = new Date(lastTimestamp).getTime();
newData.timestamps.forEach((ts, i) => {
if (new Date(ts).getTime() > lastTime) {
uniqueIndices.push(i);
}
});
if (uniqueIndices.length === 0) return;
const uniqueData = {
timestamps: uniqueIndices.map(i => newData.timestamps[i]),
open: uniqueIndices.map(i => newData.open[i]),
high: uniqueIndices.map(i => newData.high[i]),
low: uniqueIndices.map(i => newData.low[i]),
close: uniqueIndices.map(i => newData.close[i]),
volume: uniqueIndices.map(i => newData.volume[i])
};
// Update chart using extendTraces
const plotId = chart.plotId;
Plotly.extendTraces(plotId, {
x: [uniqueData.timestamps],
open: [uniqueData.open],
high: [uniqueData.high],
low: [uniqueData.low],
close: [uniqueData.close]
}, [0]);
// Update volume
const volumeColors = uniqueData.close.map((close, i) => {
return close >= uniqueData.open[i] ? '#10b981' : '#ef4444';
});
Plotly.extendTraces(plotId, {
x: [uniqueData.timestamps],
y: [uniqueData.volume],
'marker.color': [volumeColors]
}, [1]);
// Update local data cache
chart.data.timestamps.push(...uniqueData.timestamps);
chart.data.open.push(...uniqueData.open);
chart.data.high.push(...uniqueData.high);
chart.data.low.push(...uniqueData.low);
chart.data.close.push(...uniqueData.close);
chart.data.volume.push(...uniqueData.volume);
// Keep memory usage in check (limit to 5000 candles)
const MAX_CANDLES = 5000;
if (chart.data.timestamps.length > MAX_CANDLES) {
const dropCount = chart.data.timestamps.length - MAX_CANDLES;
chart.data.timestamps.splice(0, dropCount);
chart.data.open.splice(0, dropCount);
chart.data.high.splice(0, dropCount);
chart.data.low.splice(0, dropCount);
chart.data.close.splice(0, dropCount);
chart.data.volume.splice(0, dropCount);
// Note: Plotly.relayout could be used to shift window, but extending is fine for visual updates
}
console.log(`Appended ${uniqueData.timestamps.length} new candles to ${timeframe} chart`);
}
}
} catch (error) {
console.error(`Error updating ${timeframe} chart incrementally:`, error);
}
}
/**
* Update latest candle on chart (for live updates)
* Efficiently updates only the last candle or adds a new one