diff --git a/app/api/automation/analysis-details/route.js b/app/api/automation/analysis-details/route.js index adf6fe1..e69de29 100644 --- a/app/api/automation/analysis-details/route.js +++ b/app/api/automation/analysis-details/route.js @@ -1,313 +0,0 @@ -import { NextResponse } from 'next/server' -import { PrismaClient } from '@prisma/client' - -const prisma = new PrismaClient() - -export async function GET() { - try { - console.log('✅ API CORRECTED: Loading with fixed trade calculations...') - - const sessions = await prisma.automation_sessions.findMany({ - where: { - userId: 'default-user', - symbol: 'SOLUSD' - }, - orderBy: { createdAt: 'desc' }, - take: 10 - }) - - if (sessions.length === 0) { - return NextResponse.json({ - success: false, - message: 'No automation sessions found' - }) - } - - const latestSession = sessions[0] - - const sessionsByTimeframe = {} - sessions.forEach(session => { - if (!sessionsByTimeframe[session.timeframe]) { - sessionsByTimeframe[session.timeframe] = session - } - }) - - const recentTrades = await prisma.trades.findMany({ - where: { - userId: latestSession.userId, - symbol: latestSession.symbol - }, - orderBy: { createdAt: 'desc' }, - take: 10 - }) - - const completedTrades = recentTrades.filter(t => t.status === 'COMPLETED') - const successfulTrades = completedTrades.filter(t => (t.profit || 0) > 0) - const totalPnL = completedTrades.reduce((sum, trade) => sum + (trade.profit || 0), 0) - const winRate = completedTrades.length > 0 ? (successfulTrades.length / completedTrades.length * 100) : 0 - - // 🔥 GET REAL CURRENT PRICE - SYNCHRONIZED WITH PRICE MONITOR - let currentPrice = 193.54 // Fallback price - try { - // First try to get price from price-monitor endpoint (most recent and consistent) - const priceMonitorResponse = await fetch('http://localhost:3000/api/price-monitor') - if (priceMonitorResponse.ok) { - const priceMonitorData = await priceMonitorResponse.json() - if (priceMonitorData.success && priceMonitorData.data.prices.SOLUSD) { - currentPrice = priceMonitorData.data.prices.SOLUSD - console.log('📊 Using synchronized price from price monitor:', currentPrice) - } else { - throw new Error('Price monitor data not available') - } - } else { - throw new Error('Price monitor API not responding') - } - } catch (error) { - console.warn('⚠️ Price monitor unavailable, fetching directly from Binance:', error.message) - try { - // Fallback to direct Binance API call - const priceResponse = await fetch('https://api.binance.com/api/v3/ticker/price?symbol=SOLUSDT') - if (priceResponse.ok) { - const priceData = await priceResponse.json() - currentPrice = parseFloat(priceData.price) - console.log('📊 Using backup price from Binance:', currentPrice) - } - } catch (backupError) { - console.error('⚠️ Both price sources failed, using fallback:', backupError) - } - } - - const formattedTrades = recentTrades.map(trade => { - const priceChange = trade.side === 'BUY' ? - (currentPrice - trade.price) : - (trade.price - currentPrice) - - // 🔥 FIX: Calculate P&L based on ACTUAL investment amount, not position size - // Get the actual trading amount from the trade or session settings - const actualTradingAmount = trade.tradingAmount || latestSession.settings?.tradingAmount || 100 - const storedPositionValue = trade.amount * trade.price // What was actually bought - - // Calculate proportional P&L based on actual investment - const realizedPnL = trade.status === 'COMPLETED' ? (trade.profit || 0) : null - const unrealizedPnL = trade.status === 'OPEN' ? - (priceChange * trade.amount * (actualTradingAmount / storedPositionValue)) : null - -// console.log(`💰 P&L Calculation for trade ${trade.id}:`, { -// actualTradingAmount, -// storedPositionValue: storedPositionValue.toFixed(2), -// priceChange: priceChange.toFixed(2), -// rawPnL: (priceChange * trade.amount).toFixed(2), -// adjustedPnL: unrealizedPnL?.toFixed(2), -// adjustment_ratio: (actualTradingAmount / storedPositionValue).toFixed(4) -// }) - - const entryTime = new Date(trade.createdAt) - const exitTime = trade.closedAt ? new Date(trade.closedAt) : null - const currentTime = new Date() - - const durationMs = trade.status === 'COMPLETED' ? - (exitTime ? exitTime.getTime() - entryTime.getTime() : 0) : - (currentTime.getTime() - entryTime.getTime()) - - const durationMinutes = Math.floor(durationMs / (1000 * 60)) - const formatDuration = (minutes) => { - if (minutes < 60) return `${minutes}m` - const hours = Math.floor(minutes / 60) - const mins = minutes % 60 - return mins > 0 ? `${hours}h ${mins}m` : `${hours}h` - } - - // ✅ CORRECTED CALCULATION: Show actual investment amounts - const leverage = trade.leverage || 1 - const displayPositionSize = actualTradingAmount.toFixed(2) - - // Mark old trades with wrong data - const isOldWrongTrade = trade.price < 150 && trade.amount > 1.5 // Detect old wrong trades - - // Enhanced entry/exit price handling - const entryPrice = trade.entryPrice || trade.price - let exitPrice = trade.exitPrice - let calculatedProfit = trade.profit - - // If exit price is null but trade is completed, try to calculate from profit - if (trade.status === 'COMPLETED' && !exitPrice && calculatedProfit !== null && calculatedProfit !== undefined) { - // Calculate exit price from profit: profit = (exitPrice - entryPrice) * amount - if (trade.side === 'BUY') { - exitPrice = entryPrice + (calculatedProfit / trade.amount) - } else { - exitPrice = entryPrice - (calculatedProfit / trade.amount) - } - } - - // If profit is null but we have both prices, calculate profit - if (trade.status === 'COMPLETED' && (calculatedProfit === null || calculatedProfit === undefined) && exitPrice && entryPrice) { - if (trade.side === 'BUY') { - calculatedProfit = (exitPrice - entryPrice) * trade.amount - } else { - calculatedProfit = (entryPrice - exitPrice) * trade.amount - } - } - - // Determine result based on actual profit - use profit field as fallback - let result = 'ACTIVE' - if (trade.status === 'COMPLETED') { - // First try to use the stored profit field - const storedProfit = trade.profit || 0 - - if (calculatedProfit !== null && calculatedProfit !== undefined) { - // Use calculated profit if available - if (Math.abs(calculatedProfit) < 0.01) { - result = 'BREAKEVEN' - } else if (calculatedProfit > 0) { - result = 'WIN' - } else { - result = 'LOSS' - } - } else if (storedProfit !== null) { - // Fallback to stored profit field - if (Math.abs(storedProfit) < 0.01) { - result = 'BREAKEVEN' - } else if (storedProfit > 0) { - result = 'WIN' - } else { - result = 'LOSS' - } - } else { - result = 'UNKNOWN' // When we truly don't have any profit data - } - } - - return { - id: trade.id, - type: 'MARKET', - side: trade.side, - amount: trade.amount, // Keep original SOL amount for reference - tradingAmount: actualTradingAmount, // Show actual investment amount - realTradingAmount: actualTradingAmount, // Show real trading amount - leverage: leverage, - positionSize: displayPositionSize, - price: trade.price, - status: trade.status, - pnl: realizedPnL ? realizedPnL.toFixed(2) : (unrealizedPnL ? unrealizedPnL.toFixed(2) : '0.00'), - pnlPercent: realizedPnL ? `${((realizedPnL / actualTradingAmount) * 100).toFixed(2)}%` : - (unrealizedPnL ? `${((unrealizedPnL / actualTradingAmount) * 100).toFixed(2)}%` : '0.00%'), - createdAt: trade.createdAt, - entryTime: trade.createdAt, - exitTime: trade.closedAt, - actualDuration: durationMs, - durationText: formatDuration(durationMinutes) + (trade.status === 'OPEN' ? ' (Active)' : ''), - reason: `REAL: ${trade.side} signal with ${trade.confidence || 75}% confidence`, - entryPrice: entryPrice, - exitPrice: exitPrice, - currentPrice: trade.status === 'OPEN' ? currentPrice : null, - unrealizedPnl: unrealizedPnL ? unrealizedPnL.toFixed(2) : null, - realizedPnl: realizedPnL ? realizedPnL.toFixed(2) : null, - calculatedProfit: calculatedProfit, - stopLoss: trade.stopLoss || (trade.side === 'BUY' ? (trade.price * 0.98).toFixed(2) : (trade.price * 1.02).toFixed(2)), - takeProfit: trade.takeProfit || (trade.side === 'BUY' ? (trade.price * 1.04).toFixed(2) : (trade.price * 0.96).toFixed(2)), - isActive: trade.status === 'OPEN' || trade.status === 'PENDING', - confidence: trade.confidence || 75, - result: result, - resultDescription: trade.status === 'COMPLETED' ? - `REAL: ${result === 'WIN' ? 'Profitable' : result === 'LOSS' ? 'Loss' : result} ${trade.side} trade - Completed` : - `REAL: ${trade.side} position active - ${formatDuration(durationMinutes)}`, - isOldWrongTrade: isOldWrongTrade, - correctedAmount: isOldWrongTrade ? (actualTradingAmount / currentPrice).toFixed(4) : null, - originalStoredPrice: trade.price, - tradingMode: trade.tradingMode || latestSession.mode, // 🔥 USE ACTUAL TRADING MODE FROM DATABASE - driftTxId: trade.driftTxId, // Jupiter DEX transaction ID - fees: trade.fees || 0, // Trading fees - actualInvestment: actualTradingAmount, // Show the real investment amount - positionAdjustment: `${actualTradingAmount}/${storedPositionValue.toFixed(2)}` - } - }) - - return NextResponse.json({ - success: true, - data: { - session: { - id: latestSession.id, - symbol: latestSession.symbol, - timeframe: latestSession.timeframe, - status: latestSession.status, - mode: latestSession.mode, - createdAt: latestSession.createdAt, - lastAnalysisAt: latestSession.lastAnalysis || new Date().toISOString(), - totalTrades: completedTrades.length, - successfulTrades: successfulTrades.length, - errorCount: latestSession.errorCount, - totalPnL: totalPnL - }, - multiTimeframeSessions: sessionsByTimeframe, - analysis: { - decision: "HOLD", - confidence: 84, - summary: `🔥 REAL DATABASE: ${completedTrades.length} trades, ${successfulTrades.length} wins (${winRate.toFixed(1)}% win rate), P&L: $${totalPnL.toFixed(2)}`, - sentiment: "NEUTRAL", - testField: "CORRECTED_CALCULATIONS", - analysisContext: { - currentSignal: "HOLD", - explanation: `🎯 REAL DATA: ${recentTrades.length} database trades shown with corrected calculations` - }, - timeframeAnalysis: { - "15m": { decision: "HOLD", confidence: 75 }, - "1h": { decision: "HOLD", confidence: 70 }, - "2h": { decision: "HOLD", confidence: 70 }, - "4h": { decision: "HOLD", confidence: 70 } - }, - multiTimeframeResults: [ - { - timeframe: "1h", - status: "ACTIVE", - decision: "BUY", - confidence: 85, - sentiment: "BULLISH", - analysisComplete: true - }, - { - timeframe: "2h", - status: "ACTIVE", - decision: "BUY", - confidence: 78, - sentiment: "BULLISH", - analysisComplete: true - }, - { - timeframe: "4h", - status: "ACTIVE", - decision: "BUY", - confidence: 82, - sentiment: "BULLISH", - analysisComplete: true - } - ], - layoutsAnalyzed: ["AI Layout", "DIY Layout"], - entry: { - price: currentPrice, - buffer: "±0.25", - rationale: "Current market level" - }, - stopLoss: { - price: 174.5, - rationale: "Technical support level" - }, - takeProfits: { - tp1: { price: 176.5, description: "First target" }, - tp2: { price: 177.5, description: "Extended target" } - }, - reasoning: `✅ CORRECTED DATA: ${completedTrades.length} completed trades, ${winRate.toFixed(1)}% win rate, $${totalPnL.toFixed(2)} P&L`, - timestamp: new Date().toISOString(), - processingTime: "~2.5 minutes" - }, - recentTrades: formattedTrades - } - }) - } catch (error) { - console.error('Error fetching analysis details:', error) - return NextResponse.json({ - success: false, - error: 'Failed to fetch analysis details', - details: error.message - }, { status: 500 }) - } -} diff --git a/app/api/automation/place-risk-management/route.js b/app/api/automation/place-risk-management/route.js new file mode 100644 index 0000000..f7f7f05 --- /dev/null +++ b/app/api/automation/place-risk-management/route.js @@ -0,0 +1,153 @@ +import { NextResponse } from 'next/server'; + +export async function POST(request) { + try { + const body = await request.json(); + const { symbol, action } = body; + + console.log('🛡️ Risk Management Request:', { symbol, action }); + + // Get current position first + const positionResponse = await fetch(`${process.env.INTERNAL_API_URL || 'http://localhost:9001'}/api/automation/position-monitor`); + const positionData = await positionResponse.json(); + + if (!positionData.success || !positionData.monitor.hasPosition) { + return NextResponse.json({ + success: false, + error: 'No active position found' + }); + } + + const position = positionData.monitor.position; + console.log('📊 Current position:', position); + + // Calculate proper stop-loss and take-profit levels + const entryPrice = position.entryPrice; + const currentPrice = position.currentPrice; + const size = position.size; + const side = position.side; // 'short' or 'long' + + let stopLossPrice, takeProfitPrice; + + if (side.toLowerCase() === 'short') { + // For SHORT positions: + // Stop-loss: BUY above entry price (limit losses) + // Take-profit: BUY below current price (secure profits) + stopLossPrice = entryPrice * 1.025; // 2.5% above entry + takeProfitPrice = currentPrice * 0.985; // 1.5% below current (secure profits) + } else { + // For LONG positions: + // Stop-loss: SELL below entry price (limit losses) + // Take-profit: SELL above current price (secure profits) + stopLossPrice = entryPrice * 0.975; // 2.5% below entry + takeProfitPrice = currentPrice * 1.015; // 1.5% above current + } + + const orders = []; + + // Place stop-loss order + try { + const stopLossOrder = { + symbol: symbol, + side: side.toLowerCase() === 'short' ? 'BUY' : 'SELL', + amount: size, + orderType: 'TRIGGER_LIMIT', + triggerPrice: stopLossPrice, + limitPrice: side.toLowerCase() === 'short' ? stopLossPrice * 1.002 : stopLossPrice * 0.998, + reduceOnly: true + }; + + console.log('🛑 Placing stop-loss order:', stopLossOrder); + + const slResponse = await fetch(`${process.env.INTERNAL_API_URL || 'http://localhost:9001'}/api/drift/place-order`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(stopLossOrder) + }); + + const slResult = await slResponse.json(); + orders.push({ + type: 'stop-loss', + success: slResult.success, + price: stopLossPrice, + orderId: slResult.orderId, + error: slResult.error + }); + + } catch (slError) { + orders.push({ + type: 'stop-loss', + success: false, + error: slError.message + }); + } + + // Place take-profit order + try { + const takeProfitOrder = { + symbol: symbol, + side: side.toLowerCase() === 'short' ? 'BUY' : 'SELL', + amount: size, + orderType: 'TRIGGER_LIMIT', + triggerPrice: takeProfitPrice, + limitPrice: side.toLowerCase() === 'short' ? takeProfitPrice * 0.998 : takeProfitPrice * 1.002, + reduceOnly: true + }; + + console.log('🎯 Placing take-profit order:', takeProfitOrder); + + const tpResponse = await fetch(`${process.env.INTERNAL_API_URL || 'http://localhost:9001'}/api/drift/place-order`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(takeProfitOrder) + }); + + const tpResult = await tpResponse.json(); + orders.push({ + type: 'take-profit', + success: tpResult.success, + price: takeProfitPrice, + orderId: tpResult.orderId, + error: tpResult.error + }); + + } catch (tpError) { + orders.push({ + type: 'take-profit', + success: false, + error: tpError.message + }); + } + + const successfulOrders = orders.filter(o => o.success); + const failedOrders = orders.filter(o => !o.success); + + return NextResponse.json({ + success: successfulOrders.length > 0, + message: `Risk management: ${successfulOrders.length} orders placed, ${failedOrders.length} failed`, + position: { + symbol: position.symbol, + side: position.side, + size: position.size, + entryPrice: position.entryPrice, + currentPrice: position.currentPrice, + unrealizedPnl: position.unrealizedPnl + }, + orders: orders, + riskManagement: { + stopLossPrice: stopLossPrice.toFixed(4), + takeProfitPrice: takeProfitPrice.toFixed(4), + riskPercent: side.toLowerCase() === 'short' ? '+2.5%' : '-2.5%', + rewardPercent: side.toLowerCase() === 'short' ? '-1.5%' : '+1.5%' + } + }); + + } catch (error) { + console.error('❌ Risk management error:', error); + return NextResponse.json({ + success: false, + error: 'Failed to place risk management orders', + details: error.message + }, { status: 500 }); + } +} diff --git a/prisma/prisma/dev.db b/prisma/prisma/dev.db index c9cc381..121023d 100644 Binary files a/prisma/prisma/dev.db and b/prisma/prisma/dev.db differ diff --git a/sync-successful-trade.js b/sync-successful-trade.js new file mode 100644 index 0000000..52b22ad --- /dev/null +++ b/sync-successful-trade.js @@ -0,0 +1,121 @@ +// Sync successful Drift trades to AI learning system + +const { PrismaClient } = require('@prisma/client'); +const prisma = new PrismaClient(); + +async function syncSuccessfulTrade() { + try { + console.log('🔄 Syncing successful trade to AI learning system...'); + + // Get the successful trade from Drift position history + const response = await fetch('http://localhost:9001/api/drift/position-history'); + const data = await response.json(); + + if (!data.success || !data.trades.length) { + throw new Error('No trades found in Drift history'); + } + + const trade = data.trades[0]; // Most recent successful trade + console.log('📊 Found successful trade:', { + id: trade.id, + symbol: trade.symbol, + side: trade.side, + pnl: trade.pnl, + outcome: trade.outcome + }); + + // Check if this trade is already in our database + const existingTrade = await prisma.trades.findUnique({ + where: { id: trade.id } + }); + + if (existingTrade) { + console.log('✅ Trade already exists in database'); + return; + } + + // Add the successful trade to our database + const newTrade = await prisma.trades.create({ + data: { + id: trade.id, + userId: 'default-user', + symbol: trade.symbol, + side: trade.side, + amount: trade.amount, + price: trade.entryPrice, + entryPrice: trade.entryPrice, + exitPrice: trade.exitPrice, + leverage: trade.leverage || 1, + stopLoss: trade.stopLoss, + takeProfit: trade.takeProfit, + status: 'COMPLETED', + profit: trade.pnl, + createdAt: new Date(trade.entryTime), + closedAt: new Date(trade.exitTime), + confidence: trade.confidence || 85, + txId: trade.txId, + mode: 'LIVE' // This was a real trade + } + }); + + console.log('✅ Successfully added trade to database:', newTrade.id); + + // Also record this as an AI learning decision outcome + try { + const { SimplifiedStopLossLearner } = await import('../lib/simplified-stop-loss-learner-fixed.js'); + const learner = new SimplifiedStopLossLearner(); + + // Create a decision ID for this trade + const decisionId = `sync_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; + + // Record the decision first + await learner.recordDecision({ + id: decisionId, + symbol: trade.symbol, + recommendation: trade.side, + confidence: trade.confidence || 85, + stopLoss: trade.stopLoss || (trade.side === 'BUY' ? trade.entryPrice * 0.98 : trade.entryPrice * 1.02), + takeProfit: trade.takeProfit || (trade.side === 'BUY' ? trade.entryPrice * 1.04 : trade.entryPrice * 0.96), + entryPrice: trade.entryPrice, + marketConditions: { + timeframe: ['1h', '4h'], + analysis: `Successful ${trade.side} trade - ${trade.outcome}` + }, + timestamp: trade.entryTime + }); + + // Then record the successful outcome + await learner.assessDecisionOutcome({ + decisionId: decisionId, + outcome: 'WIN', + actualPnL: trade.pnl, + timestamp: trade.exitTime, + positionInfo: { + entryPrice: trade.entryPrice, + exitPrice: trade.exitPrice, + side: trade.side, + pnl: trade.pnl + } + }); + + console.log('🧠 Successfully recorded in AI learning system:', decisionId); + + // Generate updated learning report + const report = await learner.generateLearningReport(); + console.log('📊 Updated learning statistics:', report.summary); + + } catch (learningError) { + console.warn('⚠️ Could not add to AI learning system:', learningError.message); + } + + console.log('✅ Trade sync completed successfully!'); + + } catch (error) { + console.error('❌ Error syncing trade:', error); + } finally { + await prisma.$disconnect(); + } +} + +// Run the sync +syncSuccessfulTrade();