fix: improve signal quality scoring for volume breakouts
- Lower ATR threshold from 0.6% to 0.15% (allows low volatility breakouts) - Increase volume bonus: +15 for very strong volume (1.5x+), was +10 for 1.2x+ - Add volume breakout logic: High volume (1.4x+) at 95%+ range gets +5 instead of -15 penalty - Add volume compensation: +10 bonus when volume >1.8x and ATR <0.6% - Example: SOL signal with 0.18% ATR, 1.74x volume at 95.6% range now scores 70/100 (PASS) instead of 25/100 (BLOCK) - This signal moved +0.97% and would have hit TP1 (+1.5%) - proves quality scoring was too conservative - Changes apply globally to all symbols (SOL, ETH, BTC) using same scoring algorithm
This commit is contained in:
@@ -235,14 +235,17 @@ function scoreSignalQuality(params: {
|
||||
let score = 50 // Base score
|
||||
const reasons: string[] = []
|
||||
|
||||
// ATR check (volatility gate: 0.6% - 2.5%)
|
||||
// ATR check (volatility gate: 0.15% - 2.5%)
|
||||
if (params.atr > 0) {
|
||||
if (params.atr < 0.6) {
|
||||
if (params.atr < 0.15) {
|
||||
score -= 15
|
||||
reasons.push(`ATR too low (${params.atr.toFixed(2)}% - dead market)`)
|
||||
} else if (params.atr > 2.5) {
|
||||
score -= 20
|
||||
reasons.push(`ATR too high (${params.atr.toFixed(2)}% - too volatile)`)
|
||||
} else if (params.atr >= 0.15 && params.atr < 0.4) {
|
||||
score += 5
|
||||
reasons.push(`ATR moderate (${params.atr.toFixed(2)}%)`)
|
||||
} else {
|
||||
score += 10
|
||||
reasons.push(`ATR healthy (${params.atr.toFixed(2)}%)`)
|
||||
@@ -286,7 +289,10 @@ function scoreSignalQuality(params: {
|
||||
|
||||
// Volume check (want > 1.0 = above average)
|
||||
if (params.volumeRatio > 0) {
|
||||
if (params.volumeRatio > 1.2) {
|
||||
if (params.volumeRatio > 1.5) {
|
||||
score += 15
|
||||
reasons.push(`Very strong volume (${params.volumeRatio.toFixed(2)}x avg)`)
|
||||
} else if (params.volumeRatio > 1.2) {
|
||||
score += 10
|
||||
reasons.push(`Strong volume (${params.volumeRatio.toFixed(2)}x avg)`)
|
||||
} else if (params.volumeRatio < 0.8) {
|
||||
@@ -295,20 +301,38 @@ function scoreSignalQuality(params: {
|
||||
}
|
||||
}
|
||||
|
||||
// Price position check (avoid chasing)
|
||||
// Price position check (avoid chasing vs breakout detection)
|
||||
if (params.pricePosition > 0) {
|
||||
if (params.direction === 'long' && params.pricePosition > 90) {
|
||||
score -= 15
|
||||
reasons.push(`Price near top of range (${params.pricePosition.toFixed(0)}%) - risky long`)
|
||||
} else if (params.direction === 'short' && params.pricePosition < 10) {
|
||||
score -= 15
|
||||
reasons.push(`Price near bottom of range (${params.pricePosition.toFixed(0)}%) - risky short`)
|
||||
if (params.direction === 'long' && params.pricePosition > 95) {
|
||||
// High volume breakout at range top can be good
|
||||
if (params.volumeRatio > 1.4) {
|
||||
score += 5
|
||||
reasons.push(`Volume breakout at range top (${params.pricePosition.toFixed(0)}%, vol ${params.volumeRatio.toFixed(2)}x)`)
|
||||
} else {
|
||||
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
|
||||
if (params.volumeRatio > 1.4) {
|
||||
score += 5
|
||||
reasons.push(`Volume breakdown at range bottom (${params.pricePosition.toFixed(0)}%, vol ${params.volumeRatio.toFixed(2)}x)`)
|
||||
} else {
|
||||
score -= 15
|
||||
reasons.push(`Price near bottom of range (${params.pricePosition.toFixed(0)}%) - risky short`)
|
||||
}
|
||||
} else {
|
||||
score += 5
|
||||
reasons.push(`Price position OK (${params.pricePosition.toFixed(0)}%)`)
|
||||
}
|
||||
}
|
||||
|
||||
// Volume breakout bonus (high volume can override other weaknesses)
|
||||
if (params.volumeRatio > 1.8 && params.atr < 0.6) {
|
||||
score += 10
|
||||
reasons.push(`Volume breakout compensates for low ATR`)
|
||||
}
|
||||
|
||||
const minScore = params.minScore ?? 60 // Use config value or default to 60
|
||||
return {
|
||||
passed: score >= minScore,
|
||||
|
||||
Reference in New Issue
Block a user