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