'use client' import React, { useState, useEffect } from 'react' export default function PaperTradingPage() { const [paperBalance, setPaperBalance] = useState(1000) // Start with $1000 paper money const [paperTrades, setPaperTrades] = useState([]) const [currentAnalysis, setCurrentAnalysis] = useState(null) const [loading, setLoading] = useState(false) const [symbol, setSymbol] = useState('SOLUSD') const [timeframe, setTimeframe] = useState('240') // 4H default for cost efficiency const [analysisHistory, setAnalysisHistory] = useState([]) const [usageStats, setUsageStats] = useState({ dailyCount: 0, estimatedDailyCost: 0 }) const [lastAnalysisTime, setLastAnalysisTime] = useState(null) // User's selected timeframes (cost-effective) const selectedTimeframes = [ { label: '5m', value: '5', riskLevel: 'HIGH', maxDaily: 10, cost: 'High' }, { label: '30m', value: '30', riskLevel: 'MEDIUM', maxDaily: 20, cost: 'Medium' }, { label: '1h', value: '60', riskLevel: 'MEDIUM', maxDaily: 15, cost: 'Medium' }, { label: '4h', value: '240', riskLevel: 'LOW', maxDaily: 8, cost: 'Low' } ] // Paper trading settings const [settings, setSettings] = useState({ riskPerTrade: 1.0, // 1% risk per trade enableAntiChasing: true, minConfidence: 80, // High confidence required requireMultiConfirmation: true, paperMode: true }) useEffect(() => { // Load paper trading history from localStorage const savedTrades = localStorage.getItem('paperTrades') if (savedTrades) { setPaperTrades(JSON.parse(savedTrades)) } const savedBalance = localStorage.getItem('paperBalance') if (savedBalance) { setPaperBalance(parseFloat(savedBalance)) } const savedHistory = localStorage.getItem('analysisHistory') if (savedHistory) { setAnalysisHistory(JSON.parse(savedHistory)) } }, []) // Save to localStorage whenever trades or balance changes useEffect(() => { localStorage.setItem('paperTrades', JSON.stringify(paperTrades)) localStorage.setItem('paperBalance', paperBalance.toString()) }, [paperTrades, paperBalance]) useEffect(() => { localStorage.setItem('analysisHistory', JSON.stringify(analysisHistory)) }, [analysisHistory]) const runEnhancedAnalysis = async () => { // Cost control check const now = Date.now() if (lastAnalysisTime && (now - lastAnalysisTime) < 300000) { // 5 minute cooldown const remainingTime = Math.ceil((300000 - (now - lastAnalysisTime)) / 1000 / 60) alert(`⏳ Cooldown active. Wait ${remainingTime} minutes to prevent excessive OpenAI costs.`) return } // Daily limit check const timeframeConfig = selectedTimeframes.find(tf => tf.value === timeframe) if (usageStats.dailyCount >= (timeframeConfig?.maxDaily || 10)) { alert(`📊 Daily limit reached for ${timeframeConfig?.label} (${timeframeConfig?.maxDaily} analyses/day). This prevents excessive OpenAI costs.`) return } setLoading(true) try { console.log('🛡️ Running Enhanced Anti-Chasing Analysis...') console.log(`💰 Current usage: ${usageStats.dailyCount} analyses today (~$${usageStats.estimatedDailyCost.toFixed(3)} cost)`) // First, capture fresh screenshots const screenshotResponse = await fetch('/api/enhanced-screenshot', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ symbol, timeframe, layouts: ['ai', 'diy'], analyze: true }) }) if (!screenshotResponse.ok) { throw new Error('Failed to capture screenshots') } const screenshotData = await screenshotResponse.json() console.log('📸 Screenshots captured:', screenshotData.screenshots?.length || 0) // Then run enhanced anti-chasing analysis const analysisResponse = await fetch('/api/enhanced-anti-chasing', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ symbol, timeframe, layouts: ['ai', 'diy'], currentBalance: paperBalance }) }) if (!analysisResponse.ok) { throw new Error('Enhanced analysis failed') } const analysisData = await analysisResponse.json() console.log('🧠 Enhanced analysis complete:', analysisData.data) const analysis = { timestamp: new Date().toISOString(), symbol, timeframe, ...analysisData.data.analysis, riskAssessment: analysisData.data.riskAssessment, tradeDecision: analysisData.data.tradeDecision, antiChasingInsights: analysisData.data.antiChasingInsights, screenshots: screenshotData.screenshots || [] } setCurrentAnalysis(analysis) setLastAnalysisTime(now) // Update usage stats setUsageStats(prev => ({ dailyCount: prev.dailyCount + 1, estimatedDailyCost: (prev.dailyCount + 1) * 0.006 // ~$0.006 per analysis })) // Add to history setAnalysisHistory(prev => [analysis, ...prev.slice(0, 9)]) // Keep last 10 } catch (error) { console.error('❌ Analysis failed:', error) alert('Analysis failed: ' + error.message) } finally { setLoading(false) } } const executePaperTrade = (signal) => { if (!currentAnalysis) return const trade = { id: Date.now(), timestamp: new Date().toISOString(), symbol: currentAnalysis.symbol, timeframe: currentAnalysis.timeframe, side: signal, entryPrice: currentAnalysis.entry?.price || 100, stopLoss: currentAnalysis.stopLoss?.price, takeProfit: currentAnalysis.takeProfits?.tp1?.price, confidence: currentAnalysis.confidence, reasoning: currentAnalysis.reasoning, riskReward: currentAnalysis.riskToReward, status: 'OPEN', momentumStatus: currentAnalysis.momentumStatus?.type, entryQuality: currentAnalysis.entryQuality?.score, riskAssessment: currentAnalysis.riskAssessment } // Calculate position size based on risk management const riskAmount = paperBalance * (settings.riskPerTrade / 100) const stopDistance = Math.abs(trade.entryPrice - (trade.stopLoss || trade.entryPrice * 0.95)) trade.positionSize = Math.min(riskAmount / stopDistance, paperBalance * 0.1) // Max 10% of balance setPaperTrades(prev => [trade, ...prev]) console.log('📄 Paper trade executed:', trade) alert(`Paper trade executed: ${signal} ${trade.symbol} at $${trade.entryPrice}`) } const closePaperTrade = (tradeId, exitPrice, reason = 'Manual close') => { setPaperTrades(prev => prev.map(trade => { if (trade.id === tradeId && trade.status === 'OPEN') { const pnl = trade.side === 'BUY' ? (exitPrice - trade.entryPrice) * (trade.positionSize / trade.entryPrice) : (trade.entryPrice - exitPrice) * (trade.positionSize / trade.entryPrice) setPaperBalance(current => current + pnl) return { ...trade, status: 'CLOSED', exitPrice, exitTime: new Date().toISOString(), pnl, exitReason: reason } } return trade })) } const resetPaperTrading = () => { if (confirm('Reset all paper trading data? This cannot be undone.')) { setPaperBalance(1000) setPaperTrades([]) setAnalysisHistory([]) localStorage.removeItem('paperTrades') localStorage.removeItem('paperBalance') localStorage.removeItem('analysisHistory') } } const openTrades = paperTrades.filter(t => t.status === 'OPEN') const closedTrades = paperTrades.filter(t => t.status === 'CLOSED') const totalPnL = closedTrades.reduce((sum, trade) => sum + (trade.pnl || 0), 0) const winRate = closedTrades.length > 0 ? (closedTrades.filter(t => (t.pnl || 0) > 0).length / closedTrades.length * 100).toFixed(1) : 0 return (
{/* Header */}

📄 Enhanced Paper Trading

Paper Balance

= 1000 ? 'text-green-400' : 'text-red-400'}`}> ${paperBalance.toFixed(2)}

Total P&L

= 0 ? 'text-green-400' : 'text-red-400'}`}> ${totalPnL.toFixed(2)}

Win Rate

{winRate}%

Open Trades

{openTrades.length}

Closed Trades

{closedTrades.length}

Wins

{closedTrades.filter(t => (t.pnl || 0) > 0).length}

Losses

{closedTrades.filter(t => (t.pnl || 0) < 0).length}

{/* Enhanced Analysis Panel */}

🛡️ Enhanced Anti-Chasing Analysis

{/* Cost Control Warning */}

💰 Cost Control Active

Today: {usageStats.dailyCount} analyses (~${usageStats.estimatedDailyCost.toFixed(3)})

• 5-minute cooldown between analyses

• Daily limits per timeframe prevent overspending

• Manual trigger only (no auto-run)

Selected Timeframe Limits:

{selectedTimeframes.map(tf => (

{tf.label}: {tf.maxDaily}/day max

))}
{/* Status indicators */}
{isOnCooldown && ( ⏱️ Cooldown: {Math.ceil(cooldownRemaining / 1000)}s )} {usageStats.hitDailyLimit && ( 🚫 Daily limit reached )}
Cost: ~$0.006 per analysis
{/* Current Analysis Results */} {currentAnalysis && (

📊 Latest Analysis Results

Recommendation

{currentAnalysis.recommendation}

Confidence: {currentAnalysis.confidence}%

Momentum Status

{currentAnalysis.momentumStatus?.type || 'UNKNOWN'}

Direction: {currentAnalysis.momentumStatus?.direction || 'N/A'}

Entry Quality

= 80 ? 'text-green-400' : (currentAnalysis.entryQuality?.score || 0) >= 60 ? 'text-yellow-400' : 'text-red-400' }`}> {currentAnalysis.entryQuality?.score || 0}/100

Risk: {currentAnalysis.entryQuality?.riskLevel || 'Unknown'}

{/* Trading Levels */} {currentAnalysis.entry && (

Entry Price

${currentAnalysis.entry.price}

{currentAnalysis.entry.rationale}

{currentAnalysis.stopLoss && (

Stop Loss

${currentAnalysis.stopLoss.price}

{currentAnalysis.stopLoss.rationale}

)} {currentAnalysis.takeProfits?.tp1 && (

Take Profit

${currentAnalysis.takeProfits.tp1.price}

R:R {currentAnalysis.riskToReward || 'N/A'}

)}
)} {/* Anti-Chasing Insights */} {currentAnalysis.antiChasingInsights && (

🛡️ Anti-Chasing Insights

Momentum: {currentAnalysis.momentumStatus?.type}

Timeframe Alignment: {currentAnalysis.timeframeAlignment?.alignment}

Entry Quality: {currentAnalysis.entryQuality?.score}/100

Reversal Probability: {currentAnalysis.momentumStatus?.reversalProbability || 'N/A'}%

)} {/* Trade Decision */} {currentAnalysis.tradeDecision && (

Risk Management Decision

{currentAnalysis.tradeDecision.allowed ? '✅ TRADE APPROVED' : '❌ TRADE REJECTED'}

{currentAnalysis.tradeDecision.reason}

)} {/* Action Buttons */} {currentAnalysis.recommendation !== 'HOLD' && currentAnalysis.tradeDecision?.allowed && (
)} {/* Reasoning */}

Analysis Reasoning

{currentAnalysis.reasoning}

)} {/* Open Trades */} {openTrades.length > 0 && (

📊 Open Paper Trades

{openTrades.map(trade => (
{trade.side} {trade.symbol} ${trade.entryPrice} Size: ${trade.positionSize?.toFixed(2)} {trade.momentumStatus && ( {trade.momentumStatus} )}
Entry: {new Date(trade.timestamp).toLocaleString()} | Confidence: {trade.confidence}% | Quality: {trade.entryQuality}/100
))}
)} {/* Trade History */} {closedTrades.length > 0 && (

📈 Paper Trade History

{closedTrades.slice(0, 20).map(trade => (
= 0 ? 'bg-green-900/20 border-green-500' : 'bg-red-900/20 border-red-500' }`}>
{trade.side} {trade.symbol} ${trade.entryPrice} → ${trade.exitPrice} = 0 ? 'text-green-400' : 'text-red-400' }`}> ${(trade.pnl || 0).toFixed(2)}
{new Date(trade.timestamp).toLocaleDateString()}
Confidence: {trade.confidence}% | Quality: {trade.entryQuality}/100 | {trade.exitReason}
))}
)}
) }