diff --git a/app/api/automation/analysis-details/route.js b/app/api/automation/analysis-details/route.js index 480a716..322c6f8 100644 --- a/app/api/automation/analysis-details/route.js +++ b/app/api/automation/analysis-details/route.js @@ -43,6 +43,9 @@ export async function GET() { price: 174.25, status: 'OPEN', profit: null, + entryTime: new Date(Date.now() - 30 * 60 * 1000).toISOString(), // 30 minutes ago + exitTime: null, + actualDuration: 30 * 60 * 1000, // 30 minutes in milliseconds createdAt: new Date(Date.now() - 30 * 60 * 1000).toISOString(), // 30 minutes ago aiAnalysis: 'BUY signal with 78% confidence - Multi-timeframe bullish alignment', stopLoss: 172.50, @@ -89,6 +92,9 @@ export async function GET() { price: 176.88, status: 'COMPLETED', profit: 3.24, + entryTime: new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString(), // 2 hours ago + exitTime: new Date(Date.now() - 2 * 60 * 60 * 1000 + 85 * 60 * 1000).toISOString(), // 85 minutes later + actualDuration: 85 * 60 * 1000, // 85 minutes in milliseconds createdAt: new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString(), // 2 hours ago aiAnalysis: 'SELL signal with 85% confidence - Resistance level rejection', stopLoss: 178.50, @@ -133,6 +139,9 @@ export async function GET() { price: 173.15, status: 'COMPLETED', profit: -1.89, + entryTime: new Date(Date.now() - 4 * 60 * 60 * 1000).toISOString(), // 4 hours ago + exitTime: new Date(Date.now() - 4 * 60 * 60 * 1000 + 45 * 60 * 1000).toISOString(), // 45 minutes later + actualDuration: 45 * 60 * 1000, // 45 minutes in milliseconds createdAt: new Date(Date.now() - 4 * 60 * 60 * 1000).toISOString(), // 4 hours ago aiAnalysis: 'BUY signal with 72% confidence - Support level bounce', stopLoss: 171.80, @@ -177,6 +186,9 @@ export async function GET() { price: 175.90, status: 'COMPLETED', profit: 1.86, + entryTime: new Date(Date.now() - 6 * 60 * 60 * 1000).toISOString(), // 6 hours ago + exitTime: new Date(Date.now() - 6 * 60 * 60 * 1000 + 52 * 60 * 1000).toISOString(), // 52 minutes later + actualDuration: 52 * 60 * 1000, // 52 minutes in milliseconds createdAt: new Date(Date.now() - 6 * 60 * 60 * 1000).toISOString(), // 6 hours ago aiAnalysis: 'SELL signal with 81% confidence - Bearish momentum confirmed', stopLoss: 177.20, @@ -319,89 +331,138 @@ export async function GET() { }, // Recent trades - // Recent trades - recentTrades: allTrades.map(trade => ({ - id: trade.id, - type: trade.type || 'MARKET', - side: trade.side, - amount: trade.amount, - tradingAmount: trade.tradingAmount || baseTradeAmount, // Use consistent base amount - leverage: trade.leverage || baseLeverage, // Use consistent base leverage - positionSize: trade.positionSize || (trade.tradingAmount || baseTradeAmount) * (trade.leverage || baseLeverage), - price: trade.price, - status: trade.status, - pnl: trade.profit, - pnlPercent: trade.profit ? ((trade.profit / (trade.amount * trade.price)) * 100).toFixed(2) + '%' : null, - createdAt: trade.createdAt, - reason: trade.aiAnalysis || `${trade.side} signal with confidence`, + recentTrades: allTrades.map(trade => { + // Calculate proper P&L based on trade amount and price movement + const currentPrice = trade.status === 'OPEN' ? 175.82 : (trade.exitMetrics?.exitPrice || trade.price) + const priceChange = trade.side === 'BUY' ? + (currentPrice - trade.price) : + (trade.price - currentPrice) + const realizedPnL = trade.status === 'COMPLETED' ? + (trade.profit || (priceChange * trade.amount)) : null + const unrealizedPnL = trade.status === 'OPEN' ? + (priceChange * trade.amount) : null - // Enhanced trade details - entryPrice: trade.price, - currentPrice: trade.status === 'OPEN' ? 175.82 : (trade.exitMetrics?.exitPrice || trade.price), - unrealizedPnl: trade.status === 'OPEN' ? - (trade.side === 'BUY' ? - ((175.82 - trade.price) * trade.amount).toFixed(2) : - ((trade.price - 175.82) * trade.amount).toFixed(2)) : null, - duration: trade.status === 'COMPLETED' ? - (trade.exitMetrics?.timeInTrade || `${Math.floor((Date.now() - new Date(trade.createdAt).getTime()) / (1000 * 60))} minutes`) : - `${Math.floor((Date.now() - new Date(trade.createdAt).getTime()) / (1000 * 60))} minutes (Active)`, - 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 || 102, + // Calculate duration + const entryTime = new Date(trade.entryTime || trade.createdAt) + const exitTime = trade.exitTime ? new Date(trade.exitTime) : null + const currentTime = new Date() - // Enhanced analysis context - triggerAnalysis: trade.triggerAnalysis ? { - decision: trade.triggerAnalysis.decision, - confidence: trade.triggerAnalysis.confidence, - timeframe: trade.triggerAnalysis.timeframe, - keySignals: trade.triggerAnalysis.keySignals, - marketCondition: trade.triggerAnalysis.marketCondition, - riskReward: trade.triggerAnalysis.riskReward, - invalidationLevel: trade.triggerAnalysis.invalidationLevel - } : null, + const durationMs = trade.status === 'COMPLETED' ? + (exitTime ? exitTime.getTime() - entryTime.getTime() : (trade.actualDuration || 0)) : + (currentTime.getTime() - entryTime.getTime()) - // Current trade metrics (for active trades) - currentMetrics: trade.currentMetrics ? { - currentPrice: trade.currentMetrics.currentPrice, - priceChange: trade.currentMetrics.priceChange, - priceChangePercent: trade.currentMetrics.priceChangePercent, - timeInTrade: trade.currentMetrics.timeInTrade, - unrealizedPnL: trade.currentMetrics.unrealizedPnL, - unrealizedPnLPercent: trade.currentMetrics.unrealizedPnLPercent, - distanceToSL: trade.currentMetrics.distanceToSL, - distanceToTP: trade.currentMetrics.distanceToTP, - riskRewardActual: trade.currentMetrics.riskRewardActual - } : null, + const durationMinutes = Math.floor(durationMs / (1000 * 60)) + const durationHours = Math.floor(durationMinutes / 60) + const remainingMinutes = durationMinutes % 60 - // Exit metrics (for completed trades) - exitMetrics: trade.exitMetrics ? { - exitPrice: trade.exitMetrics.exitPrice, - exitReason: trade.exitMetrics.exitReason, - timeInTrade: trade.exitMetrics.timeInTrade, - maxUnrealizedPnL: trade.exitMetrics.maxUnrealizedPnL, - maxDrawdown: trade.exitMetrics.maxDrawdown, - analysisAccuracy: trade.exitMetrics.analysisAccuracy, - actualRiskReward: trade.exitMetrics.actualRiskReward - } : null, + 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` + } - // Exit conditions - exitConditions: trade.exitConditions ? { - stopLossHit: trade.exitConditions.stopLossHit, - takeProfitHit: trade.exitConditions.takeProfitHit, - manualExit: trade.exitConditions.manualExit, - timeBasedExit: trade.exitConditions.timeBasedExit, - analysisInvalidated: trade.exitConditions.analysisInvalidated - } : null, - - // Trade result analysis - result: trade.status === 'COMPLETED' ? - (trade.profit > 0 ? 'PROFIT' : trade.profit < 0 ? 'LOSS' : 'BREAKEVEN') : - 'ACTIVE', - resultDescription: trade.status === 'COMPLETED' ? - `${trade.profit > 0 ? 'Successful' : 'Failed'} ${trade.side} trade - ${trade.exitMetrics?.exitReason || 'Completed'}` : - `${trade.side} position active - ${trade.currentMetrics?.timeInTrade || 'Active'}` - })) + return { + id: trade.id, + type: trade.type || 'MARKET', + side: trade.side, + amount: trade.amount, + tradingAmount: trade.tradingAmount || baseTradeAmount, + leverage: trade.leverage || baseLeverage, + positionSize: trade.positionSize || (trade.tradingAmount || baseTradeAmount) * (trade.leverage || baseLeverage), + price: trade.price, + status: trade.status, + pnl: realizedPnL, + pnlPercent: realizedPnL ? ((realizedPnL / (trade.tradingAmount || baseTradeAmount)) * 100).toFixed(2) + '%' : null, + createdAt: trade.createdAt, + + // Enhanced timing information + entryTime: trade.entryTime || trade.createdAt, + exitTime: trade.exitTime, + actualDuration: durationMs, + durationText: formatDuration(durationMinutes) + (trade.status === 'OPEN' ? ' (Active)' : ''), + + reason: trade.aiAnalysis || `${trade.side} signal with confidence`, + + // Enhanced trade details + entryPrice: trade.price, + exitPrice: trade.status === 'COMPLETED' ? (trade.exitMetrics?.exitPrice || currentPrice) : null, + currentPrice: trade.status === 'OPEN' ? currentPrice : null, + unrealizedPnl: unrealizedPnL?.toFixed(2) || null, + realizedPnl: realizedPnL?.toFixed(2) || null, + + 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 || 102, + + // Enhanced analysis context + triggerAnalysis: trade.triggerAnalysis ? { + decision: trade.triggerAnalysis.decision, + confidence: trade.triggerAnalysis.confidence, + timeframe: trade.triggerAnalysis.timeframe, + keySignals: trade.triggerAnalysis.keySignals, + marketCondition: trade.triggerAnalysis.marketCondition, + riskReward: trade.triggerAnalysis.riskReward, + invalidationLevel: trade.triggerAnalysis.invalidationLevel + } : null, + + // Current trade metrics (for active trades) + currentMetrics: trade.currentMetrics ? { + currentPrice: trade.currentMetrics.currentPrice, + priceChange: trade.currentMetrics.priceChange, + priceChangePercent: trade.currentMetrics.priceChangePercent, + timeInTrade: formatDuration(durationMinutes), + unrealizedPnL: unrealizedPnL?.toFixed(2) || trade.currentMetrics.unrealizedPnL, + unrealizedPnLPercent: unrealizedPnL ? ((unrealizedPnL / (trade.tradingAmount || baseTradeAmount)) * 100).toFixed(2) + '%' : trade.currentMetrics.unrealizedPnLPercent, + distanceToSL: trade.currentMetrics.distanceToSL, + distanceToTP: trade.currentMetrics.distanceToTP, + riskRewardActual: trade.currentMetrics.riskRewardActual + } : null, + + // Exit metrics (for completed trades) + exitMetrics: trade.exitMetrics ? { + exitPrice: trade.exitMetrics.exitPrice, + exitReason: trade.exitMetrics.exitReason, + timeInTrade: formatDuration(durationMinutes), + maxUnrealizedPnL: trade.exitMetrics.maxUnrealizedPnL, + maxDrawdown: trade.exitMetrics.maxDrawdown, + analysisAccuracy: trade.exitMetrics.analysisAccuracy, + actualRiskReward: trade.exitMetrics.actualRiskReward + } : null, + + // Exit conditions + exitConditions: trade.exitConditions ? { + stopLossHit: trade.exitConditions.stopLossHit, + takeProfitHit: trade.exitConditions.takeProfitHit, + manualExit: trade.exitConditions.manualExit, + timeBasedExit: trade.exitConditions.timeBasedExit, + analysisInvalidated: trade.exitConditions.analysisInvalidated + } : null, + + // Trade result analysis + result: trade.status === 'COMPLETED' ? + (realizedPnL > 0 ? 'WIN' : realizedPnL < 0 ? 'LOSS' : 'BREAKEVEN') : + 'ACTIVE', + resultDescription: trade.status === 'COMPLETED' ? + `${realizedPnL > 0 ? 'Profitable' : 'Loss'} ${trade.side} trade - ${trade.exitMetrics?.exitReason || 'Completed'}` : + `${trade.side} position active - ${formatDuration(durationMinutes)}`, + + // Screenshots and analysis data for modal + screenshots: [ + `/api/screenshots/analysis-${trade.id}-ai-layout.png`, + `/api/screenshots/analysis-${trade.id}-diy-layout.png`, + `/api/screenshots/analysis-${trade.id}-overview.png` + ], + analysisData: { + timestamp: trade.entryTime || trade.createdAt, + layoutsAnalyzed: ['AI Layout', 'DIY Layout'], + timeframesAnalyzed: ['15m', '1h', '2h', '4h'], + processingTime: '2.3 minutes', + tokensUsed: Math.floor(Math.random() * 2000) + 3000 + } + } + }) } }) } catch (error) { diff --git a/app/api/automation/trade-details/[id]/route.js b/app/api/automation/trade-details/[id]/route.js new file mode 100644 index 0000000..460324c --- /dev/null +++ b/app/api/automation/trade-details/[id]/route.js @@ -0,0 +1,322 @@ +import { NextResponse } from 'next/server' +import { PrismaClient } from '@prisma/client' +import fs from 'fs' +import path from 'path' + +const prisma = new PrismaClient() + +export async function GET(request, { params }) { + try { + const { id } = params + + // Mock detailed trade data with screenshots + const mockTradeDetails = { + 'demo-trade-1': { + id: 'demo-trade-1', + side: 'BUY', + amount: 1.5, + tradingAmount: 100, + leverage: 1, + positionSize: 100, + price: 174.25, + status: 'OPEN', + entryTime: new Date(Date.now() - 30 * 60 * 1000).toISOString(), + exitTime: null, + confidence: 78, + + // Analysis screenshots + screenshots: { + aiLayout: { + url: '/screenshots/demo-trade-1-ai-layout.png', + title: 'AI Layout Analysis', + description: 'Multi-timeframe analysis showing BUY signal with RSI oversold and MACD bullish crossover' + }, + diyLayout: { + url: '/screenshots/demo-trade-1-diy-layout.png', + title: 'DIY Layout Analysis', + description: 'Custom indicators showing support bounce confirmation and volume spike' + }, + overview: { + url: '/screenshots/demo-trade-1-overview.png', + title: 'Market Overview', + description: 'Full market context with key levels and trend analysis' + } + }, + + // Detailed analysis that triggered the trade + detailedAnalysis: { + timestamp: new Date(Date.now() - 30 * 60 * 1000).toISOString(), + decision: 'BUY', + confidence: 78, + overallSentiment: 'BULLISH', + + // Multi-timeframe analysis + timeframes: { + '15m': { + decision: 'BUY', + confidence: 75, + signals: ['RSI oversold (28)', 'Price bouncing from support'], + trend: 'BULLISH' + }, + '1h': { + decision: 'BUY', + confidence: 80, + signals: ['MACD bullish crossover', 'Volume spike on bounce'], + trend: 'BULLISH' + }, + '2h': { + decision: 'BUY', + confidence: 72, + signals: ['Support level holding', 'Bullish divergence'], + trend: 'NEUTRAL' + }, + '4h': { + decision: 'BUY', + confidence: 75, + signals: ['Higher lows pattern', 'EMA support'], + trend: 'BULLISH' + } + }, + + // Key levels identified + keyLevels: { + entry: { + price: 174.25, + rationale: 'Support bounce with high volume confirmation' + }, + stopLoss: { + price: 172.50, + rationale: 'Below key support level with 1% risk' + }, + takeProfit: { + price: 178.00, + rationale: 'Previous resistance level with 2.2:1 R/R ratio' + } + }, + + // Risk management + riskManagement: { + riskReward: '1:2.2', + riskPercentage: 1.75, + positionSize: 100, + maxDrawdown: 1.75, + expectedValue: 'Positive based on historical similar setups' + }, + + // Technical indicators + technicalIndicators: { + rsi: { + value: 28, + interpretation: 'Oversold - potential reversal signal' + }, + macd: { + value: 0.125, + interpretation: 'Bullish crossover - momentum building' + }, + volume: { + value: 'Above average', + interpretation: 'Strong buying interest at support' + }, + movingAverages: { + ema20: 173.85, + ema50: 172.90, + interpretation: 'Price above key EMAs - bullish structure' + } + }, + + // Market context + marketContext: { + overallTrend: 'BULLISH', + marketPhase: 'Correction within uptrend', + volatility: 'Moderate', + newsEvents: 'No major events expected', + correlations: 'Positive correlation with crypto market' + }, + + // AI reasoning + aiReasoning: ` + Multi-timeframe analysis indicates a high-probability BUY setup: + + 1. Technical Setup: RSI oversold (28) with MACD bullish crossover + 2. Price Action: Clean bounce from key support level at 174.00 + 3. Volume Confirmation: Above-average volume on the bounce + 4. Risk/Reward: Excellent 1:2.2 ratio with clear stop loss + 5. Market Context: Correction within overall bullish trend + + The combination of oversold conditions, support bounce, and volume confirmation + provides a high-confidence entry point with favorable risk/reward. + `, + + // Execution plan + executionPlan: { + entry: 'Market buy at 174.25', + stopLoss: 'Set at 172.50 (1.75% risk)', + takeProfit: 'Target 178.00 (2.2:1 R/R)', + positionSize: '$100 with 1x leverage', + monitoring: 'Monitor for volume continuation and trend strength' + } + } + }, + + 'demo-trade-2': { + id: 'demo-trade-2', + side: 'SELL', + amount: 2.04, + tradingAmount: 100, + leverage: 1, + positionSize: 100, + price: 176.88, + status: 'COMPLETED', + entryTime: new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString(), + exitTime: new Date(Date.now() - 2 * 60 * 60 * 1000 + 85 * 60 * 1000).toISOString(), + confidence: 85, + profit: 3.24, + + screenshots: { + aiLayout: { + url: '/screenshots/demo-trade-2-ai-layout.png', + title: 'AI Layout Analysis', + description: 'Resistance rejection pattern with RSI overbought and bearish divergence' + }, + diyLayout: { + url: '/screenshots/demo-trade-2-diy-layout.png', + title: 'DIY Layout Analysis', + description: 'Distribution pattern at key resistance with volume confirmation' + }, + overview: { + url: '/screenshots/demo-trade-2-overview.png', + title: 'Market Overview', + description: 'Clear resistance level rejection with bearish momentum building' + } + }, + + detailedAnalysis: { + timestamp: new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString(), + decision: 'SELL', + confidence: 85, + overallSentiment: 'BEARISH', + + timeframes: { + '15m': { + decision: 'SELL', + confidence: 88, + signals: ['RSI overbought (72)', 'Resistance rejection'], + trend: 'BEARISH' + }, + '1h': { + decision: 'SELL', + confidence: 85, + signals: ['Bearish divergence', 'Volume on rejection'], + trend: 'BEARISH' + }, + '2h': { + decision: 'SELL', + confidence: 80, + signals: ['Distribution pattern', 'Lower highs'], + trend: 'BEARISH' + }, + '4h': { + decision: 'SELL', + confidence: 82, + signals: ['Key resistance level', 'Momentum shift'], + trend: 'BEARISH' + } + }, + + keyLevels: { + entry: { + price: 176.88, + rationale: 'Resistance rejection with high volume' + }, + stopLoss: { + price: 178.50, + rationale: 'Above resistance with 0.9% risk' + }, + takeProfit: { + price: 174.20, + rationale: 'Support level with 1.6:1 R/R ratio' + } + }, + + riskManagement: { + riskReward: '1:1.6', + riskPercentage: 0.9, + positionSize: 100, + maxDrawdown: 0.9, + expectedValue: 'Positive based on resistance rejection pattern' + }, + + technicalIndicators: { + rsi: { + value: 72, + interpretation: 'Overbought - potential reversal signal' + }, + macd: { + value: -0.085, + interpretation: 'Bearish divergence - momentum weakening' + }, + volume: { + value: 'High on rejection', + interpretation: 'Strong selling pressure at resistance' + }, + movingAverages: { + ema20: 176.45, + ema50: 175.20, + interpretation: 'Resistance at key EMA levels' + } + }, + + marketContext: { + overallTrend: 'BEARISH', + marketPhase: 'Distribution at resistance', + volatility: 'Moderate', + newsEvents: 'No major events', + correlations: 'Negative correlation with broader market' + }, + + aiReasoning: ` + High-confidence SELL setup based on resistance rejection: + + 1. Technical Setup: RSI overbought (72) with bearish divergence + 2. Price Action: Clear rejection at key resistance level + 3. Volume Confirmation: High volume on the rejection candle + 4. Risk/Reward: Good 1:1.6 ratio with tight stop loss + 5. Market Context: Distribution pattern at resistance + + The combination of overbought conditions, resistance rejection, and volume + confirmation provides excellent entry with favorable risk/reward profile. + `, + + executionPlan: { + entry: 'Market sell at 176.88', + stopLoss: 'Set at 178.50 (0.9% risk)', + takeProfit: 'Target 174.20 (1.6:1 R/R)', + positionSize: '$100 with 1x leverage', + monitoring: 'Monitor for break below support levels' + } + } + } + } + + const tradeDetails = mockTradeDetails[id] + + if (!tradeDetails) { + return NextResponse.json({ + success: false, + error: 'Trade not found' + }, { status: 404 }) + } + + return NextResponse.json({ + success: true, + data: tradeDetails + }) + + } catch (error) { + console.error('Error fetching trade details:', error) + return NextResponse.json({ + success: false, + error: 'Failed to fetch trade details' + }, { status: 500 }) + } +} diff --git a/app/automation/page.js b/app/automation/page.js index 25db910..821adee 100644 --- a/app/automation/page.js +++ b/app/automation/page.js @@ -20,6 +20,8 @@ export default function AutomationPage() { const [aiLearningStatus, setAiLearningStatus] = useState(null) const [recentTrades, setRecentTrades] = useState([]) const [analysisDetails, setAnalysisDetails] = useState(null) + const [selectedTrade, setSelectedTrade] = useState(null) + const [tradeModalOpen, setTradeModalOpen] = useState(false) useEffect(() => { fetchStatus() @@ -187,6 +189,45 @@ export default function AutomationPage() { } } + const openTradeModal = async (tradeId) => { + try { + const response = await fetch(`/api/automation/trade-details/${tradeId}`) + const data = await response.json() + if (data.success) { + setSelectedTrade(data.data) + setTradeModalOpen(true) + } else { + alert('Failed to load trade details') + } + } catch (error) { + console.error('Failed to load trade details:', error) + alert('Failed to load trade details') + } + } + + const closeTradeModal = () => { + setTradeModalOpen(false) + setSelectedTrade(null) + } + + // Calculate win rate from recent trades + const calculateWinRate = () => { + if (!recentTrades.length) return 0 + const completedTrades = recentTrades.filter(t => t.status === 'COMPLETED') + if (!completedTrades.length) return 0 + const winningTrades = completedTrades.filter(t => t.result === 'WIN') + return (winningTrades.length / completedTrades.length * 100).toFixed(1) + } + + // Calculate total P&L from recent trades + const calculateTotalPnL = () => { + if (!recentTrades.length) return 0 + return recentTrades + .filter(t => t.status === 'COMPLETED' && t.realizedPnl) + .reduce((total, trade) => total + parseFloat(trade.realizedPnl), 0) + .toFixed(2) + } + return (
@@ -538,19 +579,19 @@ export default function AutomationPage() {
Win Rate: 0.6 ? 'text-green-400' : - status.winRate > 0.4 ? 'text-yellow-400' : 'text-red-400' + calculateWinRate() > 60 ? 'text-green-400' : + calculateWinRate() > 40 ? 'text-yellow-400' : 'text-red-400' }`}> - {(status.winRate * 100).toFixed(1)}% + {calculateWinRate()}%
Total P&L: 0 ? 'text-green-400' : - status.totalPnL < 0 ? 'text-red-400' : 'text-gray-300' + calculateTotalPnL() > 0 ? 'text-green-400' : + calculateTotalPnL() < 0 ? 'text-red-400' : 'text-gray-300' }`}> - ${status.totalPnL.toFixed(2)} + ${calculateTotalPnL()}
{status.lastAnalysis && ( @@ -579,7 +620,11 @@ export default function AutomationPage() { {recentTrades.length > 0 ? (
{recentTrades.slice(0, 5).map((trade, idx) => ( -
+
openTradeModal(trade.id)} + > {/* Trade Header */}
@@ -592,7 +637,7 @@ export default function AutomationPage() { {trade.leverage}x @@ -605,6 +650,26 @@ export default function AutomationPage() {
+ {/* Enhanced Timing Information */} +
+
+
+ Entry Time: + {new Date(trade.entryTime).toLocaleTimeString()} +
+
+ Exit Time: + + {trade.exitTime ? new Date(trade.exitTime).toLocaleTimeString() : 'Active'} + +
+
+ Duration: + {trade.durationText} +
+
+
+ {/* Trading Details */}
@@ -621,117 +686,52 @@ export default function AutomationPage() { ${trade.positionSize}
- Entry Price: - ${trade.entryPrice.toFixed(2)} + {trade.isActive ? 'Current' : 'Exit'} Price: + + ${trade.isActive ? trade.currentPrice?.toFixed(2) : trade.exitPrice?.toFixed(2)} +
- {/* Analysis Context */} - {trade.triggerAnalysis && ( -
-

📊 Trigger Analysis

-
-
- Decision: - {trade.triggerAnalysis.decision} ({trade.triggerAnalysis.confidence}%) -
-
- Market Condition: - {trade.triggerAnalysis.marketCondition} -
-
- Expected R/R: - {trade.triggerAnalysis.riskReward} -
-
- Key Signals: -
    - {trade.triggerAnalysis.keySignals.map((signal, signalIdx) => ( -
  • • {signal}
  • - ))} -
-
+ {/* P&L Display */} +
+
+ P&L: +
+ 0 ? 'text-green-400' : 'text-red-400') : + (trade.realizedPnl && parseFloat(trade.realizedPnl) > 0 ? 'text-green-400' : 'text-red-400') + }`}> + ${trade.isActive ? + (trade.unrealizedPnl || '0.00') : + (trade.realizedPnl || '0.00') + } + + {trade.pnlPercent && ( + 0 ? 'text-green-400' : 'text-red-400') : + (trade.realizedPnl && parseFloat(trade.realizedPnl) > 0 ? 'text-green-400' : 'text-red-400') + }`}> + ({trade.pnlPercent}) + + )} + + {trade.isActive ? '(Unrealized)' : '(Realized)'} +
- )} +
- {/* Current Metrics (Active Trades) */} - {trade.isActive && trade.currentMetrics && ( -
-

📈 Current Status

-
-
- Current Price: - ${trade.currentMetrics.currentPrice.toFixed(2)} -
-
- Price Change: - 0 ? 'text-green-400' : 'text-red-400'}`}> - {trade.currentMetrics.priceChange > 0 ? '+' : ''}${trade.currentMetrics.priceChange.toFixed(2)} - -
-
- Unrealized P&L: - 0 ? 'text-green-400' : 'text-red-400'}`}> - {trade.currentMetrics.unrealizedPnL > 0 ? '+' : ''}${trade.currentMetrics.unrealizedPnL.toFixed(2)} - -
-
- Time in Trade: - {trade.currentMetrics.timeInTrade} -
-
-
- )} - - {/* Exit Metrics (Completed Trades) */} - {!trade.isActive && trade.exitMetrics && ( -
-

📊 Exit Analysis

-
-
- Exit Reason: - {trade.exitMetrics.exitReason} -
-
- Exit Price: - ${trade.exitMetrics.exitPrice.toFixed(2)} -
-
- Analysis Accuracy: - - {trade.exitMetrics.analysisAccuracy} - -
-
- Actual R/R: - {trade.exitMetrics.actualRiskReward} -
-
-
- )} - - {/* Trade Summary */} + {/* Click hint */}
- {trade.duration} | ${trade.tradingAmount} @ {trade.leverage}x + SL: ${trade.stopLoss} | TP: ${trade.takeProfit}
-
-
- SL: ${trade.stopLoss} | TP: ${trade.takeProfit} -
-
0 ? 'text-green-400' : 'text-red-400') : - (trade.pnl > 0 ? 'text-green-400' : 'text-red-400') - }`}> - {trade.isActive ? - `P&L: ${trade.unrealizedPnl > 0 ? '+' : ''}${trade.unrealizedPnl}` : - `P&L: ${trade.pnl > 0 ? '+' : ''}${trade.pnl}` - } -
+
+ 📊 Click to view analysis
@@ -938,6 +938,199 @@ export default function AutomationPage() {
)} + + {/* Trade Details Modal */} + {tradeModalOpen && selectedTrade && ( +
+
+ {/* Modal Header */} +
+
+

Trade Analysis Details

+ + {selectedTrade.side} {selectedTrade.amount} @ ${selectedTrade.price.toFixed(2)} + + 0 ? 'bg-green-600 text-white' : 'bg-red-600 text-white' + }`}> + {selectedTrade.status} {selectedTrade.profit && `(${selectedTrade.profit > 0 ? '+' : ''}$${selectedTrade.profit.toFixed(2)})`} + +
+ +
+ + {/* Modal Content */} +
+ + {/* Trade Overview */} +
+
+

Trade Info

+
+
+ Entry Time: + {new Date(selectedTrade.entryTime).toLocaleString()} +
+
+ Exit Time: + + {selectedTrade.exitTime ? new Date(selectedTrade.exitTime).toLocaleString() : 'Active'} + +
+
+ Duration: + + {selectedTrade.exitTime ? + `${Math.floor((new Date(selectedTrade.exitTime) - new Date(selectedTrade.entryTime)) / (1000 * 60))}m` : + `${Math.floor((new Date() - new Date(selectedTrade.entryTime)) / (1000 * 60))}m (Active)` + } + +
+
+
+ +
+

Position Details

+
+
+ Trading Amount: + ${selectedTrade.tradingAmount} +
+
+ Leverage: + {selectedTrade.leverage}x +
+
+ Position Size: + ${selectedTrade.positionSize} +
+
+
+ +
+

Risk Management

+
+
+ Stop Loss: + ${selectedTrade.detailedAnalysis?.keyLevels?.stopLoss?.price || 'N/A'} +
+
+ Take Profit: + ${selectedTrade.detailedAnalysis?.keyLevels?.takeProfit?.price || 'N/A'} +
+
+ Risk/Reward: + {selectedTrade.detailedAnalysis?.riskManagement?.riskReward || 'N/A'} +
+
+
+
+ + {/* Analysis Screenshots */} +
+

📊 Analysis Screenshots

+
+ {selectedTrade.screenshots && Object.entries(selectedTrade.screenshots).map(([key, screenshot]) => ( +
+

{screenshot.title}

+
+
+ 📷 {screenshot.title} +
+ {screenshot.description} +
+
+

{screenshot.description}

+
+ ))} +
+
+ + {/* AI Analysis Details */} + {selectedTrade.detailedAnalysis && ( +
+

🤖 AI Analysis

+ + {/* Decision Summary */} +
+
+

Decision Summary

+ + {selectedTrade.detailedAnalysis.decision} ({selectedTrade.detailedAnalysis.confidence}%) + +
+

{selectedTrade.detailedAnalysis.aiReasoning}

+
+ + {/* Multi-timeframe Analysis */} +
+

Multi-timeframe Analysis

+
+ {selectedTrade.detailedAnalysis.timeframes && Object.entries(selectedTrade.detailedAnalysis.timeframes).map(([tf, data]) => ( +
+
+ {tf} + + {data.decision} + +
+
+ Confidence: {data.confidence}% +
+
+ {data.signals.slice(0, 2).map((signal, idx) => ( +
• {signal}
+ ))} +
+
+ ))} +
+
+ + {/* Technical Indicators */} +
+

Technical Indicators

+
+ {selectedTrade.detailedAnalysis.technicalIndicators && Object.entries(selectedTrade.detailedAnalysis.technicalIndicators).map(([indicator, data]) => ( +
+
{indicator}
+
{data.value}
+
{data.interpretation}
+
+ ))} +
+
+ + {/* Execution Plan */} +
+

Execution Plan

+
+ {selectedTrade.detailedAnalysis.executionPlan && Object.entries(selectedTrade.detailedAnalysis.executionPlan).map(([key, value]) => ( +
+ {key}: + {value} +
+ ))} +
+
+
+ )} +
+
+
+ )}
) } diff --git a/prisma/prisma/dev.db b/prisma/prisma/dev.db index 919af95..57bbe1d 100644 Binary files a/prisma/prisma/dev.db and b/prisma/prisma/dev.db differ