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:
@@ -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(', ')}`,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user