fixes
This commit is contained in:
@@ -343,9 +343,34 @@ class AnnotationDashboard:
|
||||
'volume': df['volume'].tolist()
|
||||
}
|
||||
|
||||
# Get pivot bounds for the symbol
|
||||
pivot_bounds = None
|
||||
if self.data_provider:
|
||||
try:
|
||||
pivot_bounds = self.data_provider.get_pivot_bounds(symbol)
|
||||
if pivot_bounds:
|
||||
logger.info(f"Found pivot bounds for {symbol}: {len(pivot_bounds.pivot_support_levels)} support, {len(pivot_bounds.pivot_resistance_levels)} resistance")
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting pivot bounds: {e}")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'chart_data': chart_data
|
||||
'chart_data': chart_data,
|
||||
'pivot_bounds': {
|
||||
'support_levels': pivot_bounds.pivot_support_levels if pivot_bounds else [],
|
||||
'resistance_levels': pivot_bounds.pivot_resistance_levels if pivot_bounds else [],
|
||||
'price_range': {
|
||||
'min': pivot_bounds.price_min if pivot_bounds else None,
|
||||
'max': pivot_bounds.price_max if pivot_bounds else None
|
||||
},
|
||||
'volume_range': {
|
||||
'min': pivot_bounds.volume_min if pivot_bounds else None,
|
||||
'max': pivot_bounds.volume_max if pivot_bounds else None
|
||||
},
|
||||
'timeframe': '1m', # Pivot bounds are calculated from 1m data
|
||||
'period': '30 days', # Monthly data
|
||||
'total_levels': len(pivot_bounds.pivot_support_levels) + len(pivot_bounds.pivot_resistance_levels) if pivot_bounds else 0
|
||||
} if pivot_bounds else None
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
@@ -559,9 +584,34 @@ class AnnotationDashboard:
|
||||
except Exception as e:
|
||||
logger.error(f"Error refreshing {timeframe} data: {e}")
|
||||
|
||||
# Get pivot bounds for the symbol
|
||||
pivot_bounds = None
|
||||
if self.data_provider:
|
||||
try:
|
||||
pivot_bounds = self.data_provider.get_pivot_bounds(symbol)
|
||||
if pivot_bounds:
|
||||
logger.info(f"Found pivot bounds for {symbol}: {len(pivot_bounds.pivot_support_levels)} support, {len(pivot_bounds.pivot_resistance_levels)} resistance")
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting pivot bounds: {e}")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'chart_data': chart_data,
|
||||
'pivot_bounds': {
|
||||
'support_levels': pivot_bounds.pivot_support_levels if pivot_bounds else [],
|
||||
'resistance_levels': pivot_bounds.pivot_resistance_levels if pivot_bounds else [],
|
||||
'price_range': {
|
||||
'min': pivot_bounds.price_min if pivot_bounds else None,
|
||||
'max': pivot_bounds.price_max if pivot_bounds else None
|
||||
},
|
||||
'volume_range': {
|
||||
'min': pivot_bounds.volume_min if pivot_bounds else None,
|
||||
'max': pivot_bounds.volume_max if pivot_bounds else None
|
||||
},
|
||||
'timeframe': '1m', # Pivot bounds are calculated from 1m data
|
||||
'period': '30 days', # Monthly data
|
||||
'total_levels': len(pivot_bounds.pivot_support_levels) + len(pivot_bounds.pivot_resistance_levels) if pivot_bounds else 0
|
||||
} if pivot_bounds else None,
|
||||
'message': f'Refreshed data for {symbol}'
|
||||
})
|
||||
|
||||
|
||||
@@ -14,14 +14,15 @@ class ChartManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize charts for all timeframes
|
||||
* Initialize charts for all timeframes with pivot bounds
|
||||
*/
|
||||
initializeCharts(chartData) {
|
||||
initializeCharts(chartData, pivotBounds = null) {
|
||||
console.log('Initializing charts with data:', chartData);
|
||||
console.log('Pivot bounds:', pivotBounds);
|
||||
|
||||
this.timeframes.forEach(timeframe => {
|
||||
if (chartData[timeframe]) {
|
||||
this.createChart(timeframe, chartData[timeframe]);
|
||||
this.createChart(timeframe, chartData[timeframe], pivotBounds);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -32,7 +33,7 @@ class ChartManager {
|
||||
/**
|
||||
* Create a single chart for a timeframe
|
||||
*/
|
||||
createChart(timeframe, data) {
|
||||
createChart(timeframe, data, pivotBounds = null) {
|
||||
const plotId = `plot-${timeframe}`;
|
||||
const plotElement = document.getElementById(plotId);
|
||||
|
||||
@@ -129,7 +130,49 @@ class ChartManager {
|
||||
scrollZoom: true
|
||||
};
|
||||
|
||||
Plotly.newPlot(plotId, [candlestickTrace, volumeTrace], layout, config);
|
||||
// Prepare chart data with pivot bounds
|
||||
const chartData = [candlestickTrace, volumeTrace];
|
||||
|
||||
// Add pivot levels if available
|
||||
if (pivotBounds && pivotBounds.support_levels && pivotBounds.resistance_levels) {
|
||||
// Add support levels
|
||||
pivotBounds.support_levels.forEach((level, index) => {
|
||||
chartData.push({
|
||||
x: data.timestamps,
|
||||
y: Array(data.timestamps.length).fill(level),
|
||||
type: 'scatter',
|
||||
mode: 'lines',
|
||||
line: {
|
||||
color: '#28a745',
|
||||
width: 1,
|
||||
dash: 'dash'
|
||||
},
|
||||
name: `Support ${index + 1}`,
|
||||
showlegend: index === 0, // Only show legend for first support level
|
||||
hovertemplate: `Support: $%{y:.2f}<extra></extra>`
|
||||
});
|
||||
});
|
||||
|
||||
// Add resistance levels
|
||||
pivotBounds.resistance_levels.forEach((level, index) => {
|
||||
chartData.push({
|
||||
x: data.timestamps,
|
||||
y: Array(data.timestamps.length).fill(level),
|
||||
type: 'scatter',
|
||||
mode: 'lines',
|
||||
line: {
|
||||
color: '#dc3545',
|
||||
width: 1,
|
||||
dash: 'dash'
|
||||
},
|
||||
name: `Resistance ${index + 1}`,
|
||||
showlegend: index === 0, // Only show legend for first resistance level
|
||||
hovertemplate: `Resistance: $%{y:.2f}<extra></extra>`
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Plotly.newPlot(plotId, chartData, layout, config);
|
||||
|
||||
// Store chart reference
|
||||
this.charts[timeframe] = {
|
||||
@@ -204,29 +247,74 @@ class ChartManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Update charts with new data
|
||||
* Update charts with new data including pivot levels
|
||||
*/
|
||||
updateCharts(newData) {
|
||||
updateCharts(newData, pivotBounds = null) {
|
||||
Object.keys(newData).forEach(timeframe => {
|
||||
if (this.charts[timeframe]) {
|
||||
const plotId = this.charts[timeframe].plotId;
|
||||
|
||||
Plotly.react(plotId, [
|
||||
// Prepare chart data
|
||||
const chartData = [
|
||||
{
|
||||
x: newData[timeframe].timestamps,
|
||||
open: newData[timeframe].open,
|
||||
high: newData[timeframe].high,
|
||||
low: newData[timeframe].low,
|
||||
close: newData[timeframe].close,
|
||||
type: 'candlestick'
|
||||
type: 'candlestick',
|
||||
name: 'Price'
|
||||
},
|
||||
{
|
||||
x: newData[timeframe].timestamps,
|
||||
y: newData[timeframe].volume,
|
||||
type: 'bar',
|
||||
yaxis: 'y2'
|
||||
yaxis: 'y2',
|
||||
name: 'Volume',
|
||||
marker: { color: 'rgba(0, 123, 255, 0.3)' }
|
||||
}
|
||||
]);
|
||||
];
|
||||
|
||||
// Add pivot levels if available
|
||||
if (pivotBounds && pivotBounds.support_levels && pivotBounds.resistance_levels) {
|
||||
// Add support levels
|
||||
pivotBounds.support_levels.forEach((level, index) => {
|
||||
chartData.push({
|
||||
x: newData[timeframe].timestamps,
|
||||
y: Array(newData[timeframe].timestamps.length).fill(level),
|
||||
type: 'scatter',
|
||||
mode: 'lines',
|
||||
line: {
|
||||
color: '#28a745',
|
||||
width: 1,
|
||||
dash: 'dash'
|
||||
},
|
||||
name: `Support ${index + 1}`,
|
||||
showlegend: index === 0, // Only show legend for first support level
|
||||
hovertemplate: `Support: $%{y:.2f}<extra></extra>`
|
||||
});
|
||||
});
|
||||
|
||||
// Add resistance levels
|
||||
pivotBounds.resistance_levels.forEach((level, index) => {
|
||||
chartData.push({
|
||||
x: newData[timeframe].timestamps,
|
||||
y: Array(newData[timeframe].timestamps.length).fill(level),
|
||||
type: 'scatter',
|
||||
mode: 'lines',
|
||||
line: {
|
||||
color: '#dc3545',
|
||||
width: 1,
|
||||
dash: 'dash'
|
||||
},
|
||||
name: `Resistance ${index + 1}`,
|
||||
showlegend: index === 0, // Only show legend for first resistance level
|
||||
hovertemplate: `Resistance: $%{y:.2f}<extra></extra>`
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Plotly.react(plotId, chartData);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -61,8 +61,8 @@
|
||||
// Initialize application state
|
||||
window.appState = {
|
||||
currentSymbol: '{{ current_symbol }}',
|
||||
currentTimeframes: {{ timeframes | tojson }},
|
||||
annotations: { { annotations | tojson } },
|
||||
currentTimeframes: '{{ timeframes | tojson }}',
|
||||
annotations: '{{ annotations | tojson }}',
|
||||
pendingAnnotation: null,
|
||||
chartManager: null,
|
||||
annotationManager: null,
|
||||
@@ -95,7 +95,87 @@
|
||||
});
|
||||
|
||||
function loadInitialData() {
|
||||
console.log('Loading initial chart data...');
|
||||
|
||||
// Fetch initial chart data
|
||||
fetch('/api/chart-data', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
symbol: appState.currentSymbol,
|
||||
timeframes: appState.currentTimeframes,
|
||||
start_time: null,
|
||||
end_time: null
|
||||
})
|
||||
})
|
||||
.then(response => {
|
||||
console.log('Chart data response status:', response.status);
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
console.log('Chart data received:', data);
|
||||
|
||||
if (data.success) {
|
||||
console.log('Initializing charts with data...');
|
||||
window.appState.chartManager.initializeCharts(data.chart_data, data.pivot_bounds);
|
||||
|
||||
// Show pivot bounds info if available
|
||||
if (data.pivot_bounds) {
|
||||
const pivotInfo = data.pivot_bounds;
|
||||
console.log(`Loaded ${pivotInfo.total_levels} pivot levels (${pivotInfo.support_levels.length} support, ${pivotInfo.resistance_levels.length} resistance) from ${pivotInfo.timeframe} data over ${pivotInfo.period}`);
|
||||
}
|
||||
|
||||
// Load existing annotations
|
||||
console.log('Loading', window.appState.annotations.length, 'existing annotations');
|
||||
window.appState.annotations.forEach(annotation => {
|
||||
window.appState.chartManager.addAnnotation(annotation);
|
||||
});
|
||||
|
||||
// Update annotation list
|
||||
if (typeof renderAnnotationsList === 'function') {
|
||||
renderAnnotationsList(window.appState.annotations);
|
||||
}
|
||||
|
||||
// DISABLED: Live updates were causing data corruption (red wall issue)
|
||||
// Use manual refresh button instead
|
||||
// startLiveChartUpdates();
|
||||
|
||||
console.log('Initial data load complete');
|
||||
} else {
|
||||
console.error('Chart data load failed:', data.error);
|
||||
showError('Failed to load chart data: ' + data.error.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Chart data fetch error:', error);
|
||||
showError('Network error: ' + error.message);
|
||||
});
|
||||
}
|
||||
|
||||
// Live chart update mechanism
|
||||
let liveUpdateInterval = null;
|
||||
|
||||
function startLiveChartUpdates() {
|
||||
// Clear any existing interval
|
||||
if (liveUpdateInterval) {
|
||||
clearInterval(liveUpdateInterval);
|
||||
}
|
||||
|
||||
console.log('Starting live chart updates (1s interval)');
|
||||
|
||||
// Update every second for 1s chart
|
||||
liveUpdateInterval = setInterval(() => {
|
||||
updateLiveChartData();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function updateLiveChartData() {
|
||||
// Only update if we have a chart manager
|
||||
if (!window.appState || !window.appState.chartManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch latest data
|
||||
fetch('/api/chart-data', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
@@ -108,28 +188,30 @@
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
window.appState.chartManager.initializeCharts(data.chart_data);
|
||||
if (data.success && window.appState.chartManager) {
|
||||
// Update charts with new data and pivot bounds
|
||||
window.appState.chartManager.updateCharts(data.chart_data, data.pivot_bounds);
|
||||
|
||||
// Load existing annotations
|
||||
console.log('Loading', window.appState.annotations.length, 'existing annotations');
|
||||
window.appState.annotations.forEach(annotation => {
|
||||
window.appState.chartManager.addAnnotation(annotation);
|
||||
});
|
||||
|
||||
// Update annotation list
|
||||
if (typeof renderAnnotationsList === 'function') {
|
||||
renderAnnotationsList(window.appState.annotations);
|
||||
// Show pivot bounds info if available
|
||||
if (data.pivot_bounds) {
|
||||
const pivotInfo = data.pivot_bounds;
|
||||
console.log(`Loaded ${pivotInfo.total_levels} pivot levels (${pivotInfo.support_levels.length} support, ${pivotInfo.resistance_levels.length} resistance) from ${pivotInfo.timeframe} data over ${pivotInfo.period}`);
|
||||
}
|
||||
} else {
|
||||
showError('Failed to load chart data: ' + data.error.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showError('Network error: ' + error.message);
|
||||
console.debug('Live update error:', error);
|
||||
// Don't show error to user for live updates
|
||||
});
|
||||
}
|
||||
|
||||
// Clean up on page unload
|
||||
window.addEventListener('beforeunload', function () {
|
||||
if (liveUpdateInterval) {
|
||||
clearInterval(liveUpdateInterval);
|
||||
}
|
||||
});
|
||||
|
||||
function setupKeyboardShortcuts() {
|
||||
document.addEventListener('keydown', function (e) {
|
||||
// Arrow left - navigate backward
|
||||
|
||||
@@ -218,11 +218,18 @@
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
// Update charts with new data
|
||||
// Update charts with new data and pivot bounds
|
||||
if (appState.chartManager) {
|
||||
appState.chartManager.updateCharts(data.chart_data);
|
||||
appState.chartManager.updateCharts(data.chart_data, data.pivot_bounds);
|
||||
}
|
||||
|
||||
// Show pivot bounds info if available
|
||||
if (data.pivot_bounds) {
|
||||
const pivotInfo = data.pivot_bounds;
|
||||
showSuccess(`Chart data refreshed successfully. Found ${pivotInfo.total_levels} pivot levels (${pivotInfo.support_levels.length} support, ${pivotInfo.resistance_levels.length} resistance) from ${pivotInfo.timeframe} data over ${pivotInfo.period}`);
|
||||
} else {
|
||||
showSuccess('Chart data refreshed successfully');
|
||||
}
|
||||
showSuccess('Chart data refreshed successfully');
|
||||
} else {
|
||||
showError('Failed to refresh data: ' + data.error.message);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user