diff --git a/app/api/trading/check-risk/route.ts b/app/api/trading/check-risk/route.ts index 0c3d85d..aaadaab 100644 --- a/app/api/trading/check-risk/route.ts +++ b/app/api/trading/check-risk/route.ts @@ -8,6 +8,7 @@ import { NextRequest, NextResponse } from 'next/server' import { getMergedConfig } from '@/config/trading' import { getInitializedPositionManager } from '@/lib/trading/position-manager' +import { getLastTradeTime, getTradesInLastHour, getTodayPnL } from '@/lib/database/trades' export interface RiskCheckRequest { symbol: string @@ -79,13 +80,66 @@ export async function POST(request: NextRequest): Promise= config.maxTradesPerHour) { + console.log('🚫 Risk check BLOCKED: Hourly trade limit reached', { + tradesInLastHour, + maxTradesPerHour: config.maxTradesPerHour, + }) + + return NextResponse.json({ + allowed: false, + reason: 'Hourly trade limit', + details: `Already placed ${tradesInLastHour} trades in the last hour (max: ${config.maxTradesPerHour})`, + }) + } + + // 3. Check cooldown period + const lastTradeTime = await getLastTradeTime() + if (lastTradeTime && config.minTimeBetweenTrades > 0) { + const timeSinceLastTrade = Date.now() - lastTradeTime.getTime() + const cooldownMs = config.minTimeBetweenTrades * 60 * 1000 // Convert minutes to milliseconds + + if (timeSinceLastTrade < cooldownMs) { + const remainingMs = cooldownMs - timeSinceLastTrade + const remainingMinutes = Math.ceil(remainingMs / 60000) + + console.log('🚫 Risk check BLOCKED: Cooldown period active', { + lastTradeTime: lastTradeTime.toISOString(), + timeSinceLastTradeMs: timeSinceLastTrade, + cooldownMs, + remainingMinutes, + }) + + return NextResponse.json({ + allowed: false, + reason: 'Cooldown period', + details: `Must wait ${remainingMinutes} more minute(s) before next trade (cooldown: ${config.minTimeBetweenTrades} min)`, + }) + } + } + + console.log(`✅ Risk check PASSED: All checks passed`, { + todayPnL: todayPnL.toFixed(2), + tradesLastHour: tradesInLastHour, + cooldownPassed: lastTradeTime ? 'yes' : 'no previous trades', + }) return NextResponse.json({ allowed: true, diff --git a/lib/database/trades.ts b/lib/database/trades.ts index 2ef5416..e06184f 100644 --- a/lib/database/trades.ts +++ b/lib/database/trades.ts @@ -251,6 +251,78 @@ export async function getOpenTrades() { } } +/** + * Get the most recent trade entry time (for cooldown checking) + */ +export async function getLastTradeTime(): Promise { + const prisma = getPrismaClient() + + try { + const lastTrade = await prisma.trade.findFirst({ + orderBy: { entryTime: 'desc' }, + select: { entryTime: true }, + }) + + return lastTrade?.entryTime || null + } catch (error) { + console.error('❌ Failed to get last trade time:', error) + return null + } +} + +/** + * Get count of trades in the last hour + */ +export async function getTradesInLastHour(): Promise { + const prisma = getPrismaClient() + + try { + const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000) + + const count = await prisma.trade.count({ + where: { + entryTime: { + gte: oneHourAgo, + }, + }, + }) + + return count + } catch (error) { + console.error('❌ Failed to get trades in last hour:', error) + return 0 + } +} + +/** + * Get total P&L for today + */ +export async function getTodayPnL(): Promise { + const prisma = getPrismaClient() + + try { + const startOfDay = new Date() + startOfDay.setHours(0, 0, 0, 0) + + const result = await prisma.trade.aggregate({ + where: { + entryTime: { + gte: startOfDay, + }, + status: 'closed', + }, + _sum: { + realizedPnL: true, + }, + }) + + return result._sum.realizedPnL || 0 + } catch (error) { + console.error('❌ Failed to get today PnL:', error) + return 0 + } +} + /** * Add price update for a trade (for tracking max gain/drawdown) */