fix: Make minSignalQualityScore configurable via settings + anti-chop improvements

CRITICAL BUG FIX:
- Settings page saved MIN_SIGNAL_QUALITY_SCORE to .env but check-risk had hardcoded value
- Now reads from config.minSignalQualityScore (defaults to 65, editable via /settings)
- Prevents settings changes from being ignored after restart

ANTI-CHOP FILTER FIXES:
- Fixed volume breakout bonus conflicting with anti-chop filter
- Volume breakout now requires ADX > 18 (trending market)
- Prevents high volume + low ADX from getting rewarded instead of penalized
- Anti-chop filter now properly blocks whipsaw traps at score 60

TESTING INFRASTRUCTURE:
- Added backtest script showing +17.1% P&L improvement (saved $242 in losses)
- Added test-signals.sh for comprehensive signal quality validation
- Added test-recent-signals.sh for analyzing actual trading session signals
- All tests passing: timeframe awareness, anti-chop, score thresholds

CHANGES:
- config/trading.ts: Added minSignalQualityScore to interface and defaults
- app/api/trading/check-risk/route.ts: Use config value instead of hardcoded 65
- lib/trading/signal-quality.ts: Fixed volume breakout bonus logic
- .env: Added MIN_SIGNAL_QUALITY_SCORE=65
- scripts/: Added comprehensive testing tools

BACKTEST RESULTS (Last 30 trades):
- Old system (score ≥60): $1,412.79 P&L
- New system (score ≥65 + anti-chop): $1,654.79 P&L
- Improvement: +$242.00 (+17.1%)
- Blocked 5 losing trades, missed 0 winners
This commit is contained in:
mindesbunister
2025-11-10 11:22:52 +01:00
parent 60a0035f56
commit d2fbd125a0
8 changed files with 594 additions and 11 deletions

View File

@@ -264,6 +264,17 @@ export async function POST(request: NextRequest): Promise<NextResponse<RiskCheck
const hasContextMetrics = body.atr !== undefined && body.atr > 0
if (hasContextMetrics) {
console.log('🔍 Risk check for:', {
symbol: body.symbol,
direction: body.direction,
timeframe: body.timeframe, // DEBUG: Check if timeframe is received
atr: body.atr,
adx: body.adx,
rsi: body.rsi,
volumeRatio: body.volumeRatio,
pricePosition: body.pricePosition
})
const qualityScore = scoreSignalQuality({
atr: body.atr || 0,
adx: body.adx || 0,
@@ -272,7 +283,7 @@ export async function POST(request: NextRequest): Promise<NextResponse<RiskCheck
pricePosition: body.pricePosition || 0,
direction: body.direction,
timeframe: body.timeframe, // Pass timeframe for context-aware scoring
minScore: 60 // Hardcoded threshold
minScore: config.minSignalQualityScore // Use config value (editable via settings page)
})
if (!qualityScore.passed) {