diff --git a/app/api/automation/analysis-details/route.js b/app/api/automation/analysis-details/route.js index bc14c31..313725b 100644 --- a/app/api/automation/analysis-details/route.js +++ b/app/api/automation/analysis-details/route.js @@ -107,17 +107,32 @@ export async function GET() { } } - // Determine result based on actual profit + // Determine result based on actual profit - use profit field as fallback let result = 'ACTIVE' if (trade.status === 'COMPLETED') { - if (calculatedProfit === null || calculatedProfit === undefined) { - result = 'UNKNOWN' // When we truly don't have enough data - } else if (Math.abs(calculatedProfit) < 0.01) { // Within 1 cent - result = 'BREAKEVEN' - } else if (calculatedProfit > 0) { - result = 'WIN' + // 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 = 'LOSS' + result = 'UNKNOWN' // When we truly don't have any profit data } } diff --git a/app/automation/page.js b/app/automation/page.js index 803cc97..c504c6c 100644 --- a/app/automation/page.js +++ b/app/automation/page.js @@ -95,10 +95,13 @@ export default function AutomationPage() { const fetchRecentTrades = async () => { try { + console.log('๐Ÿ” Fetching recent trades...') // Get enhanced trade data from analysis-details instead of recent-trades const response = await fetch('/api/automation/analysis-details') const data = await response.json() + console.log('๐Ÿ“Š Trade data response:', data.success, data.data?.recentTrades?.length || 0) if (data.success && data.data.recentTrades) { + console.log('โœ… Setting recent trades:', data.data.recentTrades.length) setRecentTrades(data.data.recentTrades) } } catch (error) { @@ -211,22 +214,14 @@ export default function AutomationPage() { 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) + // Use status API data instead of calculating from limited recent trades + const getWinRate = () => { + return status?.winRate || 0 } - // Calculate total P&L from recent trades - const calculateTotalPnL = () => { - if (!recentTrades.length) return 0 - return recentTrades - .filter(t => t.status === 'COMPLETED' && t.pnl) - .reduce((total, trade) => total + parseFloat(trade.pnl), 0) - .toFixed(2) + // Use status API data for total P&L + const getTotalPnL = () => { + return status?.totalPnL || 0 } return ( @@ -583,19 +578,19 @@ export default function AutomationPage() {
Win Rate: 60 ? 'text-green-400' : - calculateWinRate() > 40 ? 'text-yellow-400' : 'text-red-400' + getWinRate() > 60 ? 'text-green-400' : + getWinRate() > 40 ? 'text-yellow-400' : 'text-red-400' }`}> - {calculateWinRate()}% + {getWinRate()}%
Total P&L: 0 ? 'text-green-400' : - calculateTotalPnL() < 0 ? 'text-red-400' : 'text-gray-300' + getTotalPnL() > 0 ? 'text-green-400' : + getTotalPnL() < 0 ? 'text-red-400' : 'text-gray-300' }`}> - ${calculateTotalPnL()} + ${getTotalPnL()}
{status.lastAnalysis && ( @@ -620,7 +615,8 @@ export default function AutomationPage() { {/* Recent Trades */}
-

Latest 4 Automated Trades

+

Latest 4 Automated Trades (Debug: {recentTrades.length})

+ {console.log('๐ŸŽฏ Rendering trades section, count:', recentTrades.length)} {recentTrades.length > 0 ? (
{recentTrades.slice(0, 4).map((trade, idx) => ( diff --git a/app/automation/page.js.backup b/app/automation/page.js.backup new file mode 100644 index 0000000..c11ab83 --- /dev/null +++ b/app/automation/page.js.backup @@ -0,0 +1,1200 @@ +'use client' +import React, { useState, useEffect } from 'react' +import RealTimePriceMonitor from '../../components/RealTimePriceMonitor' + +export default function AutomationPage() { + const [config, setConfig] = useState({ + mode: 'SIMULATION', + symbol: 'SOLUSD', + timeframe: '1h', + tradingAmount: 100, + maxLeverage: 3, + stopLossPercent: 2, + takeProfitPercent: 6, + maxDailyTrades: 5, + riskPercentage: 2 + }) + + const [status, setStatus] = useState(null) + const [isLoading, setIsLoading] = useState(false) + const [learningInsights, setLearningInsights] = useState(null) + 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() + fetchLearningInsights() + fetchAiLearningStatus() + fetchRecentTrades() + fetchAnalysisDetails() + + // Auto-refresh every 30 seconds + const interval = setInterval(() => { + fetchStatus() + fetchAnalysisDetails() + fetchAiLearningStatus() + }, 30000) + + return () => clearInterval(interval) + }, []) + + const fetchAnalysisDetails = async () => { + try { + const response = await fetch('/api/automation/analysis-details') + const data = await response.json() + if (data.success) { + setAnalysisDetails(data.data) + // Also update recent trades from the same endpoint + if (data.data.recentTrades) { + setRecentTrades(data.data.recentTrades) + } + } + } catch (error) { + console.error('Failed to fetch analysis details:', error) + } + } + + const fetchStatus = async () => { + try { + const response = await fetch('/api/automation/status') + const data = await response.json() + if (data.success) { + setStatus(data.status) + } + } catch (error) { + console.error('Failed to fetch status:', error) + } + } + + const fetchLearningInsights = async () => { + try { + const response = await fetch('/api/automation/learning-insights') + const data = await response.json() + if (data.success) { + setLearningInsights(data.insights) + } + } catch (error) { + console.error('Failed to fetch learning insights:', error) + } + } + + const fetchAiLearningStatus = async () => { + try { + const response = await fetch('/api/ai-learning-status') + const data = await response.json() + if (data.success) { + setAiLearningStatus(data.data) + } + } catch (error) { + console.error('Failed to fetch AI learning status:', error) + } + } + + const fetchRecentTrades = async () => { + try { + console.log('๐Ÿ” Fetching recent trades...') + // Get enhanced trade data from analysis-details instead of recent-trades + const response = await fetch('/api/automation/analysis-details') + const data = await response.json() + console.log('๐Ÿ“Š API Response:', data) + console.log('๐Ÿ“ˆ Recent trades in response:', data.data?.recentTrades?.length || 0) + if (data.success && data.data.recentTrades) { + console.log('โœ… Setting recent trades:', data.data.recentTrades.length) + setRecentTrades(data.data.recentTrades) + } else { + console.log('โŒ No recent trades found in API response') + } + } catch (error) { + console.error('Failed to fetch recent trades:', error) + } + } + + const handleStart = async () => { + setIsLoading(true) + try { + const response = await fetch('/api/automation/start', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(config) + }) + const data = await response.json() + if (data.success) { + fetchStatus() + } else { + alert('Failed to start automation: ' + data.error) + } + } catch (error) { + console.error('Failed to start automation:', error) + alert('Failed to start automation') + } finally { + setIsLoading(false) + } + } + + const handleStop = async () => { + setIsLoading(true) + try { + const response = await fetch('/api/automation/stop', { + method: 'POST' + }) + const data = await response.json() + if (data.success) { + fetchStatus() + } else { + alert('Failed to stop automation: ' + data.error) + } + } catch (error) { + console.error('Failed to stop automation:', error) + alert('Failed to stop automation') + } finally { + setIsLoading(false) + } + } + + const handlePause = async () => { + setIsLoading(true) + try { + const response = await fetch('/api/automation/pause', { + method: 'POST' + }) + const data = await response.json() + if (data.success) { + fetchStatus() + } else { + alert('Failed to pause automation: ' + data.error) + } + } catch (error) { + console.error('Failed to pause automation:', error) + alert('Failed to pause automation') + } finally { + setIsLoading(false) + } + } + + const handleResume = async () => { + setIsLoading(true) + try { + const response = await fetch('/api/automation/resume', { + method: 'POST' + }) + const data = await response.json() + if (data.success) { + fetchStatus() + } else { + alert('Failed to resume automation: ' + data.error) + } + } catch (error) { + console.error('Failed to resume automation:', error) + alert('Failed to resume automation') + } finally { + setIsLoading(false) + } + } + + 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.pnl) + .reduce((total, trade) => total + parseFloat(trade.pnl), 0) + .toFixed(2) + } + + return ( +
+
+
+

Automation Mode

+

+ AI-powered automated trading on 1H timeframe with learning capabilities +

+
+
+ {status?.isActive ? ( + <> + + + + ) : ( + <> + {status?.status === 'PAUSED' && ( + + )} + + + )} +
+
+ + {/* Real-Time Price Monitor - Top Priority */} + + +
+ {/* Left Column: Configuration & Controls */} +
+ {/* Configuration Panel */} +
+

โš™๏ธ Configuration

+ +
+
+ + +
+ +
+
+ + +
+ +
+ + +
+
+ +
+
+ + setConfig({...config, tradingAmount: parseFloat(e.target.value)})} + className="w-full p-3 bg-gray-800 border border-gray-700 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-blue-500" + disabled={status?.isActive} + min="10" + step="10" + /> +
+ +
+ + +
+
+ +
+
+ + setConfig({...config, stopLossPercent: parseFloat(e.target.value)})} + className="w-full p-3 bg-gray-800 border border-gray-700 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-blue-500" + disabled={status?.isActive} + min="1" + max="10" + step="0.5" + /> +
+ +
+ + setConfig({...config, takeProfitPercent: parseFloat(e.target.value)})} + className="w-full p-3 bg-gray-800 border border-gray-700 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-blue-500" + disabled={status?.isActive} + min="2" + max="20" + step="1" + /> +
+ +
+ + setConfig({...config, maxDailyTrades: parseInt(e.target.value)})} + className="w-full p-3 bg-gray-800 border border-gray-700 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-blue-500" + disabled={status?.isActive} + min="1" + max="20" + /> +
+
+
+
+
+ + {/* Right Column: Status & Performance */} +
+ {/* Status Panel */} +
+

๐Ÿ“Š Automation Status

+ {status ? ( +
+
+ Status: + + {status.isActive ? 'ACTIVE' : 'STOPPED'} + +
+
+ Mode: + + {status.mode} + +
+
+ Symbol: + {status.symbol} +
+
+ Timeframe: + {status.timeframe} +
+
+ Total Trades: + {status.totalTrades} +
+
+ Win Rate: + 60 ? 'text-green-400' : + calculateWinRate() > 40 ? 'text-yellow-400' : 'text-red-400' + }`}> + {calculateWinRate()}% + +
+
+ Total P&L: + 0 ? 'text-green-400' : + calculateTotalPnL() < 0 ? 'text-red-400' : 'text-gray-300' + }`}> + ${calculateTotalPnL()} + +
+ {status.lastAnalysis && ( +
+ Last Analysis: + + {new Date(status.lastAnalysis).toLocaleTimeString()} + +
+ )} + {status.errorCount > 0 && ( +
+ Errors: + {status.errorCount} +
+ )} +
+ ) : ( +

No active automation session

+ )} +
+ + {/* Recent Trades */} +
+

Latest 4 Automated Trades (Debug: {recentTrades.length})

+ {recentTrades.length > 0 ? ( +
+
โœ… We have {recentTrades.length} trades to display
+ {recentTrades.slice(0, 4).map((trade, idx) => ( +
+
+ Trade #{idx + 1}: {trade?.side || 'UNKNOWN'} - ${trade?.amount?.toFixed(4) || 'N/A'} - {trade?.status || 'UNKNOWN'} +
+
+ Entry: ${trade?.entryPrice?.toFixed(2) || trade?.price?.toFixed(2) || '0.00'} | + P&L: ${trade?.pnl || trade?.realizedPnl || '0.00'} | + Result: {trade?.result || 'UNKNOWN'} +
+
+ ))} +
+ ) : ( +

No recent trades

+ )} +
+
+ {trade?.amount?.toFixed(4) || 'N/A'} + {trade?.leverage || 1}x + + {trade?.isActive ? 'ACTIVE' : (trade?.result || 'UNKNOWN')} + +
+
+
${trade?.entryPrice?.toFixed(2) || trade?.price?.toFixed(2) || '0.00'}
+
{trade?.confidence || 0}% confidence
+
+
+ + {/* Enhanced Timing Information */} +
+
+
+ Entry Time: + {trade?.entryTime ? new Date(trade.entryTime).toLocaleTimeString() : 'N/A'} +
+
+ Exit Time: + + {trade?.exitTime ? new Date(trade.exitTime).toLocaleTimeString() : 'Active'} + +
+
+ Duration: + {trade?.durationText || 'N/A'} +
+
+
+ + {/* Trading Details */} +
+
+
+ Trading Amount: + ${trade?.tradingAmount || 0} +
+
+ Leverage: + {trade?.leverage || 1}x +
+
+ Position Size: + ${trade?.positionSize || '0.00'} +
+ {/* Entry Price - Always show for completed trades */} +
+ Entry Price: + ${trade?.entryPrice?.toFixed(2) || trade?.price?.toFixed(2) || '0.00'} +
+ {/* Exit Price or Current Price */} +
+ {trade?.isActive ? 'Current' : 'Exit'} Price: + + {trade?.isActive ? + `$${trade?.currentPrice?.toFixed(2) || '0.00'}` : + (trade?.exitPrice ? + `$${trade.exitPrice.toFixed(2)}` : + Not recorded + ) + } + +
+ {/* Price difference for completed trades */} + {!trade?.isActive && trade?.exitPrice && trade?.entryPrice && ( +
+ Price Difference: + 0 ? 'text-green-400' : + (trade?.exitPrice - trade?.entryPrice) < 0 ? 'text-red-400' : + 'text-gray-400' + }`}> + ${((trade?.exitPrice - trade?.entryPrice) >= 0 ? '+' : '')}${(trade?.exitPrice - trade?.entryPrice)?.toFixed(2) || '0.00'} + +
+ )} +
+
+ + {/* P&L Display */} +
+
+ P&L: +
+ 0 ? 'text-green-400' : 'text-red-400') : + (trade?.realizedPnl && parseFloat(trade.realizedPnl) > 0 ? 'text-green-400' : + trade?.realizedPnl && parseFloat(trade.realizedPnl) < 0 ? 'text-red-400' : 'text-gray-400') + }`}> + ${trade?.isActive ? + (trade?.unrealizedPnl || '0.00') : + (trade?.realizedPnl || trade?.pnl || '0.00') + } + + {trade?.pnlPercent && ( + 0 ? 'text-green-400' : 'text-red-400') : + (trade?.realizedPnl && parseFloat(trade.realizedPnl) > 0 ? 'text-green-400' : + trade?.realizedPnl && parseFloat(trade.realizedPnl) < 0 ? 'text-red-400' : 'text-gray-400') + }`}> + ({trade?.pnlPercent || '0%'}) + + )} + + {trade?.isActive ? '(Unrealized)' : '(Realized)'} + +
+
+ {/* Debug info for missing data */} + {trade?.result === 'UNKNOWN' && ( +
+ โš ๏ธ Missing exit data: {!trade?.exitPrice ? 'Exit Price ' : ''}{trade?.calculatedProfit === null ? 'Profit' : ''} +
+ )} + {/* Warning for old incorrect trades */} + {trade?.isOldWrongTrade && ( +
+ ๐Ÿ”ง Old trade with incorrect price data (stored: ${trade?.originalStoredPrice?.toFixed(2)}, should be ~$189) +
+ )} +
+ + {/* Click hint */} +
+
+ SL: ${trade?.stopLoss || 'N/A'} | TP: ${trade?.takeProfit || 'N/A'} +
+
+ ๐Ÿ“Š Click to view analysis +
+
+ + {/* Learning Insights */} + {learningInsights && ( +
+

๐Ÿ’ก Learning Insights

+
+
+ Total Analyses: + {learningInsights.totalAnalyses} +
+
+ Avg Accuracy: + {(learningInsights.avgAccuracy * 100).toFixed(1)}% +
+
+ Best Timeframe: + {learningInsights.bestTimeframe} +
+
+ Worst Timeframe: + {learningInsights.worstTimeframe} +
+ +
+

Recommendations

+
    + {learningInsights.recommendations.map((rec, idx) => ( +
  • โ€ข {rec}
  • + ))} +
+
+
+
+ )} +
+
+ + {/* Detailed AI Analysis Section */} + {analysisDetails?.analysis && ( +
+

Latest AI Analysis

+ +
+ {/* Main Decision */} +
+

๐ŸŽฏ Trading Decision

+
+
+ Decision: + + {analysisDetails.analysis.decision} + +
+
+ Confidence: + 80 ? 'text-green-400' : + analysisDetails.analysis.confidence > 60 ? 'text-yellow-400' : + 'text-red-400' + }`}> + {analysisDetails.analysis.confidence}% + +
+
+ Market Sentiment: + + {analysisDetails.analysis.sentiment} + +
+
+

+ Summary: {analysisDetails.analysis.summary} +

+
+
+
+ + {/* Key Levels */} +
+

๐Ÿ“Š Key Levels

+
+ {analysisDetails.analysis.keyLevels?.support?.length > 0 && ( +
+

Support Levels

+ {analysisDetails.analysis.keyLevels.support.map((level, idx) => ( +
+ S{idx + 1}: + ${level.toFixed(2)} +
+ ))} +
+ )} + {analysisDetails.analysis.keyLevels?.resistance?.length > 0 && ( +
+

Resistance Levels

+ {analysisDetails.analysis.keyLevels.resistance.map((level, idx) => ( +
+ R{idx + 1}: + ${level.toFixed(2)} +
+ ))} +
+ )} +
+
+ + {/* Technical Indicators */} +
+

๐Ÿ“ˆ Technical Indicators

+
+ {analysisDetails.analysis.technicalIndicators && Object.entries(analysisDetails.analysis.technicalIndicators).map(([key, value]) => ( +
+ {key.replace(/([A-Z])/g, ' $1').trim()}: + + {typeof value === 'number' ? value.toFixed(2) : value} + +
+ ))} +
+
+
+ + {/* AI Reasoning */} + {analysisDetails.analysis.reasoning && ( +
+

๐Ÿค– AI Reasoning

+
+
+

{analysisDetails.analysis.reasoning}

+
+ {analysisDetails.analysis.executionPlan && ( +
+

Execution Plan:

+

{analysisDetails.analysis.executionPlan}

+
+ )} +
+
+ )} + + {/* Risk Assessment */} + {analysisDetails.analysis.riskAssessment && ( +
+

โš ๏ธ Risk Assessment

+
+
+

{analysisDetails.analysis.riskAssessment}

+
+ {analysisDetails.analysis.marketConditions && ( +
+

Market Conditions:

+

{analysisDetails.analysis.marketConditions}

+
+ )} +
+
+ )} + + {/* Layout Analysis */} + {analysisDetails.analysis.layoutAnalysis && ( +
+

๐Ÿ” Multi-Layout Analysis

+
+ {Object.entries(analysisDetails.analysis.layoutAnalysis).map(([layout, analysis]) => ( +
+

{layout} Layout:

+

{analysis}

+
+ ))} +
+
+ )} + + {/* Performance Metrics */} +
+

๐Ÿ“Š Analysis Performance

+
+
+
+ {analysisDetails.analysis.timestamp ? + new Date(analysisDetails.analysis.timestamp).toLocaleTimeString() : + 'N/A' + } +
+
Last Analysis
+
+
+
+ {analysisDetails.analysis.processingTime ? + `${analysisDetails.analysis.processingTime}ms` : + 'N/A' + } +
+
Processing Time
+
+
+
+ {analysisDetails.session?.totalTrades || 0} +
+
Total Trades
+
+
+
+ {analysisDetails.session?.errorCount || 0} +
+
Errors
+
+
+
+
+ )} + + {/* Multi-Timeframe Analysis Results */} + {analysisDetails?.analysis?.multiTimeframeResults && analysisDetails.analysis.multiTimeframeResults.length > 0 && ( +
+

๐Ÿ“Š Multi-Timeframe Analysis

+ +
+ {analysisDetails.analysis.multiTimeframeResults.map((result, index) => ( +
+
+

+ {result.analysisComplete ? ( + โœ… + ) : ( + โณ + )} + {result.timeframe} Timeframe +

+ + {result.analysisComplete ? 'Complete' : 'In Progress'} + +
+ +
+
+ Decision: + + {result.decision} + +
+ +
+ Confidence: + 80 ? 'text-green-400' : + result.confidence > 60 ? 'text-yellow-400' : + 'text-red-400' + }`}> + {result.confidence}% + +
+ +
+ Sentiment: + + {result.sentiment} + +
+ + {result.createdAt && ( +
+
+ Analyzed: {new Date(result.createdAt).toLocaleString()} +
+
+ )} +
+
+ ))} +
+ + {/* Multi-Timeframe Summary */} +
+

๐Ÿ“ˆ Cross-Timeframe Consensus

+
+
+
+ {analysisDetails.analysis.multiTimeframeResults.length} +
+
Timeframes Analyzed
+
+
+
+ {analysisDetails.analysis.multiTimeframeResults.filter(r => r.analysisComplete).length} +
+
Completed
+
+
+
+ {Math.round( + analysisDetails.analysis.multiTimeframeResults.reduce((sum, r) => sum + r.confidence, 0) / + analysisDetails.analysis.multiTimeframeResults.length + )}% +
+
Avg Confidence
+
+
+
+
+ )} + + {/* No Analysis Available */} + {!analysisDetails?.analysis && status?.isActive && ( +
+

๐Ÿค– AI Analysis

+
+
+

Waiting for first analysis...

+

The AI will analyze the market every hour

+
+
+ )} + + {/* Trade Details Modal */} + {tradeModalOpen && selectedTrade && ( +
+
+ {/* Modal Header */} +
+
+

Trade Analysis Details

+ + {selectedTrade.side} {selectedTrade.amount} @ ${selectedTrade.price?.toFixed(2) || '0.00'} + + 0 ? 'bg-green-600 text-white' : 'bg-red-600 text-white' + }`}> + {selectedTrade.status} {selectedTrade.profit && `(${selectedTrade.profit > 0 ? '+' : ''}$${selectedTrade.profit?.toFixed(2) || '0.00'})`} + +
+ +
+ + {/* 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/create-test-open-trade.js b/create-test-open-trade.js new file mode 100644 index 0000000..3df0833 --- /dev/null +++ b/create-test-open-trade.js @@ -0,0 +1,53 @@ +// Create a test open trade to demonstrate real-time monitoring +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function createTestOpenTrade() { + try { + const currentPrice = 190.50 // Simulated SOL price + const stopLoss = currentPrice * 0.98 // 2% below entry + const takeProfit = currentPrice * 1.06 // 6% above entry + + const trade = await prisma.trade.create({ + data: { + userId: 'default-user', + symbol: 'SOLUSD', + side: 'BUY', + amount: 0.5263, // ~$100 position + price: currentPrice, + entryPrice: currentPrice, + status: 'OPEN', // This is the key - OPEN status for monitoring + stopLoss: stopLoss, + takeProfit: takeProfit, + leverage: 1, + isAutomated: true, + tradingMode: 'SIMULATION', + confidence: 85, + marketSentiment: 'BULLISH', + timeframe: '1h', + createdAt: new Date() + } + }) + + console.log('โœ… Created test open trade:', { + id: trade.id.slice(-8), + symbol: trade.symbol, + side: trade.side, + entryPrice: trade.entryPrice, + stopLoss: trade.stopLoss, + takeProfit: trade.takeProfit, + status: trade.status + }) + + console.log('๐Ÿ“Š Price monitor should now detect this trade and start monitoring it!') + console.log('๐Ÿ’ก Check the automation page - it should show under "Active Trades Monitor"') + + } catch (error) { + console.error('โŒ Error creating test trade:', error) + } finally { + await prisma.$disconnect() + } +} + +createTestOpenTrade() diff --git a/lib/ai-learning-status.ts b/lib/ai-learning-status.ts index 74f9145..c6a008c 100644 --- a/lib/ai-learning-status.ts +++ b/lib/ai-learning-status.ts @@ -25,7 +25,7 @@ export async function getAILearningStatus(userId: string): Promise t.status === 'COMPLETED').length - winningTrades = trades.filter(t => (t.profit || 0) > 0).length - } + // Calculate real trade statistics from database + const displayedTrades = trades.length + const completedTrades = trades.filter(t => t.status === 'COMPLETED') + const winningTrades = completedTrades.filter(t => (t.profit || 0) > 0) - // Calculate metrics + // Calculate metrics from real trade data const totalAnalyses = learningData.length const totalTrades = displayedTrades - const winRate = completedTrades > 0 ? (winningTrades / completedTrades) : 0 + const winRate = completedTrades.length > 0 ? (winningTrades.length / completedTrades.length) : 0 - // Calculate average accuracy from learning data (use realistic progression) - let avgAccuracy = 0.50 // Start at 50% - if (totalAnalyses > 0) { - // Gradual improvement based on analyses count - avgAccuracy = Math.min(0.50 + (totalAnalyses * 0.003), 0.85) // Cap at 85% + // Calculate average accuracy based on actual win rate and trade performance + let avgAccuracy = winRate // Use actual win rate as accuracy baseline + if (totalAnalyses > 0 && winRate > 0) { + // Enhance accuracy based on consistency: more analyses with good performance = higher accuracy + const consistencyBonus = Math.min(totalAnalyses / 200, 0.15) // Up to 15% bonus for experience + avgAccuracy = Math.min(winRate + consistencyBonus, 0.95) // Cap at 95% + } else if (totalAnalyses > 0) { + // If no wins yet, base accuracy on analysis experience only + avgAccuracy = Math.min(0.40 + (totalAnalyses * 0.002), 0.60) // Start low, cap at 60% without wins } - // Calculate average confidence (progressive improvement) - let avgConfidence = 60 // Start at 60% - if (totalAnalyses > 0) { - avgConfidence = Math.min(60 + (totalAnalyses * 2), 85) // Cap at 85% + // Calculate confidence based on actual trading performance + let avgConfidence = 50 // Start at 50% + if (completedTrades.length > 0) { + // Base confidence on win rate and number of trades + const winRateConfidence = winRate * 70 // Win rate contributes up to 70% + const experienceBonus = Math.min(completedTrades.length * 2, 30) // Up to 30% for experience + avgConfidence = Math.min(winRateConfidence + experienceBonus, 95) // Cap at 95% + } else if (totalAnalyses > 0) { + // If no completed trades, base on analysis experience only + avgConfidence = Math.min(50 + (totalAnalyses * 0.5), 70) // Cap at 70% without trade results } // Calculate days active @@ -75,43 +73,44 @@ export async function getAILearningStatus(userId: string): Promise= 200 && winRate >= 0.75 && avgAccuracy >= 0.75) { + if (completedTrades.length >= 50 && winRate >= 0.75 && avgAccuracy >= 0.75) { phase = 'EXPERT' phaseDescription = 'Expert-level performance' nextMilestone = 'Maintain excellence' - } else if (totalAnalyses >= 100 && winRate >= 0.70 && avgAccuracy >= 0.70) { + } else if (completedTrades.length >= 20 && winRate >= 0.65 && avgAccuracy >= 0.65) { phase = 'ADVANCED' phaseDescription = 'Advanced pattern mastery' - nextMilestone = 'Achieve 75% accuracy for expert level' - } else if (totalAnalyses >= 50 && winRate >= 0.60) { + nextMilestone = 'Achieve 75% win rate for expert level' + } else if (completedTrades.length >= 10 && winRate >= 0.55) { phase = 'PATTERN_RECOGNITION' phaseDescription = 'Recognizing patterns' - nextMilestone = 'Reach 70% accuracy for advanced level' - } else if (totalAnalyses >= 20) { + nextMilestone = 'Reach 65% win rate for advanced level' + } else if (completedTrades.length >= 5) { phase = 'PATTERN_RECOGNITION' - phaseDescription = 'Recognizing patterns' - nextMilestone = 'Reach 60% win rate for advanced level' + phaseDescription = 'Building trading experience' + nextMilestone = 'Reach 55% win rate with 10+ trades' } - // Determine strengths and improvements + // Determine strengths and improvements based on real performance const strengths: string[] = [] const improvements: string[] = [] - if (avgConfidence > 75) strengths.push('High confidence in analysis') + if (avgConfidence > 70) strengths.push('High confidence in analysis') if (winRate > 0.6) strengths.push('Good trade selection') - if (avgAccuracy > 0.7) strengths.push('Accurate predictions') + if (avgAccuracy > 0.6) strengths.push('Accurate predictions') if (totalAnalyses > 50) strengths.push('Rich learning dataset') - if (totalTrades > 0) strengths.push('Active trading experience') + if (completedTrades.length > 10) strengths.push('Active trading experience') - if (avgConfidence < 70) improvements.push('Build confidence through experience') - if (winRate < 0.7) improvements.push('Improve trade selection criteria') - if (avgAccuracy < 0.7) improvements.push('Enhance prediction accuracy') + if (avgConfidence < 60) improvements.push('Build confidence through experience') + if (winRate < 0.6) improvements.push('Improve trade selection criteria') + if (avgAccuracy < 0.6) improvements.push('Enhance prediction accuracy') if (totalAnalyses < 50) improvements.push('Gather more analysis data') + if (completedTrades.length < 10) improvements.push('Complete more trades for better statistics') // Generate recommendation let recommendation = 'Continue collecting data' diff --git a/lib/automation-service-simple.ts b/lib/automation-service-simple.ts index eacbfe8..a0dfa0f 100644 --- a/lib/automation-service-simple.ts +++ b/lib/automation-service-simple.ts @@ -726,7 +726,7 @@ ${validResults.map(r => `โ€ข ${r.timeframe}: ${r.analysis?.recommendation} (${r. executionPrice, amount: decision.positionSize, direction: decision.direction, - status: 'COMPLETED', + status: 'OPEN', // Trades start as OPEN, not COMPLETED timestamp: new Date(), fees: decision.positionSize * 0.001, // 0.1% fee slippage: slippage * 100 diff --git a/lib/price-monitor.ts b/lib/price-monitor.ts index 6a194ab..5996671 100644 --- a/lib/price-monitor.ts +++ b/lib/price-monitor.ts @@ -142,6 +142,14 @@ class PriceMonitor extends EventEmitter { // Update trade in database with current PnL await this.updateTradeCurrentData(trade.id, currentPrice, monitoring.currentPnL!) + // Check if trade should be closed (TP/SL hit) + const shouldClose = await this.checkTradeClose(trade, currentPrice) + if (shouldClose) { + await this.closeTrade(trade.id, currentPrice, shouldClose.reason) + console.log(`๐Ÿ”’ Trade ${trade.id.slice(-8)} closed: ${shouldClose.reason} at $${currentPrice}`) + continue // Skip further processing for this trade + } + // Check if analysis is needed const needsAnalysis = this.shouldTriggerAnalysis(monitoring) if (needsAnalysis) { @@ -384,6 +392,67 @@ class PriceMonitor extends EventEmitter { } return null } + + // Check if a trade should be closed based on TP/SL + private async checkTradeClose(trade: any, currentPrice: number): Promise<{ reason: string } | null> { + const entryPrice = trade.entryPrice || trade.price + + // Check Take Profit + if (trade.takeProfit) { + const tpHit = (trade.side === 'BUY' && currentPrice >= trade.takeProfit) || + (trade.side === 'SELL' && currentPrice <= trade.takeProfit) + if (tpHit) { + return { reason: 'TAKE_PROFIT' } + } + } + + // Check Stop Loss + if (trade.stopLoss) { + const slHit = (trade.side === 'BUY' && currentPrice <= trade.stopLoss) || + (trade.side === 'SELL' && currentPrice >= trade.stopLoss) + if (slHit) { + return { reason: 'STOP_LOSS' } + } + } + + return null + } + + // Close a trade by updating its status and exit data + private async closeTrade(tradeId: string, exitPrice: number, reason: string): Promise { + try { + const trade = await prisma.trade.findUnique({ where: { id: tradeId } }) + if (!trade) return + + const entryPrice = trade.entryPrice || trade.price + const pnl = this.calculatePnL(trade.side, entryPrice, exitPrice, trade.amount) + const tradingAmount = trade.amount * entryPrice // Estimate trading amount + const pnlPercent = ((pnl / tradingAmount) * 100) + + await prisma.trade.update({ + where: { id: tradeId }, + data: { + status: 'COMPLETED', + exitPrice: exitPrice, + closedAt: new Date(), + profit: pnl, + pnlPercent: pnlPercent, + outcome: pnl > 0 ? 'WIN' : pnl < 0 ? 'LOSS' : 'BREAK_EVEN' + } + }) + } catch (error) { + console.error('Error closing trade:', error) + } + } + + // Calculate P&L for a trade + private calculatePnL(side: string, entryPrice: number, exitPrice: number, amount: number): number { + if (side === 'BUY') { + return (exitPrice - entryPrice) * amount + } else { + return (entryPrice - exitPrice) * amount + } + } } export const priceMonitor = PriceMonitor.getInstance() diff --git a/prisma/prisma/dev.db b/prisma/prisma/dev.db index b3b7f36..55a90b7 100644 Binary files a/prisma/prisma/dev.db and b/prisma/prisma/dev.db differ diff --git a/remove-demo-trades.js b/remove-demo-trades.js new file mode 100644 index 0000000..5f18483 --- /dev/null +++ b/remove-demo-trades.js @@ -0,0 +1,47 @@ +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function removeDemoTrades() { + try { + console.log('๐Ÿงน Removing demo trades...') + + // Remove demo trades + const deletedTrades = await prisma.trade.deleteMany({ + where: { + userId: 'demo-user', + tradingMode: 'SIMULATION', + isAutomated: true + } + }) + + console.log(`โœ… Removed ${deletedTrades.count} demo trades`) + + // Optionally remove demo user if no other data + const remainingUserData = await prisma.trade.count({ + where: { userId: 'demo-user' } + }) + + if (remainingUserData === 0) { + await prisma.user.delete({ + where: { id: 'demo-user' } + }) + console.log('โœ… Removed demo user (no remaining data)') + } else { + console.log(`โ„น๏ธ Demo user kept (has ${remainingUserData} other records)`) + } + + console.log('๐ŸŽ‰ Demo data cleanup completed!') + + } catch (error) { + console.error('โŒ Error removing demo trades:', error) + } finally { + await prisma.$disconnect() + } +} + +if (require.main === module) { + removeDemoTrades() +} + +module.exports = { removeDemoTrades }