From 3c9da22a8a3cd122a8021d8aa987d6cd0a83b62c Mon Sep 17 00:00:00 2001 From: mindesbunister Date: Fri, 7 Nov 2025 12:19:41 +0100 Subject: [PATCH] Add ADX > 18 requirement for extreme price positions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Shorts/longs at < 15% range require ADX > 18 AND volume > 1.2x - OR RSI < 35 for shorts, RSI > 60 for longs - Increased penalty from -10 to -15 when conditions not met - Changed threshold from < 5% to < 15% to catch more edge cases Test results: - Big loser (01:35): ADX 16.1, price 9.3% → Score 60 (was 90) → BLOCKED - Today's signal (10:05): ADX 17.3, price 0.9% → Score 55 (was 85) → BLOCKED Rationale: False breakdowns in choppy ranges (ADX < 18) cause losses. Tradeoff: May block some profitable breakdowns, but prevents chop losses. --- lib/trading/signal-quality.ts | 37 +++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/lib/trading/signal-quality.ts b/lib/trading/signal-quality.ts index f790beb..468d999 100644 --- a/lib/trading/signal-quality.ts +++ b/lib/trading/signal-quality.ts @@ -173,24 +173,35 @@ export function scoreSignalQuality(params: { score -= 15 reasons.push(`Price near top of range (${params.pricePosition.toFixed(0)}%) - risky long`) } - } else if (params.direction === 'short' && params.pricePosition < 5) { - // High volume breakdown at range bottom can be good - // Also allow if RSI is bearish (< 40) - breakdowns continue lower - if (params.volumeRatio > 1.2 || (params.rsi > 0 && params.rsi < 40)) { + } else if (params.direction === 'short' && params.pricePosition < 15) { + // Shorts near range bottom (< 15%) require strong confirmation + // Require STRONG trend (ADX > 18) to avoid false breakdowns in choppy ranges + // OR very bearish RSI (< 35) indicating strong momentum continuation + const hasStrongTrend = params.adx > 18 + const isVeryBearish = params.rsi > 0 && params.rsi < 35 + const hasGoodVolume = params.volumeRatio > 1.2 + + if ((hasGoodVolume && hasStrongTrend) || isVeryBearish) { score += 5 - reasons.push(`Valid breakdown at range bottom (${params.pricePosition.toFixed(0)}%, vol ${params.volumeRatio.toFixed(2)}x, RSI ${params.rsi.toFixed(1)})`) + reasons.push(`Valid breakdown at range bottom (${params.pricePosition.toFixed(0)}%, vol ${params.volumeRatio.toFixed(2)}x, ADX ${params.adx.toFixed(1)}, RSI ${params.rsi.toFixed(1)})`) } else { - score -= 10 - reasons.push(`Price near bottom of range (${params.pricePosition.toFixed(0)}%) - reduced penalty for short`) + score -= 15 + reasons.push(`Price near bottom (${params.pricePosition.toFixed(0)}%) - need ADX > 18 or RSI < 35 for breakdown`) } - } else if (params.direction === 'long' && params.pricePosition < 5) { - // Longs at bottom with good volume = potential reversal - if (params.volumeRatio > 1.2 || (params.rsi > 0 && params.rsi > 60)) { + } else if (params.direction === 'long' && params.pricePosition < 15) { + // Longs near range bottom (< 15%) require strong reversal confirmation + // Require STRONG trend (ADX > 18) to avoid catching falling knives + // OR very bullish RSI (> 60) after bounce showing momentum shift + const hasStrongTrend = params.adx > 18 + const isVeryBullish = params.rsi > 0 && params.rsi > 60 + const hasGoodVolume = params.volumeRatio > 1.2 + + if ((hasGoodVolume && hasStrongTrend) || isVeryBullish) { score += 5 - reasons.push(`Potential reversal at bottom (${params.pricePosition.toFixed(0)}%, vol ${params.volumeRatio.toFixed(2)}x, RSI ${params.rsi.toFixed(1)})`) + reasons.push(`Potential reversal at bottom (${params.pricePosition.toFixed(0)}%, vol ${params.volumeRatio.toFixed(2)}x, ADX ${params.adx.toFixed(1)}, RSI ${params.rsi.toFixed(1)})`) } else { - score -= 10 - reasons.push(`Price near bottom (${params.pricePosition.toFixed(0)}%) - reduced penalty for reversal long`) + score -= 15 + reasons.push(`Price near bottom (${params.pricePosition.toFixed(0)}%) - need ADX > 18 or RSI > 60 for reversal`) } } else { score += 5