From 86a579bea9cf9d93bfa6bbeaf83267e03f26160f Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Fri, 24 Oct 2025 23:26:59 +0300 Subject: [PATCH] fix template again --- ANNOTATE/web/app.py | 57 +++++- ANNOTATE/web/static/js/chart_manager.js | 180 +++++++++++++++++- .../web/templates/annotation_dashboard.html | 6 +- 3 files changed, 238 insertions(+), 5 deletions(-) diff --git a/ANNOTATE/web/app.py b/ANNOTATE/web/app.py index 7297bb9..4a3011f 100644 --- a/ANNOTATE/web/app.py +++ b/ANNOTATE/web/app.py @@ -480,6 +480,51 @@ class AnnotationDashboard: """ + @self.server.route('/api/recalculate-pivots', methods=['POST']) + def recalculate_pivots(): + """Recalculate pivot points for merged data""" + try: + data = request.get_json() + symbol = data.get('symbol', 'ETH/USDT') + timeframe = data.get('timeframe') + timestamps = data.get('timestamps', []) + ohlcv_data = data.get('ohlcv', {}) + + if not timeframe or not timestamps: + return jsonify({ + 'success': False, + 'error': {'code': 'INVALID_REQUEST', 'message': 'Missing timeframe or timestamps'} + }) + + logger.info(f"🔄 Recalculating pivots for {symbol} {timeframe} with {len(timestamps)} candles") + + # Convert to DataFrame + df = pd.DataFrame({ + 'open': ohlcv_data.get('open', []), + 'high': ohlcv_data.get('high', []), + 'low': ohlcv_data.get('low', []), + 'close': ohlcv_data.get('close', []), + 'volume': ohlcv_data.get('volume', []) + }) + df.index = pd.to_datetime(timestamps) + + # Recalculate pivot markers + pivot_markers = self._get_pivot_markers_for_timeframe(symbol, timeframe, df) + + logger.info(f" ✅ Recalculated {len(pivot_markers)} pivot candles") + + return jsonify({ + 'success': True, + 'pivot_markers': pivot_markers + }) + + except Exception as e: + logger.error(f"Error recalculating pivots: {e}") + return jsonify({ + 'success': False, + 'error': {'code': 'RECALC_ERROR', 'message': str(e)} + }) + @self.server.route('/api/chart-data', methods=['POST']) def get_chart_data(): """Get chart data for specified symbol and timeframes with infinite scroll support""" @@ -489,9 +534,15 @@ class AnnotationDashboard: timeframes = data.get('timeframes', ['1s', '1m', '1h', '1d']) start_time_str = data.get('start_time') end_time_str = data.get('end_time') - limit = data.get('limit', 500) # Allow client to request more data + limit = data.get('limit', 2000) # Default 2000 candles for training direction = data.get('direction', 'latest') # 'latest', 'before', or 'after' + logger.info(f"📊 Chart data request: {symbol} {timeframes} direction={direction} limit={limit}") + if start_time_str: + logger.info(f" start_time: {start_time_str}") + if end_time_str: + logger.info(f" end_time: {end_time_str}") + if not self.data_loader: return jsonify({ 'success': False, @@ -522,6 +573,8 @@ class AnnotationDashboard: ) if df is not None and not df.empty: + logger.info(f" ✅ {timeframe}: {len(df)} candles ({df.index[0]} to {df.index[-1]})") + # Get pivot points for this timeframe pivot_markers = self._get_pivot_markers_for_timeframe(symbol, timeframe, df) @@ -535,6 +588,8 @@ class AnnotationDashboard: 'volume': df['volume'].tolist(), 'pivot_markers': pivot_markers # Optional: only present if pivots exist } + else: + logger.warning(f" ❌ {timeframe}: No data returned") # Get pivot bounds for the symbol pivot_bounds = None diff --git a/ANNOTATE/web/static/js/chart_manager.js b/ANNOTATE/web/static/js/chart_manager.js index cdd5f1b..774c817 100644 --- a/ANNOTATE/web/static/js/chart_manager.js +++ b/ANNOTATE/web/static/js/chart_manager.js @@ -1190,6 +1190,14 @@ class ChartManager { const result = await response.json(); + console.log(`📊 API Response for ${timeframe} ${direction}:`, { + success: result.success, + hasChartData: !!result.chart_data, + hasTimeframeData: result.chart_data ? !!result.chart_data[timeframe] : false, + dataLength: result.chart_data && result.chart_data[timeframe] ? result.chart_data[timeframe].timestamps.length : 0, + error: result.error + }); + if (result.success && result.chart_data && result.chart_data[timeframe]) { const newData = result.chart_data[timeframe]; @@ -1200,13 +1208,18 @@ class ChartManager { return; } + // Log data ranges for debugging + console.log(`📥 New data: ${newData.timestamps[0]} to ${newData.timestamps[newData.timestamps.length - 1]}`); + console.log(`📦 Existing: ${chart.data.timestamps[0]} to ${chart.data.timestamps[chart.data.timestamps.length - 1]}`); + // Merge with existing data this.mergeChartData(timeframe, newData, direction); - console.log(`Loaded ${newData.timestamps.length} new candles for ${timeframe}`); + console.log(`✅ Loaded ${newData.timestamps.length} new candles for ${timeframe}`); window.showSuccess(`Loaded ${newData.timestamps.length} more candles`); } else { - console.warn(`No more data available for ${timeframe} ${direction}`); + console.warn(`❌ No more data available for ${timeframe} ${direction}`); + console.warn('Full result:', result); window.showWarning('No more historical data available'); } @@ -1287,10 +1300,173 @@ class ChartManager { // Update stored data chart.data = mergedData; + // Recalculate pivot points for the merged data + this.recalculatePivots(timeframe, mergedData); + // Update the chart with merged data this.updateSingleChart(timeframe, mergedData); } + /** + * Recalculate pivot points for merged data + */ + async recalculatePivots(timeframe, data) { + try { + console.log(`🔄 Recalculating pivots for ${timeframe} with ${data.timestamps.length} candles...`); + + const response = await fetch('/api/recalculate-pivots', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + symbol: window.appState?.currentSymbol || 'ETH/USDT', + timeframe: timeframe, + timestamps: data.timestamps, + ohlcv: { + open: data.open, + high: data.high, + low: data.low, + close: data.close, + volume: data.volume + } + }) + }); + + const result = await response.json(); + + if (result.success && result.pivot_markers) { + // Update pivot markers in chart data + const chart = this.charts[timeframe]; + if (chart && chart.data) { + chart.data.pivot_markers = result.pivot_markers; + console.log(`✅ Pivots recalculated: ${Object.keys(result.pivot_markers).length} pivot candles`); + + // Redraw the chart with updated pivots + this.redrawChartWithPivots(timeframe, chart.data); + } + } else { + console.warn('Failed to recalculate pivots:', result.error); + } + + } catch (error) { + console.error(`Error recalculating pivots for ${timeframe}:`, error); + } + } + + /** + * Redraw chart with updated pivot markers + */ + redrawChartWithPivots(timeframe, data) { + const chart = this.charts[timeframe]; + if (!chart) return; + + // Build pivot shapes and annotations + const shapes = []; + const annotations = []; + const pivotDots = { + x: [], y: [], text: [], + marker: { color: [], size: [], symbol: [] }, + mode: 'markers', + hoverinfo: 'text', + showlegend: false + }; + + if (data.pivot_markers && Object.keys(data.pivot_markers).length > 0) { + const xMin = data.timestamps[0]; + const xMax = data.timestamps[data.timestamps.length - 1]; + + // Process each timestamp that has pivot markers + Object.entries(data.pivot_markers).forEach(([timestamp, pivots]) => { + // Process high pivots + if (pivots.highs && pivots.highs.length > 0) { + pivots.highs.forEach(pivot => { + const color = this._getPivotColor(pivot.level, 'high'); + + pivotDots.x.push(timestamp); + pivotDots.y.push(pivot.price); + pivotDots.text.push(`L${pivot.level} High Pivot
Price: ${pivot.price.toFixed(2)}
Strength: ${(pivot.strength * 100).toFixed(0)}%`); + pivotDots.marker.color.push(color); + pivotDots.marker.size.push(this._getPivotMarkerSize(pivot.level)); + pivotDots.marker.symbol.push('triangle-down'); + + if (pivot.is_last) { + shapes.push({ + type: 'line', + x0: xMin, y0: pivot.price, + x1: xMax, y1: pivot.price, + line: { color: color, width: 1, dash: 'dash' }, + layer: 'below' + }); + + annotations.push({ + x: xMax, y: pivot.price, + text: `L${pivot.level}H`, + showarrow: false, + xanchor: 'left', + font: { size: 9, color: color }, + bgcolor: '#1f2937', + borderpad: 2 + }); + } + }); + } + + // Process low pivots + if (pivots.lows && pivots.lows.length > 0) { + pivots.lows.forEach(pivot => { + const color = this._getPivotColor(pivot.level, 'low'); + + pivotDots.x.push(timestamp); + pivotDots.y.push(pivot.price); + pivotDots.text.push(`L${pivot.level} Low Pivot
Price: ${pivot.price.toFixed(2)}
Strength: ${(pivot.strength * 100).toFixed(0)}%`); + pivotDots.marker.color.push(color); + pivotDots.marker.size.push(this._getPivotMarkerSize(pivot.level)); + pivotDots.marker.symbol.push('triangle-up'); + + if (pivot.is_last) { + shapes.push({ + type: 'line', + x0: xMin, y0: pivot.price, + x1: xMax, y1: pivot.price, + line: { color: color, width: 1, dash: 'dash' }, + layer: 'below' + }); + + annotations.push({ + x: xMax, y: pivot.price, + text: `L${pivot.level}L`, + showarrow: false, + xanchor: 'left', + font: { size: 9, color: color }, + bgcolor: '#1f2937', + borderpad: 2 + }); + } + }); + } + }); + } + + // Update chart layout with new pivots + Plotly.relayout(chart.plotId, { + shapes: shapes, + annotations: annotations + }); + + // Update pivot dots trace + if (pivotDots.x.length > 0) { + Plotly.restyle(chart.plotId, { + x: [pivotDots.x], + y: [pivotDots.y], + text: [pivotDots.text], + 'marker.color': [pivotDots.marker.color], + 'marker.size': [pivotDots.marker.size], + 'marker.symbol': [pivotDots.marker.symbol] + }, [2]); // Trace index 2 is pivot dots + } + + console.log(`🎨 Redrawn ${timeframe} chart with updated pivots`); + } + /** * Update a single chart with new data */ diff --git a/ANNOTATE/web/templates/annotation_dashboard.html b/ANNOTATE/web/templates/annotation_dashboard.html index e51704b..42325b8 100644 --- a/ANNOTATE/web/templates/annotation_dashboard.html +++ b/ANNOTATE/web/templates/annotation_dashboard.html @@ -59,6 +59,7 @@ {% block extra_js %}