LIVE CHART WORKS ON ANNOTATE APP
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user