Add ADX > 18 requirement for extreme price positions

- 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.
This commit is contained in:
mindesbunister
2025-11-07 12:19:41 +01:00
parent db907d8074
commit 3c9da22a8a

View File

@@ -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