From af7926862152d07c20414052743debb105d762ff Mon Sep 17 00:00:00 2001 From: DiTus Date: Sun, 1 Mar 2026 22:16:12 +0100 Subject: [PATCH] simplified crossover detection: find first candle where price crosses MA --- .../static/js/ui/signals-calculator.js | 60 +++++++++---------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/src/api/dashboard/static/js/ui/signals-calculator.js b/src/api/dashboard/static/js/ui/signals-calculator.js index 9d58af2..30c41d1 100644 --- a/src/api/dashboard/static/js/ui/signals-calculator.js +++ b/src/api/dashboard/static/js/ui/signals-calculator.js @@ -94,9 +94,6 @@ export function calculateSummarySignal(signals) { 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]; @@ -107,46 +104,43 @@ function calculateHistoricalCrossovers(activeIndicators, candles) { if (!results || results.length === 0) return; - // Track the last crossover timestamp - let lastCrossoverTimestamp = indicator.lastSignalTimestamp || null; - let crossoverCount = 0; + // Find the most recent crossover by going backwards from the newest candle + // candles are sorted oldest first, newest last + let lastCrossoverTimestamp = null; - // 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; + for (let i = candles.length - 1; i > 0; i--) { + const candle = candles[i]; // newer candle + const prevCandle = candles[i-1]; // older candle - const candle = candles[i]; - const prevCandle = candles[i + 1]; + const result = results[i]; + const prevResult = results[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] }; + if (!result || !prevResult) continue; - const closeThis = candles[i].close; - const closePrev = candles[i + 1].close; - const maThis = valuesThis.ma; - const maPrev = valuesPrev.ma; + // Get MA value (handle both object and number formats) + const ma = result.ma !== undefined ? result.ma : result; + const prevMa = prevResult.ma !== undefined ? prevResult.ma : prevResult; - // 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: ${prevCandle.time}`); - lastCrossoverTimestamp = prevCandle.time; - crossoverCount++; - break; // Found most recent crossover + if (ma === undefined || prevMa === undefined) continue; + + // Check crossover: price was on one side of MA, now on the other side + const priceAbovePrev = prevCandle.close > prevMa; + const priceAboveNow = candle.close > ma; + + // SELL signal: price crossed from above to below MA + if (priceAbovePrev && !priceAboveNow) { + lastCrossoverTimestamp = candle.time; + break; } - // 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: ${prevCandle.time}`); - lastCrossoverTimestamp = prevCandle.time; - crossoverCount++; - break; // Found most recent crossover + // BUY signal: price crossed from below to above MA + if (!priceAbovePrev && priceAboveNow) { + lastCrossoverTimestamp = candle.time; + break; } } - if (crossoverCount > 0) { + if (lastCrossoverTimestamp) { console.log(`[HistoricalCross] ${indicatorType}: Found crossover at ${new Date(lastCrossoverTimestamp * 1000).toLocaleString()}`); - // Update the indicator's lastSignalTimestamp indicator.lastSignalTimestamp = lastCrossoverTimestamp; } });