feat: Direction-specific quality thresholds (long=90, short=95)

- DATA-DRIVEN: 227 trades analysis showed longs 71.4% WR vs shorts 28.6% WR at quality 90-94
- LONG threshold: 90 (captures profitable 90-94 signals: +4.77 total, +.40 avg)
- SHORT threshold: 95 (blocks toxic 90-94 signals: -53.76 total, -9.11 avg)
- Historical validation: Quality 90+ longs +00.62 vs shorts -77.90

Modified files:
- config/trading.ts: Added minSignalQualityScoreLong/Short fields + getMinQualityScoreForDirection()
- lib/trading/signal-quality.ts: Accept direction-specific minScore parameter
- app/api/trading/check-risk/route.ts: Use direction-specific thresholds
- .env: Added MIN_SIGNAL_QUALITY_SCORE_LONG=90 and _SHORT=95

Fallback logic: direction-specific → global → 60 default
Backward compatible with existing code
This commit is contained in:
mindesbunister
2025-11-23 15:01:56 +01:00
parent 625566224a
commit 01aaa0932a
5 changed files with 111 additions and 9 deletions

View File

@@ -6,7 +6,7 @@
*/
import { NextRequest, NextResponse } from 'next/server'
import { getMergedConfig, TradingConfig } from '@/config/trading'
import { getMergedConfig, TradingConfig, getMinQualityScoreForDirection } from '@/config/trading'
import { getInitializedPositionManager, ActiveTrade } from '@/lib/trading/position-manager'
import { getLastTradeTime, getLastTradeTimeForSymbol, getTradesInLastHour, getTodayPnL, createBlockedSignal } from '@/lib/database/trades'
import { getPythPriceMonitor } from '@/lib/pyth/price-monitor'
@@ -329,6 +329,9 @@ export async function POST(request: NextRequest): Promise<NextResponse<RiskCheck
const latestPrice = priceMonitor.getCachedPrice(body.symbol)
const currentPrice = latestPrice?.price || body.currentPrice
// Use direction-specific quality threshold (Nov 23, 2025)
const minQualityScore = getMinQualityScoreForDirection(body.direction, config)
const qualityScore = await scoreSignalQuality({
atr: body.atr || 0,
adx: body.adx || 0,
@@ -339,13 +342,14 @@ export async function POST(request: NextRequest): Promise<NextResponse<RiskCheck
symbol: body.symbol,
currentPrice: currentPrice,
timeframe: body.timeframe, // Pass timeframe for context-aware scoring
minScore: config.minSignalQualityScore // Use config value
minScore: minQualityScore // Use direction-specific threshold
})
if (!qualityScore.passed) {
console.log('🚫 Risk check BLOCKED: Signal quality too low', {
score: qualityScore.score,
threshold: config.minSignalQualityScore,
direction: body.direction,
threshold: minQualityScore,
reasons: qualityScore.reasons
})
@@ -367,7 +371,7 @@ export async function POST(request: NextRequest): Promise<NextResponse<RiskCheck
signalQualityScore: qualityScore.score,
signalQualityVersion: 'v4', // Update this when scoring logic changes
scoreBreakdown: { reasons: qualityScore.reasons },
minScoreRequired: config.minSignalQualityScore,
minScoreRequired: minQualityScore, // Use direction-specific threshold
blockReason: 'QUALITY_SCORE_TOO_LOW',
blockDetails: `Score: ${qualityScore.score}/${config.minSignalQualityScore} - ${qualityScore.reasons.join(', ')}`,
})