diff --git a/app/api/trading/check-risk/route.ts b/app/api/trading/check-risk/route.ts index aaadaab..42ec907 100644 --- a/app/api/trading/check-risk/route.ts +++ b/app/api/trading/check-risk/route.ts @@ -13,12 +13,20 @@ import { getLastTradeTime, getTradesInLastHour, getTodayPnL } from '@/lib/databa export interface RiskCheckRequest { symbol: string direction: 'long' | 'short' + // Optional context metrics from TradingView + atr?: number + adx?: number + rsi?: number + volumeRatio?: number + pricePosition?: number } export interface RiskCheckResponse { allowed: boolean reason?: string details?: string + qualityScore?: number + qualityReasons?: string[] } export async function POST(request: NextRequest): Promise> { @@ -135,6 +143,50 @@ export async function POST(request: NextRequest): Promise 0 + + if (hasContextMetrics) { + const qualityScore = scoreSignalQuality({ + atr: body.atr || 0, + adx: body.adx || 0, + rsi: body.rsi || 0, + volumeRatio: body.volumeRatio || 0, + pricePosition: body.pricePosition || 0, + direction: body.direction + }) + + if (!qualityScore.passed) { + console.log('🚫 Risk check BLOCKED: Signal quality too low', { + score: qualityScore.score, + reasons: qualityScore.reasons + }) + + return NextResponse.json({ + allowed: false, + reason: 'Signal quality too low', + details: `Score: ${qualityScore.score}/100 - ${qualityScore.reasons.join(', ')}`, + qualityScore: qualityScore.score, + qualityReasons: qualityScore.reasons + }) + } + + console.log(`āœ… Risk check PASSED: All checks passed`, { + todayPnL: todayPnL.toFixed(2), + tradesLastHour: tradesInLastHour, + cooldownPassed: lastTradeTime ? 'yes' : 'no previous trades', + qualityScore: qualityScore.score, + qualityReasons: qualityScore.reasons + }) + + return NextResponse.json({ + allowed: true, + details: 'All risk checks passed', + qualityScore: qualityScore.score, + qualityReasons: qualityScore.reasons + }) + } + console.log(`āœ… Risk check PASSED: All checks passed`, { todayPnL: todayPnL.toFixed(2), tradesLastHour: tradesInLastHour, @@ -159,3 +211,106 @@ export async function POST(request: NextRequest): Promise 0) { + if (params.atr < 0.6) { + 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 { + score += 10 + reasons.push(`ATR healthy (${params.atr.toFixed(2)}%)`) + } + } + + // ADX check (trend strength: want >18) + if (params.adx > 0) { + if (params.adx > 25) { + score += 15 + reasons.push(`Strong trend (ADX ${params.adx.toFixed(1)})`) + } else if (params.adx < 18) { + score -= 15 + reasons.push(`Weak trend (ADX ${params.adx.toFixed(1)})`) + } else { + score += 5 + reasons.push(`Moderate trend (ADX ${params.adx.toFixed(1)})`) + } + } + + // RSI check (momentum confirmation) + if (params.rsi > 0) { + if (params.direction === 'long') { + if (params.rsi > 50 && params.rsi < 70) { + score += 10 + reasons.push(`RSI supports long (${params.rsi.toFixed(1)})`) + } else if (params.rsi > 70) { + score -= 10 + reasons.push(`RSI overbought (${params.rsi.toFixed(1)})`) + } + } else { // short + if (params.rsi < 50 && params.rsi > 30) { + score += 10 + reasons.push(`RSI supports short (${params.rsi.toFixed(1)})`) + } else if (params.rsi < 30) { + score -= 10 + reasons.push(`RSI oversold (${params.rsi.toFixed(1)})`) + } + } + } + + // Volume check (want > 1.0 = above average) + if (params.volumeRatio > 0) { + if (params.volumeRatio > 1.2) { + score += 10 + reasons.push(`Strong volume (${params.volumeRatio.toFixed(2)}x avg)`) + } else if (params.volumeRatio < 0.8) { + score -= 10 + reasons.push(`Weak volume (${params.volumeRatio.toFixed(2)}x avg)`) + } + } + + // Price position check (avoid chasing) + 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`) + } else { + score += 5 + reasons.push(`Price position OK (${params.pricePosition.toFixed(0)}%)`) + } + } + + const minScore = 60 // Require 60+ to pass + return { + passed: score >= minScore, + score, + reasons + } +} diff --git a/app/api/trading/execute/route.ts b/app/api/trading/execute/route.ts index 9426852..4966f83 100644 --- a/app/api/trading/execute/route.ts +++ b/app/api/trading/execute/route.ts @@ -19,6 +19,12 @@ export interface ExecuteTradeRequest { timeframe: string // e.g., '5' signalStrength?: 'strong' | 'moderate' | 'weak' signalPrice?: number + // Context metrics from TradingView + atr?: number + adx?: number + rsi?: number + volumeRatio?: number + pricePosition?: number } export interface ExecuteTradeResponse { @@ -360,6 +366,12 @@ export async function POST(request: NextRequest): Promise