diff --git a/src/api/dashboard/static/js/ui/indicators-panel-new.js b/src/api/dashboard/static/js/ui/indicators-panel-new.js index 5efb68c..469bb0b 100644 --- a/src/api/dashboard/static/js/ui/indicators-panel-new.js +++ b/src/api/dashboard/static/js/ui/indicators-panel-new.js @@ -813,59 +813,31 @@ function renderIndicatorOnPane(indicator, meta, instance, candles, paneIndex, li }); } -// Update existing indicator series with new data (for real-time updates) +// Completely redraw indicators (works for both overlay and pane) export function updateIndicatorCandles() { - if (!window.dashboard || !window.dashboard.chart) return; + console.log('[UpdateIndicators] Removing and recreating all indicator series'); + // Remove all existing series const activeIndicators = getActiveIndicators(); - const currentInterval = window.dashboard.currentInterval; - const candles = window.dashboard?.allData?.get(currentInterval); - - if (!candles || candles.length === 0) return; - activeIndicators.forEach(indicator => { - if (!indicator.visible || indicator.series.length === 0) return; - - const IndicatorClass = IndicatorRegistry[indicator.type]; - if (!IndicatorClass) return; - - const instance = new IndicatorClass(indicator); - const results = instance.calculate(candles); - - if (!results || results.length === 0) return; - - const meta = instance.getMetadata(); - - // Update each plot series - meta.plots.forEach((plot, plotIdx) => { - const series = indicator.series[plotIdx]; - if (!series) return; - - const plotColor = indicator.params[`_color_${plotIdx}`] || plot.color || '#2962ff'; - const lineWidth = indicator.params._lineWidth || 2; - - // Build complete data array - const data = []; - - for (let i = 0; i < candles.length; i++) { - const value = results[i]?.[plot.id]; - if (value !== null && value !== undefined) { - data.push({ - time: candles[i].time, - value: value, - color: plotColor, - lineWidth: lineWidth - }); - } - } - - if (data.length > 0) { - series.setData(data); + indicator.series?.forEach(s => { + try { + window.dashboard.chart.removeSeries(s); + } catch(e) { + console.warn('[UpdateIndicators] Error removing series:', e); } }); + indicator.series = []; }); - console.log(`[UpdateIndicators] Updated ${activeIndicators.length} indicator series`); + // Clear pane mappings + indicatorPanes.clear(); + nextPaneIndex = 1; + + // Now call drawIndicatorsOnChart to recreate everything + drawIndicatorsOnChart(); + + console.log(`[UpdateIndicators] Recreated ${activeIndicators.length} indicators`); } // Chart drawing diff --git a/src/api/dashboard/static/js/ui/signals-calculator.js b/src/api/dashboard/static/js/ui/signals-calculator.js index fa75a33..0a3de5b 100644 --- a/src/api/dashboard/static/js/ui/signals-calculator.js +++ b/src/api/dashboard/static/js/ui/signals-calculator.js @@ -87,6 +87,71 @@ export function calculateSummarySignal(signals) { return result; } +/** + * Calculate historical crossovers for all indicators based on full candle history + * Finds the last time each indicator crossed from BUY to SELL or SELL to BUY + */ +function calculateHistoricalCrossovers(activeIndicators, candles) { + activeIndicators.forEach(indicator => { + const indicatorType = indicator.type || indicator.indicatorType; + const SignalFunction = getSignalFunction(indicatorType); + + if (!SignalFunction) return; + + // Recalculate indicator values for all candles + const IndicatorClass = IndicatorRegistry[indicatorType]; + if (!IndicatorClass) return; + + const instance = new IndicatorClass(indicator); + const results = instance.calculate(candles); + + if (!results || results.length === 0) return; + + // Track the last crossover timestamp + let lastCrossoverTimestamp = indicator.lastSignalTimestamp || null; + let crossoverCount = 0; + + // Iterate through candles to find crossovers (from newest to oldest) + // We start from the end and go backwards to find the most recent crossover + for (let i = candles.length - 2; i >= 0; i--) { + // Skip if we don't have data for these candles + if (!results[i] || !results[i + 1]) continue; + + const candle = candles[i]; + const prevCandle = candles[i + 1]; + + const valuesThis = typeof results[i] === 'object' ? results[i] : { ma: results[i] }; + const valuesPrev = typeof results[i + 1] === 'object' ? results[i + 1] : { ma: results[i + 1] }; + + const closeThis = candles[i].close; + const closePrev = candles[i + 1].close; + const maThis = valuesThis.ma; + const maPrev = valuesPrev.ma; + + // Check for BUY→SELL crossover (was above, now below) + if (closePrev > maPrev && closeThis < maThis) { + console.log(`[HistoricalCross] ${indicatorType} BUY→SELL crossover at candle ${i}, time: ${candle.time}`); + lastCrossoverTimestamp = candle.time; + crossoverCount++; + break; // Found most recent crossover + } + // Check for SELL→BUY crossover (was below, now above) + else if (closePrev < maPrev && closeThis > maThis) { + console.log(`[HistoricalCross] ${indicatorType} SELL→BUY crossover at candle ${i}, time: ${candle.time}`); + lastCrossoverTimestamp = candle.time; + crossoverCount++; + break; // Found most recent crossover + } + } + + if (crossoverCount > 0) { + console.log(`[HistoricalCross] ${indicatorType}: Found crossover at ${new Date(lastCrossoverTimestamp * 1000).toLocaleString()}`); + // Update the indicator's lastSignalTimestamp + indicator.lastSignalTimestamp = lastCrossoverTimestamp; + } + }); +} + /** * Calculate signals for all active indicators * @returns {Array} Array of indicator signals @@ -110,6 +175,9 @@ export function calculateAllIndicatorSignals() { const signals = []; + // Calculate crossovers for all indicators based on historical data + calculateHistoricalCrossovers(activeIndicators, candles); + for (const indicator of activeIndicators) { const IndicatorClass = IndicatorRegistry[indicator.type]; if (!IndicatorClass) {