Files
trading_bot_v3/app/safe-paper-trading/page.js
mindesbunister 284e1c8b8c feat: fix Safe Paper Trading display formatting and API sync
- Fixed field mapping between API and frontend (amount→positionSize, entry→entryPrice, createdAt→timestamp)
- Updated API sync function to properly convert API trade format to frontend format
- Resolved display issues: 'Invalid Date', missing entry price, missing trade size
- Added trade monitoring system and automation improvements
- Enhanced automation with simple-automation.js for reliable 24/7 operation
- Working automation now detecting 85% confidence BUY signals and executing trades
2025-08-07 16:55:41 +02:00

1909 lines
83 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import { useState, useEffect } from 'react'
// Available timeframes for analysis (matching automation-v2 format)
const timeframes = [
{ label: '5m', value: '5' },
{ label: '15m', value: '15' },
{ label: '30m', value: '30' },
{ label: '1h', value: '60' },
{ label: '2h', value: '120' },
{ label: '4h', value: '240' },
{ label: '1d', value: 'D' },
]
// Intelligent delay mapping based on timeframe (optimize ChatGPT budget)
const ANALYSIS_DELAYS = {
'5': 5 * 60 * 1000, // 5m chart: analyze every 5 minutes
'15': 15 * 60 * 1000, // 15m chart: analyze every 15 minutes
'30': 30 * 60 * 1000, // 30m chart: analyze every 30 minutes
'60': 60 * 60 * 1000, // 1h chart: analyze every 1 hour
'120': 2 * 60 * 60 * 1000, // 2h chart: analyze every 2 hours
'240': 4 * 60 * 60 * 1000, // 4h chart: analyze every 4 hours
'D': 24 * 60 * 60 * 1000, // 1d chart: analyze once per day
}
export default function SafePaperTradingPage() {
const [symbol, setSymbol] = useState('SOLUSD')
const [selectedTimeframes, setSelectedTimeframes] = useState(['60']) // Default to 1h
const [loading, setLoading] = useState(false)
const [currentAnalysis, setCurrentAnalysis] = useState(null)
const [paperBalance, setPaperBalance] = useState(1000)
const [paperTrades, setPaperTrades] = useState([])
const [analysisHistory, setAnalysisHistory] = useState([])
const [error, setError] = useState(null)
const [learningInsights, setLearningInsights] = useState(null)
const [showDetailedAnalysis, setShowDetailedAnalysis] = useState(false)
const [continuousLearning, setContinuousLearning] = useState(false)
const [autoExecuteTrades, setAutoExecuteTrades] = useState(false) // New: Auto-execute trades based on AI recommendations
const [learningInterval, setLearningInterval] = useState(null)
const [lastAnalysisTime, setLastAnalysisTime] = useState(null)
const [nextAnalysisTime, setNextAnalysisTime] = useState(null)
const [countdownTimer, setCountdownTimer] = useState(null)
const [timeRemaining, setTimeRemaining] = useState(0)
// Load persisted analysis data on component mount
useEffect(() => {
const loadPersistedData = () => {
try {
const savedAnalysis = localStorage.getItem('safePaperTrading_currentAnalysis')
const savedTrades = localStorage.getItem('safePaperTrading_paperTrades')
const savedBalance = localStorage.getItem('safePaperTrading_paperBalance')
const savedHistory = localStorage.getItem('safePaperTrading_analysisHistory')
const savedLearningInsights = localStorage.getItem('safePaperTrading_learningInsights')
const savedContinuousLearning = localStorage.getItem('safePaperTrading_continuousLearning')
const savedAutoExecute = localStorage.getItem('safePaperTrading_autoExecute')
if (savedAnalysis) {
const parsedAnalysis = JSON.parse(savedAnalysis)
// Check if the saved analysis is stale (older than 2 hours)
const analysisAge = Date.now() - new Date(parsedAnalysis.timestamp).getTime()
const twoHours = 2 * 60 * 60 * 1000
if (analysisAge > twoHours) {
console.log('📂 Found stale analysis data (>2 hours old), will fetch fresh data')
localStorage.removeItem('safePaperTrading_currentAnalysis')
// Trigger fresh analysis after component loads
setTimeout(() => {
console.log('🔄 Fetching fresh analysis to replace stale data')
runSafeAnalysis(false)
}, 5000)
} else {
setCurrentAnalysis(parsedAnalysis)
console.log('📂 Restored recent analysis from localStorage')
}
} else {
// No saved analysis, fetch fresh data
setTimeout(() => {
console.log('🔄 No saved analysis found, fetching fresh data')
runSafeAnalysis(false)
}, 3000)
}
if (savedTrades) {
const parsedTrades = JSON.parse(savedTrades)
setPaperTrades(parsedTrades)
console.log(`📂 Restored ${parsedTrades.length} paper trades`)
}
if (savedBalance) {
const parsedBalance = parseFloat(savedBalance)
setPaperBalance(parsedBalance)
console.log(`📂 Restored paper balance: $${parsedBalance}`)
}
if (savedHistory) {
const parsedHistory = JSON.parse(savedHistory)
setAnalysisHistory(parsedHistory)
console.log(`📂 Restored ${parsedHistory.length} analysis history entries`)
}
if (savedLearningInsights) {
const parsedInsights = JSON.parse(savedLearningInsights)
setLearningInsights(parsedInsights)
console.log('📂 Restored learning insights from localStorage')
}
if (savedContinuousLearning === 'true') {
console.log('📂 Found continuous learning was active - restarting...')
setContinuousLearning(true)
// Restart continuous learning after a short delay to ensure component is ready
setTimeout(() => {
console.log('<27> Restarting continuous learning from localStorage')
startContinuousLearning()
}, 3000) // Increased delay to ensure everything is loaded
}
} catch (error) {
console.error('⚠️ Error loading persisted data:', error)
// Clear corrupted data
localStorage.removeItem('safePaperTrading_currentAnalysis')
localStorage.removeItem('safePaperTrading_paperTrades')
localStorage.removeItem('safePaperTrading_paperBalance')
localStorage.removeItem('safePaperTrading_analysisHistory')
localStorage.removeItem('safePaperTrading_learningInsights')
localStorage.removeItem('safePaperTrading_continuousLearning')
}
}
loadPersistedData()
// Load auto-execute setting
try {
const savedAutoExecute = localStorage.getItem('safePaperTrading_autoExecute')
if (savedAutoExecute === 'true') {
console.log('📂 Found auto-execute was enabled - restoring...')
setAutoExecuteTrades(true)
}
} catch (error) {
console.error('⚠️ Error loading auto-execute setting:', error)
}
// Check if continuous learning should be active
const checkContinuousLearningState = () => {
try {
const savedContinuousLearning = localStorage.getItem('safePaperTrading_continuousLearning')
console.log('🔍 Checking continuous learning state:', savedContinuousLearning)
if (savedContinuousLearning === 'true') {
console.log('🔄 Restoring continuous learning state...')
setContinuousLearning(true)
// Force restart continuous learning immediately
setTimeout(() => {
console.log('🎓 Starting continuous learning from restored state')
startContinuousLearning()
}, 1000) // Reduced delay
} else {
console.log('💡 No continuous learning state found - user needs to start manually')
}
} catch (error) {
console.error('⚠️ Error checking continuous learning state:', error)
}
}
// Force enable learning for testing - DEBUG FUNCTION
const forceEnableLearning = () => {
console.log('🔧 FORCE ENABLING CONTINUOUS LEARNING...')
localStorage.setItem('safePaperTrading_continuousLearning', 'true')
setContinuousLearning(true)
setTimeout(() => {
console.log('🎓 Force starting continuous learning')
startContinuousLearning()
}, 500)
console.log('✅ Continuous learning forcefully enabled')
}
// Check state immediately
checkContinuousLearningState()
// Expose force enable function to browser console for debugging
if (typeof window !== 'undefined') {
window.forceEnableLearning = forceEnableLearning
console.log('🔧 Debug function exposed: window.forceEnableLearning()')
}
// Also check after a short delay to ensure everything is loaded
setTimeout(checkContinuousLearningState, 2000)
}, [])
// Persist analysis data whenever it changes
useEffect(() => {
if (currentAnalysis) {
try {
localStorage.setItem('safePaperTrading_currentAnalysis', JSON.stringify(currentAnalysis))
console.log('💾 Persisted current analysis to localStorage')
} catch (error) {
console.error('⚠️ Error persisting current analysis:', error)
}
}
}, [currentAnalysis])
useEffect(() => {
if (paperTrades.length >= 0) { // Always persist, even empty array
try {
localStorage.setItem('safePaperTrading_paperTrades', JSON.stringify(paperTrades))
console.log(`💾 Persisted ${paperTrades.length} paper trades`)
} catch (error) {
console.error('⚠️ Error persisting paper trades:', error)
}
}
}, [paperTrades])
useEffect(() => {
try {
localStorage.setItem('safePaperTrading_paperBalance', paperBalance.toString())
console.log(`💾 Persisted paper balance: $${paperBalance}`)
} catch (error) {
console.error('⚠️ Error persisting paper balance:', error)
}
}, [paperBalance])
useEffect(() => {
if (learningInsights) {
try {
localStorage.setItem('safePaperTrading_learningInsights', JSON.stringify(learningInsights))
console.log('💾 Persisted learning insights to localStorage')
} catch (error) {
console.error('⚠️ Error persisting learning insights:', error)
}
}
}, [learningInsights])
// Persist continuous learning state
useEffect(() => {
try {
localStorage.setItem('safePaperTrading_continuousLearning', continuousLearning.toString())
console.log(`💾 Persisted continuous learning state: ${continuousLearning}`)
} catch (error) {
console.error('⚠️ Error persisting continuous learning state:', error)
}
}, [continuousLearning])
// Persist auto-execute setting
useEffect(() => {
try {
localStorage.setItem('safePaperTrading_autoExecute', autoExecuteTrades.toString())
console.log(`💾 Persisted auto-execute setting: ${autoExecuteTrades}`)
} catch (error) {
console.error('⚠️ Error persisting auto-execute setting:', error)
}
}, [autoExecuteTrades])
// Live countdown timer for continuous learning
useEffect(() => {
if (continuousLearning && nextAnalysisTime) {
// Clear any existing countdown timer
if (countdownTimer) {
clearInterval(countdownTimer)
}
// Create new countdown timer that updates every second
const countdown = setInterval(() => {
const remaining = nextAnalysisTime - Date.now()
if (remaining <= 0) {
setTimeRemaining(0)
} else {
setTimeRemaining(remaining)
}
}, 1000)
setCountdownTimer(countdown)
// Initial calculation
const remaining = nextAnalysisTime - Date.now()
setTimeRemaining(remaining > 0 ? remaining : 0)
return () => {
if (countdown) {
clearInterval(countdown)
}
}
} else {
// Clear countdown when not in continuous learning
if (countdownTimer) {
clearInterval(countdownTimer)
setCountdownTimer(null)
}
setTimeRemaining(0)
}
}, [continuousLearning, nextAnalysisTime])
// Clean up countdown on unmount
useEffect(() => {
return () => {
if (countdownTimer) {
clearInterval(countdownTimer)
}
}
}, [])
// Health check for continuous learning - ensure it's actually running
useEffect(() => {
if (continuousLearning) {
const healthCheck = setInterval(() => {
if (!learningInterval) {
console.warn('⚠️ HEALTH CHECK: Continuous learning is ON but interval is missing - restarting...')
restartContinuousLearning()
} else {
console.log('✅ HEALTH CHECK: Continuous learning interval is active')
}
}, 5 * 60 * 1000) // Check every 5 minutes
return () => clearInterval(healthCheck)
}
}, [continuousLearning, learningInterval])
// SAFETY: Only these timeframes allowed in paper trading
const safeTimeframes = timeframes.map(tf => ({
...tf,
riskLevel: tf.value === '5' || tf.value === '15' ? 'HIGH' :
tf.value === '30' || tf.value === '60' ? 'MEDIUM' : 'LOW'
}))
const settings = {
riskPerTrade: 1.0,
paperMode: true, // ALWAYS true - cannot be changed
isolatedMode: true // ALWAYS true - completely isolated
}
const toggleTimeframe = (timeframe) => {
setSelectedTimeframes(prev =>
prev.includes(timeframe)
? prev.filter(tf => tf !== timeframe)
: [...prev, timeframe]
)
}
const calculateOptimalDelay = () => {
if (selectedTimeframes.length === 0) return 60 * 60 * 1000 // Default 1 hour
// Use the shortest timeframe as base, but not too frequent for budget optimization
const shortestTf = selectedTimeframes.reduce((shortest, current) => {
const currentDelay = ANALYSIS_DELAYS[current] || 60 * 60 * 1000
const shortestDelay = ANALYSIS_DELAYS[shortest] || 60 * 60 * 1000
return currentDelay < shortestDelay ? current : shortest
})
// Minimum 10 minutes delay to protect ChatGPT budget
return Math.max(ANALYSIS_DELAYS[shortestTf] || 60 * 60 * 1000, 10 * 60 * 1000)
}
// Format countdown time for display
const formatCountdown = (milliseconds) => {
if (milliseconds <= 0) return 'Running soon...'
const totalSeconds = Math.ceil(milliseconds / 1000)
const hours = Math.floor(totalSeconds / 3600)
const minutes = Math.floor((totalSeconds % 3600) / 60)
const seconds = totalSeconds % 60
if (hours > 0) {
return `${hours}h ${minutes}m ${seconds}s`
} else if (minutes > 0) {
return `${minutes}m ${seconds}s`
} else {
return `${seconds}s`
}
}
const startContinuousLearning = () => {
if (learningInterval) {
clearInterval(learningInterval)
}
const delay = calculateOptimalDelay()
console.log(`🎓 Starting continuous learning with ${delay / 60000} minute intervals`)
// Run first analysis immediately for faster feedback
setTimeout(async () => {
console.log('🔄 IMMEDIATE: Running first continuous learning analysis')
console.log('📚 Running immediate learning analysis (paper trading mode)')
try {
await runSafeAnalysis(true) // Mark as continuous learning
} catch (error) {
console.error('❌ Error in immediate analysis:', error)
}
}, 5000) // 5 seconds delay for immediate feedback
const interval = setInterval(async () => {
console.log('🔄 Continuous learning cycle triggered')
console.log(`📊 Current time: ${new Date().toLocaleTimeString()}`)
// For safe paper trading, always run analysis regardless of positions
// (since it's completely isolated and for learning purposes)
console.log('📚 Running scheduled learning analysis (paper trading mode)')
try {
await runSafeAnalysis(true) // Mark as continuous learning
} catch (error) {
console.error('❌ Error in continuous learning cycle:', error)
// Set next time even if there's an error to prevent stopping
setNextAnalysisTime(Date.now() + delay)
}
}, delay)
setLearningInterval(interval)
setNextAnalysisTime(Date.now() + 5000) // Show immediate next time (5 seconds)
console.log(`🎓 Continuous learning started - next analysis in 5 seconds, then every ${delay / 60000} minutes`)
}
const stopContinuousLearning = () => {
if (learningInterval) {
clearInterval(learningInterval)
setLearningInterval(null)
setNextAnalysisTime(null)
console.log('🛑 Continuous learning stopped')
}
}
const restartContinuousLearning = () => {
console.log('🔄 Restarting continuous learning...')
stopContinuousLearning()
// Small delay to ensure cleanup
setTimeout(() => {
startContinuousLearning()
console.log('✅ Continuous learning restarted successfully')
}, 1000)
}
useEffect(() => {
// Load paper trading data from localStorage using consistent keys
// Check both old and new key patterns for backward compatibility
const savedTrades = localStorage.getItem('safePaperTrading_paperTrades') || localStorage.getItem('safePaperTrades')
const savedBalance = localStorage.getItem('safePaperTrading_paperBalance') || localStorage.getItem('safePaperBalance')
if (savedTrades) {
setPaperTrades(JSON.parse(savedTrades))
console.log('📂 Restored paper trades from localStorage')
}
if (savedBalance) {
setPaperBalance(parseFloat(savedBalance))
console.log('📂 Restored paper balance from localStorage')
}
// Sync with API trades (from automation)
const syncApiTrades = async () => {
try {
console.log('🔄 Syncing trades from API...')
const response = await fetch('/api/safe-paper-trading/trades')
if (response.ok) {
const data = await response.json()
if (data.success && data.trades.length > 0) {
console.log(`📈 Found ${data.trades.length} API trades, syncing with localStorage...`)
// Get existing localStorage trades
const existingTrades = JSON.parse(localStorage.getItem('safePaperTrading_paperTrades') || '[]')
// Convert API trades to frontend format and filter out existing ones
const existingIds = new Set(existingTrades.map(t => t.id))
const newTrades = data.trades
.filter(t => !existingIds.has(t.id))
.map(apiTrade => ({
id: apiTrade.id,
symbol: apiTrade.symbol,
side: apiTrade.side,
positionSize: apiTrade.amount, // Map amount to positionSize
entryPrice: apiTrade.entry, // Map entry to entryPrice
confidence: apiTrade.confidence,
reasoning: apiTrade.reasoning,
source: apiTrade.source,
status: apiTrade.status,
timestamp: apiTrade.createdAt, // Map createdAt to timestamp
pnl: apiTrade.pnl || 0,
fees: apiTrade.fees || 0
}))
if (newTrades.length > 0) {
const combinedTrades = [...existingTrades, ...newTrades]
setPaperTrades(combinedTrades)
localStorage.setItem('safePaperTrading_paperTrades', JSON.stringify(combinedTrades))
// Update balance based on new trades
const additionalValue = newTrades.reduce((sum, trade) => {
return sum + (trade.side === 'BUY' ? -trade.positionSize : trade.positionSize)
}, 0)
const newBalance = paperBalance + additionalValue
setPaperBalance(newBalance)
localStorage.setItem('safePaperTrading_paperBalance', newBalance.toString())
console.log(`✅ Synced ${newTrades.length} new trades from API`)
} else {
console.log('📊 All API trades already in localStorage')
}
} else {
console.log('📊 No API trades found')
}
}
} catch (error) {
console.log('❌ Failed to sync API trades:', error.message)
}
}
// Sync API trades after loading localStorage
syncApiTrades()
// Fetch AI learning status
fetchLearningStatus()
// Cleanup continuous learning on unmount
return () => {
if (learningInterval) {
clearInterval(learningInterval)
}
}
}, [])
// Update continuous learning when timeframes change
useEffect(() => {
if (continuousLearning) {
stopContinuousLearning()
startContinuousLearning()
}
}, [selectedTimeframes])
// Save to localStorage whenever data changes - use consistent prefixed keys
useEffect(() => {
localStorage.setItem('safePaperTrading_paperTrades', JSON.stringify(paperTrades))
localStorage.setItem('safePaperTrading_paperBalance', paperBalance.toString())
// Also save to old keys for backward compatibility (temporarily)
localStorage.setItem('safePaperTrades', JSON.stringify(paperTrades))
localStorage.setItem('safePaperBalance', paperBalance.toString())
}, [paperTrades, paperBalance])
const runSafeAnalysis = async (isContinuous = false) => {
console.log(`🔄 ${isContinuous ? 'CONTINUOUS LEARNING' : 'BUTTON CLICKED'}: Starting safe analysis...`)
console.log(`🎯 Analysis Type: ${isContinuous ? 'CONTINUOUS LEARNING' : 'MANUAL'} for ${symbol}`)
console.log(`⏰ Current time: ${new Date().toLocaleString()}`)
console.log(`📊 Selected timeframes: ${selectedTimeframes.join(', ')}`)
if (isContinuous) {
console.log(`🎓 This is a CONTINUOUS LEARNING cycle - automatic analysis`)
}
console.log(`📊 Selected timeframes: ${selectedTimeframes.join(', ')}`)
setLoading(true)
setError(null)
setLastAnalysisTime(Date.now())
try {
console.log('📄 SAFE PAPER TRADING: Starting isolated analysis...')
console.log('📋 Request data:', {
symbol,
selectedTimeframes,
mode: 'PAPER_ONLY',
paperTrading: true,
isolatedMode: true,
isContinuous
})
console.log(`🌐 Making API call to /api/paper-trading-safe...`)
// SAFETY: Only call the isolated paper trading API
const response = await fetch('/api/paper-trading-safe', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
symbol,
selectedTimeframes,
mode: 'PAPER_ONLY', // REQUIRED for safety
paperTrading: true,
isolatedMode: true,
isContinuous
})
})
console.log('📡 Response status:', response.status)
console.log('📡 Response ok:', response.ok)
if (!response.ok) {
const errorText = await response.text()
console.error('❌ Response error:', errorText)
throw new Error(`Analysis failed: ${response.status} - ${errorText}`)
}
const result = await response.json()
console.log('📊 Full API result:', result)
if (!result.success) {
throw new Error(result.error || 'Analysis failed')
}
console.log('✅ SAFE ANALYSIS COMPLETE:', result.analysis.recommendation)
const analysisData = {
...result.analysis,
timeframes: selectedTimeframes,
analysisType: isContinuous ? 'CONTINUOUS_LEARNING' : 'MANUAL'
}
setCurrentAnalysis(analysisData)
// Add to analysis history with timestamp
const historyEntry = {
...analysisData,
timestamp: new Date().toISOString(),
symbol: symbol,
timeframes: selectedTimeframes,
analysisId: `analysis_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
}
// Keep only last 10 analyses in history
setAnalysisHistory(prev => {
const updated = [historyEntry, ...prev].slice(0, 10)
try {
localStorage.setItem('safePaperTrading_analysisHistory', JSON.stringify(updated))
console.log(`💾 Persisted ${updated.length} analysis history entries`)
} catch (error) {
console.error('⚠️ Error persisting analysis history:', error)
}
return updated
})
// Update next analysis time for both manual and continuous learning
if (continuousLearning) {
const delay = calculateOptimalDelay()
const nextTime = Date.now() + delay
setNextAnalysisTime(nextTime)
console.log(`⏰ Next analysis scheduled for: ${new Date(nextTime).toLocaleString()}`)
console.log(`⏱️ Delay: ${delay / 60000} minutes`)
}
// AUTO-EXECUTE TRADES: If auto-execute is enabled and we have a strong recommendation, execute the trade
console.log('🔍 Checking auto-execute conditions:', {
autoExecuteTrades,
recommendation: analysisData.recommendation,
confidence: analysisData.confidence,
hasAnalysisData: !!analysisData
})
if (autoExecuteTrades && analysisData.recommendation && analysisData.confidence >= 60) {
const recommendation = analysisData.recommendation.toUpperCase()
if (recommendation === 'BUY' || recommendation === 'SELL') {
console.log(`🤖 AUTO-EXECUTE: ${recommendation} signal with ${analysisData.confidence}% confidence`)
// Wait a moment for the analysis to fully update, then execute
setTimeout(() => {
try {
executeSafePaperTrade(recommendation)
console.log(`✅ AUTO-EXECUTED: ${recommendation} trade based on AI recommendation`)
} catch (error) {
console.error('❌ Auto-execute error:', error)
}
}, 1000)
} else {
console.log(`💡 AUTO-EXECUTE: HOLD signal (${recommendation}) - no trade executed`)
}
} else if (autoExecuteTrades) {
console.log(`💡 AUTO-EXECUTE: Recommendation ${analysisData.recommendation} with ${analysisData.confidence}% confidence does not meet execution criteria (need BUY/SELL with ≥60% confidence)`)
} else {
console.log(`🔍 AUTO-EXECUTE: Disabled or no valid recommendation`)
}
} catch (error) {
console.error('❌ Safe analysis error:', error)
console.error('❌ Error stack:', error.stack)
setError(error.message)
} finally {
setLoading(false)
console.log('🏁 Analysis complete, loading set to false')
}
}
const executeSafePaperTrade = (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,
status: 'OPEN',
momentumStatus: currentAnalysis.momentumStatus?.type,
entryQuality: currentAnalysis.entryQuality?.score,
paperMode: true,
safeMode: true
}
// 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)
setPaperTrades(prev => [trade, ...prev])
console.log('📄 SAFE PAPER TRADE:', trade)
alert(`✅ Safe Paper Trade: ${signal} ${trade.symbol} at $${trade.entryPrice}\\n💡 This is completely isolated - no real money at risk!`)
}
const closeSafePaperTrade = (tradeId, exitPrice) => {
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)
const isWinner = pnl > 0
setPaperBalance(current => current + pnl)
// Update learning insights after closing trade
updateLearningInsights(trade, pnl, isWinner)
return {
...trade,
status: 'CLOSED',
exitPrice,
exitTime: new Date().toISOString(),
pnl,
isWinner,
exitReason: 'Manual close'
}
}
return trade
}))
}
const updateLearningInsights = async (trade, pnl, isWinner) => {
try {
// Simulate AI learning from trade outcome
const learningData = {
tradeId: trade.id,
symbol: trade.symbol,
timeframe: trade.timeframe,
side: trade.side,
entryPrice: trade.entryPrice,
exitPrice: trade.exitPrice || null,
pnl,
isWinner,
confidence: trade.confidence,
reasoning: trade.reasoning,
timestamp: new Date().toISOString()
}
console.log('🧠 AI Learning from trade outcome:', learningData)
// Call learning API if available (simulated for paper trading)
setLearningInsights(prev => ({
...prev,
lastTrade: learningData,
totalTrades: (prev?.totalTrades || 0) + 1,
winners: isWinner ? (prev?.winners || 0) + 1 : (prev?.winners || 0),
learningPoints: [
...(prev?.learningPoints || []).slice(-4), // Keep last 4
{
timestamp: new Date().toISOString(),
insight: generateLearningInsight(trade, pnl, isWinner),
impact: isWinner ? 'POSITIVE' : 'NEGATIVE',
confidence: trade.confidence
}
]
}))
} catch (error) {
console.error('❌ Error updating learning insights:', error)
}
}
const generateLearningInsight = (trade, pnl, isWinner) => {
const winRate = trade.confidence
if (isWinner) {
if (winRate >= 80) {
return `High confidence (${winRate}%) trade succeeded. Reinforcing pattern recognition for ${trade.symbol} ${trade.timeframe}m setups.`
} else {
return `Medium confidence (${winRate}%) trade worked out. Learning to trust similar setups more in future.`
}
} else {
if (winRate >= 80) {
return `High confidence (${winRate}%) trade failed. Reviewing analysis criteria to prevent overconfidence in similar setups.`
} else {
return `Medium confidence (${winRate}%) trade didn't work. Adjusting risk thresholds for ${trade.timeframe}m timeframe.`
}
}
}
const fetchLearningStatus = async () => {
try {
// Fetch real AI learning status from the learning system
console.log('🧠 Fetching real AI learning status...')
// Get real learning status from the AI learning system
const response = await fetch('/api/ai-learning-status', {
method: 'GET',
headers: { 'Content-Type': 'application/json' }
})
if (response.ok) {
const result = await response.json()
const realLearningData = result.data
console.log('✅ Real learning status received:', realLearningData)
setLearningInsights(prev => ({
...prev,
status: {
totalDecisions: realLearningData.totalDecisions || 0,
recentDecisions: realLearningData.totalOutcomes || 0,
successRate: (realLearningData.avgAccuracy || 0) / 100,
currentThresholds: {
emergency: 0.5,
risk: 1.5,
confidence: realLearningData.confidenceLevel || 75
},
nextTradeAdjustments: [
realLearningData.recommendation || 'Learning system initializing...',
realLearningData.nextMilestone || 'Building pattern recognition',
`Phase: ${realLearningData.phase || 'INITIALIZATION'}`
],
phase: realLearningData.phase,
winRate: realLearningData.winRate,
daysActive: realLearningData.daysActive
}
}))
} else {
// If learning API not available, create basic structure without mock data
console.log('⚠️ Learning API not available, using basic structure')
setLearningInsights(prev => ({
...prev,
status: {
totalDecisions: 0,
recentDecisions: 0,
successRate: 0,
currentThresholds: {
emergency: 0.5,
risk: 1.5,
confidence: 75
},
nextTradeAdjustments: [
'Learning system initializing...',
'Building pattern recognition database',
'Preparing adaptive decision making'
]
}
}))
}
} catch (error) {
console.error('❌ Error fetching learning status:', error)
// Minimal structure without any mock data
setLearningInsights(prev => ({
...prev,
status: {
totalDecisions: 0,
recentDecisions: 0,
successRate: 0,
currentThresholds: {
emergency: 0.5,
risk: 1.5,
confidence: 75
},
nextTradeAdjustments: ['Learning system offline']
}
}))
}
}
const resetSafePaperTrading = () => {
if (confirm('Reset all SAFE paper trading data? This cannot be undone.')) {
setPaperBalance(1000)
setPaperTrades([])
setCurrentAnalysis(null)
// Clear both key patterns to ensure complete reset
localStorage.removeItem('safePaperTrades')
localStorage.removeItem('safePaperBalance')
localStorage.removeItem('safePaperTrading_paperTrades')
localStorage.removeItem('safePaperTrading_paperBalance')
localStorage.removeItem('safePaperTrading_currentAnalysis')
console.log('🗑️ All safe paper trading data reset')
}
}
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
? Math.round((closedTrades.filter(t => (t.pnl || 0) > 0).length / closedTrades.length) * 100)
: 0
return (
<div className="space-y-6">
{/* SAFETY NOTICE */}
<div className="bg-green-900/30 border border-green-700 rounded-lg p-4">
<h2 className="text-green-400 font-bold text-lg mb-2">🛡 SAFE PAPER TRADING MODE</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 text-sm">
<div>
<p className="text-green-300 mb-1"> Completely isolated from real trading</p>
<p className="text-green-300 mb-1"> No connection to live trading APIs</p>
<p className="text-green-300"> Zero risk of real money execution</p>
</div>
<div>
<p className="text-green-300 mb-1">🧠 AI learning through safe simulation</p>
<p className="text-green-300 mb-1">📊 Real market analysis for practice</p>
<p className="text-green-300">🎯 Perfect for confidence building</p>
</div>
</div>
</div>
{/* Header with Balance */}
<div className="bg-gray-800/50 rounded-lg p-6 border border-gray-700">
<div className="flex items-center justify-between mb-4">
<div className="flex items-center space-x-4">
<h1 className="text-2xl font-bold text-white">📄 Safe Paper Trading</h1>
{continuousLearning && (
<div className="flex items-center bg-green-900/30 border border-green-600/50 rounded-lg px-3 py-2">
<div className="w-2 h-2 bg-green-400 rounded-full animate-pulse mr-2"></div>
<div className="text-sm">
<span className="text-green-400 font-medium">🎓 Learning Active</span>
{timeRemaining > 0 && (
<div className="text-xs text-green-300 font-mono">
Next cycle: {formatCountdown(timeRemaining)}
</div>
)}
</div>
</div>
)}
</div>
<div className="flex items-center space-x-4">
<div className="text-right">
<p className="text-sm text-gray-400">Virtual Balance</p>
<p className={`text-lg font-bold ${paperBalance >= 1000 ? 'text-green-400' : 'text-red-400'}`}>
${paperBalance.toFixed(2)}
</p>
</div>
<div className="text-right">
<p className="text-sm text-gray-400">Total P&L</p>
<p className={`text-lg font-bold ${totalPnL >= 0 ? 'text-green-400' : 'text-red-400'}`}>
${totalPnL.toFixed(2)}
</p>
</div>
<div className="text-right">
<p className="text-sm text-gray-400">Win Rate</p>
<p className="text-lg font-bold text-blue-400">{winRate}%</p>
</div>
</div>
</div>
{/* Stats */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 text-sm">
<div className="bg-gray-700/50 rounded p-3 text-center">
<p className="text-gray-400">Open Trades</p>
<p className="text-white font-bold text-lg">{openTrades.length}</p>
</div>
<div className="bg-gray-700/50 rounded p-3 text-center">
<p className="text-gray-400">Closed Trades</p>
<p className="text-white font-bold text-lg">{closedTrades.length}</p>
</div>
<div className="bg-gray-700/50 rounded p-3 text-center">
<p className="text-gray-400">Wins</p>
<p className="text-green-400 font-bold text-lg">
{closedTrades.filter(t => (t.pnl || 0) > 0).length}
</p>
</div>
<div className="bg-gray-700/50 rounded p-3 text-center">
<p className="text-gray-400">Losses</p>
<p className="text-red-400 font-bold text-lg">
{closedTrades.filter(t => (t.pnl || 0) < 0).length}
</p>
</div>
</div>
</div>
{/* Trading Controls */}
<div className="bg-gray-800/50 rounded-lg p-6 border border-gray-700">
<h3 className="text-lg font-bold text-white mb-4">🎯 Safe Analysis Controls</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
<div>
<label className="block text-sm text-gray-400 mb-2">Symbol</label>
<select
value={symbol}
onChange={(e) => setSymbol(e.target.value)}
disabled={loading || continuousLearning}
className="w-full bg-gray-700 text-white rounded px-3 py-2 disabled:opacity-50"
>
<option value="SOLUSD">SOL/USD</option>
<option value="BTCUSD">BTC/USD</option>
<option value="ETHUSD">ETH/USD</option>
</select>
</div>
<div>
<label className="block text-sm text-gray-400 mb-2">
Continuous Learning
{continuousLearning && (
<span className="ml-2 text-xs text-green-400 font-mono bg-green-900/20 px-2 py-1 rounded">
{timeRemaining > 0 ? (
<> Next: {formatCountdown(timeRemaining)}</>
) : (
<>🔄 Analysis running...</>
)}
</span>
)}
</label>
<div className="flex gap-2">
<button
onClick={() => {
if (continuousLearning) {
stopContinuousLearning()
setContinuousLearning(false)
} else {
setContinuousLearning(true)
startContinuousLearning()
}
}}
disabled={loading}
className={`flex-1 py-2 px-4 rounded-lg font-medium transition-all duration-200 ${
continuousLearning
? 'bg-red-600 hover:bg-red-700 text-white'
: 'bg-green-600 hover:bg-green-700 text-white'
} disabled:opacity-50`}
>
{continuousLearning ? '🛑 Stop Learning' : '🎓 Start Learning'}
</button>
{continuousLearning && (
<button
onClick={restartContinuousLearning}
disabled={loading}
className="py-2 px-3 rounded-lg font-medium transition-all duration-200 bg-blue-600 hover:bg-blue-700 text-white disabled:opacity-50"
title="Restart continuous learning if it seems stuck"
>
🔄
</button>
)}
<button
onClick={() => {
console.log('🔄 Force refresh: Clearing stale data and fetching fresh analysis')
localStorage.removeItem('safePaperTrading_currentAnalysis')
setCurrentAnalysis(null)
runSafeAnalysis(false)
}}
disabled={loading}
className="py-2 px-4 rounded-lg font-medium transition-all duration-200 bg-blue-600 hover:bg-blue-700 text-white disabled:opacity-50"
title="Clear stale data and get fresh analysis"
>
🔄 Fresh
</button>
</div>
{/* Auto-Execute Toggle - Only show when continuous learning is active */}
{continuousLearning && (
<div className="mt-4 p-3 bg-gray-800 rounded-lg border border-gray-700">
<div className="flex items-center justify-between">
<div className="flex flex-col">
<span className="text-sm font-medium text-gray-300">Auto-Execute Trades</span>
<span className="text-xs text-gray-400">Automatically execute paper trades based on AI recommendations (60% confidence)</span>
</div>
<button
onClick={() => setAutoExecuteTrades(!autoExecuteTrades)}
className={`ml-4 px-4 py-2 rounded-lg font-medium transition-all duration-200 ${
autoExecuteTrades
? 'bg-green-600 hover:bg-green-700 text-white'
: 'bg-gray-600 hover:bg-gray-700 text-white'
}`}
>
{autoExecuteTrades ? '🤖 ON' : '📄 Manual'}
</button>
</div>
{autoExecuteTrades && (
<div className="mt-2 text-xs text-yellow-400">
Paper trades will be executed automatically when AI recommends BUY/SELL with 60% confidence
</div>
)}
</div>
)}
</div>
</div>
{/* Multi-Timeframe Selection */}
<div className="mb-6">
<label className="block text-sm text-gray-400 mb-3">Multi-Timeframe Analysis</label>
{/* Trading Style Presets */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-3 mb-4">
<button
type="button"
onClick={() => setSelectedTimeframes(['5', '15', '30'])}
disabled={loading || continuousLearning}
className="group p-4 rounded-lg bg-gradient-to-br from-green-600/20 to-emerald-600/10 border border-green-600/30 hover:border-green-500/50 transition-all duration-200 disabled:opacity-50 text-left"
>
<div className="flex items-center justify-between mb-2">
<div className="text-xl">📈</div>
<div className="text-xs text-green-400 bg-green-500/20 px-2 py-1 rounded">FAST</div>
</div>
<h4 className="text-sm font-bold text-green-300 mb-1">Scalping</h4>
<div className="text-xs text-green-400/80 font-mono">5m 15m 30m</div>
</button>
<button
type="button"
onClick={() => setSelectedTimeframes(['60', '120'])}
disabled={loading || continuousLearning}
className="group p-4 rounded-lg bg-gradient-to-br from-blue-600/20 to-indigo-600/10 border border-blue-600/30 hover:border-blue-500/50 transition-all duration-200 disabled:opacity-50 text-left"
>
<div className="flex items-center justify-between mb-2">
<div className="text-xl"></div>
<div className="text-xs text-blue-400 bg-blue-500/20 px-2 py-1 rounded">MEDIUM</div>
</div>
<h4 className="text-sm font-bold text-blue-300 mb-1">Day Trading</h4>
<div className="text-xs text-blue-400/80 font-mono">1h 2h</div>
</button>
<button
type="button"
onClick={() => setSelectedTimeframes(['240', 'D'])}
disabled={loading || continuousLearning}
className="group p-4 rounded-lg bg-gradient-to-br from-purple-600/20 to-violet-600/10 border border-purple-600/30 hover:border-purple-500/50 transition-all duration-200 disabled:opacity-50 text-left"
>
<div className="flex items-center justify-between mb-2">
<div className="text-xl">🎯</div>
<div className="text-xs text-purple-400 bg-purple-500/20 px-2 py-1 rounded">SLOW</div>
</div>
<h4 className="text-sm font-bold text-purple-300 mb-1">Swing Trading</h4>
<div className="text-xs text-purple-400/80 font-mono">4h 1d</div>
</button>
</div>
{/* Individual Timeframe Toggles */}
<div className="grid grid-cols-3 md:grid-cols-7 gap-2">
{timeframes.map(tf => (
<button
key={tf.value}
onClick={() => toggleTimeframe(tf.value)}
disabled={loading || continuousLearning}
className={`py-2 px-3 rounded-lg text-sm font-medium transition-all duration-200 ${
selectedTimeframes.includes(tf.value)
? 'bg-blue-600 text-white border border-blue-500'
: 'bg-gray-700 text-gray-300 border border-gray-600 hover:bg-gray-600'
} disabled:opacity-50`}
>
{tf.label}
</button>
))}
</div>
<div className="mt-2 text-xs text-gray-500">
Selected: {selectedTimeframes.length > 0 ? selectedTimeframes.map(tf =>
timeframes.find(t => t.value === tf)?.label || tf
).join(', ') : 'None'}
{selectedTimeframes.length > 0 && (
<span className="ml-2 text-blue-400">
(Analysis delay: {Math.ceil(calculateOptimalDelay() / 60000)}m)
</span>
)}
</div>
</div>
<button
onClick={() => {
console.log('🟢 BUTTON CLICK DETECTED!')
console.log('🔍 Current state - loading:', loading, 'symbol:', symbol, 'timeframes:', selectedTimeframes)
runSafeAnalysis()
}}
disabled={loading || selectedTimeframes.length === 0}
className={`w-full py-3 px-4 rounded-lg font-medium transition-all duration-200 ${
loading
? 'bg-gray-600 text-gray-400 cursor-not-allowed'
: selectedTimeframes.length === 0
? 'bg-gray-600 text-gray-400 cursor-not-allowed'
: 'bg-blue-600 hover:bg-blue-700 text-white'
}`}
>
{loading ? '🔄 Safe Analysis Running...' :
selectedTimeframes.length === 0 ? '⚠️ Select Timeframes First' :
'🛡️ Start Safe Paper Analysis'}
</button>
{/* Force Analysis Button for Testing */}
{continuousLearning && (
<button
onClick={() => {
console.log('🧪 FORCE ANALYSIS: Manual trigger for testing')
runSafeAnalysis(true)
}}
disabled={loading}
className="w-full mt-2 py-2 px-4 rounded-lg font-medium transition-all duration-200 bg-yellow-600 hover:bg-yellow-700 text-white disabled:opacity-50"
>
🧪 Force Analysis Now (Test)
</button>
)}
<div className="mt-2 text-xs text-gray-500">
Real market analysis Paper trading only Zero trading risk
{continuousLearning && (
<span className="block mt-1 text-green-400">
🎓 Continuous learning active - System automatically analyzes every {Math.ceil(calculateOptimalDelay() / 60000)} minutes
{timeRemaining > 0 && (
<span className="ml-2 text-green-300">
(Next: {formatCountdown(timeRemaining)})
</span>
)}
</span>
)}
</div>
{/* Clear Data Controls */}
{(currentAnalysis || paperTrades.length > 0 || analysisHistory.length > 0) && (
<div className="mt-4 pt-4 border-t border-gray-700">
<div className="flex items-center justify-between">
<div className="text-sm text-gray-400">
<p>Analysis History: {analysisHistory.length} entries</p>
<p>Paper Trades: {paperTrades.length} trades</p>
</div>
<button
onClick={() => {
if (confirm('Clear all analysis history and paper trading data? This cannot be undone.')) {
// Stop continuous learning first
if (continuousLearning) {
stopContinuousLearning()
setContinuousLearning(false)
}
setCurrentAnalysis(null)
setPaperTrades([])
setAnalysisHistory([])
setLearningInsights(null)
setPaperBalance(1000)
// Clear localStorage
localStorage.removeItem('safePaperTrading_currentAnalysis')
localStorage.removeItem('safePaperTrading_paperTrades')
localStorage.removeItem('safePaperTrading_analysisHistory')
localStorage.removeItem('safePaperTrading_learningInsights')
localStorage.removeItem('safePaperTrading_paperBalance')
localStorage.removeItem('safePaperTrading_continuousLearning')
console.log('🧹 Cleared all safe paper trading data')
}
}}
className="py-1 px-3 rounded text-xs font-medium transition-all duration-200 bg-gray-600 hover:bg-gray-500 text-gray-300"
>
🧹 Clear All Data
</button>
</div>
</div>
)}
</div>
{/* Error Display */}
{error && (
<div className="bg-red-900/30 border border-red-700 rounded-lg p-4">
<p className="text-red-400"> Error: {error}</p>
</div>
)}
{/* Current Analysis Results */}
{currentAnalysis && (
<div className="bg-gray-800/50 rounded-lg p-6 border border-gray-700">
<h3 className="text-lg font-bold text-white mb-4">📊 Safe Analysis Results</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
<div className="bg-gray-700/50 rounded p-3">
<p className="text-gray-400 text-sm">Recommendation</p>
<p className={`font-bold text-lg ${
currentAnalysis.recommendation === 'BUY' ? 'text-green-400' :
currentAnalysis.recommendation === 'SELL' ? 'text-red-400' : 'text-yellow-400'
}`}>
{currentAnalysis.recommendation}
</p>
</div>
<div className="bg-gray-700/50 rounded p-3">
<p className="text-gray-400 text-sm">Confidence</p>
<p className="font-bold text-lg text-blue-400">{currentAnalysis.confidence}%</p>
{currentAnalysis.originalConfidence && currentAnalysis.originalConfidence !== currentAnalysis.confidence && (
<p className="text-xs text-gray-500">
(Original: {currentAnalysis.originalConfidence}%, Macro: {currentAnalysis.macroAdjustment?.netAdjustment > 0 ? '+' : ''}{currentAnalysis.macroAdjustment?.netAdjustment}%)
</p>
)}
</div>
<div className="bg-gray-700/50 rounded p-3">
<p className="text-gray-400 text-sm">Timeframes</p>
<p className="font-bold text-sm text-purple-400">
{currentAnalysis.timeframes?.map(tf =>
timeframes.find(t => t.value === tf)?.label || tf
).join(', ') || 'Single'}
</p>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
<div className="bg-gray-700/50 rounded p-3">
<p className="text-gray-400 text-sm">Entry Price</p>
<p className="font-bold text-lg text-white">${currentAnalysis.entry?.price?.toFixed(2) || 'N/A'}</p>
</div>
<div className="bg-gray-700/50 rounded p-3">
<p className="text-gray-400 text-sm">Analysis Mode</p>
<p className="font-bold text-sm text-indigo-400">
{currentAnalysis.analysisMode === 'CONTINUOUS_LEARNING' ? '🎓 Learning' : '👤 Manual'}
</p>
</div>
<div className="bg-gray-700/50 rounded p-3">
<p className="text-gray-400 text-sm">Primary Focus</p>
<p className="font-bold text-sm text-cyan-400">
{currentAnalysis.primaryTimeframe ?
timeframes.find(t => t.value === currentAnalysis.primaryTimeframe)?.label || currentAnalysis.primaryTimeframe
: 'N/A'}
</p>
</div>
</div>
{/* Action Buttons */}
{currentAnalysis.recommendation !== 'HOLD' && currentAnalysis.tradeDecision?.allowed && (
<div className="flex space-x-4 mb-4">
<button
onClick={() => executeSafePaperTrade('BUY')}
disabled={currentAnalysis.recommendation !== 'BUY'}
className={`flex-1 py-2 px-4 rounded font-medium ${
currentAnalysis.recommendation === 'BUY'
? 'bg-green-600 hover:bg-green-700 text-white'
: 'bg-gray-600 text-gray-400 cursor-not-allowed'
}`}
>
📄 Safe Paper BUY
</button>
<button
onClick={() => executeSafePaperTrade('SELL')}
disabled={currentAnalysis.recommendation !== 'SELL'}
className={`flex-1 py-2 px-4 rounded font-medium ${
currentAnalysis.recommendation === 'SELL'
? 'bg-red-600 hover:bg-red-700 text-white'
: 'bg-gray-600 text-gray-400 cursor-not-allowed'
}`}
>
📄 Safe Paper SELL
</button>
</div>
)}
{/* Analysis Details */}
<div className="bg-gray-700/30 rounded p-4">
<h4 className="text-white font-medium mb-2">Analysis Reasoning:</h4>
<pre className="text-gray-300 text-sm whitespace-pre-wrap">
{typeof currentAnalysis.reasoning === 'string'
? currentAnalysis.reasoning
: typeof currentAnalysis.reasoning === 'object'
? JSON.stringify(currentAnalysis.reasoning, null, 2)
: 'Analysis reasoning not available'}
</pre>
</div>
{/* Macro Sentiment Panel */}
{currentAnalysis.macroSentiment && (
<div className="bg-gradient-to-r from-purple-900/30 to-blue-900/30 rounded p-4 mt-4 border border-purple-500/30">
<h4 className="text-white font-medium mb-3 flex items-center">
💰 Macro Sentiment Analysis
{currentAnalysis.macroAdjustment?.applied && (
<span className="ml-2 text-xs bg-purple-600 px-2 py-1 rounded">
{currentAnalysis.macroAdjustment.netAdjustment > 0 ? '+' : ''}{currentAnalysis.macroAdjustment.netAdjustment}%
</span>
)}
</h4>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{/* Fear & Greed Index */}
<div className="bg-gray-800/50 rounded p-3">
<p className="text-gray-400 text-xs">Fear & Greed Index</p>
<div className="flex items-center space-x-2">
<span className={`text-lg font-bold ${
currentAnalysis.macroSentiment.fearAndGreed?.value <= 25 ? 'text-red-400' :
currentAnalysis.macroSentiment.fearAndGreed?.value <= 45 ? 'text-orange-400' :
currentAnalysis.macroSentiment.fearAndGreed?.value >= 75 ? 'text-green-400' :
currentAnalysis.macroSentiment.fearAndGreed?.value >= 55 ? 'text-yellow-400' :
'text-gray-400'
}`}>
{currentAnalysis.macroSentiment.fearAndGreed?.value || 'N/A'}
</span>
<span className="text-xs text-gray-400">
{currentAnalysis.macroSentiment.fearAndGreed?.classification || 'unknown'}
</span>
</div>
</div>
{/* M2 Money Supply */}
<div className="bg-gray-800/50 rounded p-3">
<p className="text-gray-400 text-xs">M2 Money Supply</p>
<div className="flex items-center space-x-2">
<span className={`text-sm font-bold ${
currentAnalysis.macroSentiment.m2MoneySupply?.cryptoSignal?.signal === 'BULLISH' ? 'text-green-400' :
currentAnalysis.macroSentiment.m2MoneySupply?.cryptoSignal?.signal === 'BEARISH' ? 'text-red-400' :
'text-gray-400'
}`}>
{currentAnalysis.macroSentiment.m2MoneySupply?.cryptoSignal?.signal || 'N/A'}
</span>
<span className="text-xs text-gray-400">
({currentAnalysis.macroSentiment.m2MoneySupply?.cryptoSignal?.confidence || 0}%)
</span>
</div>
{currentAnalysis.macroSentiment.m2MoneySupply?.cryptoSignal?.timeframe && (
<p className="text-xs text-purple-400 mt-1">
{currentAnalysis.macroSentiment.m2MoneySupply.cryptoSignal.timeframe}
</p>
)}
</div>
</div>
{/* Macro Adjustments Applied */}
{currentAnalysis.macroAdjustment?.applied && (
<div className="mt-3 bg-gray-800/30 rounded p-2">
<p className="text-xs text-gray-400 mb-1">Macro Adjustments Applied:</p>
<ul className="text-xs text-gray-300 space-y-1">
{currentAnalysis.macroAdjustment.adjustments.map((adjustment, index) => (
<li key={index} className="flex items-start">
<span className="text-purple-400 mr-1"></span>
{adjustment}
</li>
))}
</ul>
</div>
)}
</div>
)}
{/* Toggle Detailed Analysis */}
<button
onClick={() => setShowDetailedAnalysis(!showDetailedAnalysis)}
className="w-full mt-4 py-2 px-4 bg-purple-600 hover:bg-purple-700 text-white rounded-lg font-medium transition-all duration-200"
>
{showDetailedAnalysis ? '📊 Hide Detailed Analysis' : '🔍 Show Detailed Analysis'}
</button>
</div>
)}
{/* Detailed Market Analysis Panel */}
{currentAnalysis && showDetailedAnalysis && (
<div className="bg-gradient-to-br from-blue-900/30 to-purple-900/30 rounded-lg p-6 border border-blue-700/50">
<div className="flex items-center justify-between mb-4">
<h3 className="text-xl font-bold text-white flex items-center">
🧠 Market Summary
{currentAnalysis.timeframes && currentAnalysis.timeframes.length > 1 && (
<span className="ml-2 text-sm text-purple-400 bg-purple-500/20 px-2 py-1 rounded">
{currentAnalysis.timeframes.length} Timeframes
</span>
)}
</h3>
<div className="text-sm text-blue-300">
{currentAnalysis.analysisMode === 'CONTINUOUS_LEARNING'
? 'Continuous learning analysis with multi-timeframe insights'
: 'Comprehensive multi-layout analysis with timeframe risk assessment and cross-layout insights'
}
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
{/* Market Sentiment */}
<div className="bg-gray-800/60 rounded-lg p-4">
<h4 className="text-green-400 font-medium mb-2">Market Sentiment</h4>
<p className="text-2xl font-bold text-white">{currentAnalysis.marketSentiment || 'NEUTRAL'}</p>
</div>
{/* Recommendation */}
<div className="bg-gray-800/60 rounded-lg p-4">
<h4 className="text-blue-400 font-medium mb-2">Recommendation</h4>
<p className={`text-2xl font-bold ${
currentAnalysis.recommendation === 'BUY' ? 'text-green-400' :
currentAnalysis.recommendation === 'SELL' ? 'text-red-400' : 'text-yellow-400'
}`}>
{currentAnalysis.recommendation}
</p>
<p className="text-sm text-gray-300">{currentAnalysis.confidence}% confidence</p>
</div>
{/* Resistance Levels */}
<div className="bg-gray-800/60 rounded-lg p-4">
<h4 className="text-red-400 font-medium mb-2">Resistance Levels</h4>
<p className="text-white font-mono">
{currentAnalysis.keyLevels?.resistance?.join(', ') ||
`$${(currentAnalysis.entry?.price * 1.02 || 164).toFixed(2)}, $${(currentAnalysis.entry?.price * 1.05 || 168).toFixed(2)}`}
</p>
</div>
{/* Support Levels */}
<div className="bg-gray-800/60 rounded-lg p-4">
<h4 className="text-green-400 font-medium mb-2">Support Levels</h4>
<p className="text-white font-mono">
{currentAnalysis.keyLevels?.support?.join(', ') ||
`$${(currentAnalysis.entry?.price * 0.98 || 160).toFixed(2)}, $${(currentAnalysis.entry?.price * 0.95 || 156).toFixed(2)}`}
</p>
</div>
</div>
{/* Trading Setup */}
<div className="bg-purple-900/20 rounded-lg p-4 mb-4">
<h4 className="text-purple-300 font-medium mb-3">Trading Setup</h4>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
{/* Entry Point */}
<div>
<div className="flex items-center mb-2">
<span className="text-yellow-400 mr-2">🎯</span>
<span className="text-yellow-400 font-medium">Entry Point</span>
</div>
<p className="text-white font-mono text-lg">${currentAnalysis.entry?.price?.toFixed(2) || 'N/A'}</p>
<p className="text-sm text-gray-400">
{typeof currentAnalysis.entry?.reasoning === 'string'
? currentAnalysis.entry.reasoning
: typeof currentAnalysis.entry?.reasoning === 'object'
? JSON.stringify(currentAnalysis.entry.reasoning)
: currentAnalysis.summary || 'Real market analysis entry point'}
</p>
</div>
{/* Stop Loss */}
<div>
<div className="flex items-center mb-2">
<span className="text-red-400 mr-2"></span>
<span className="text-red-400 font-medium">Stop Loss</span>
</div>
<p className="text-white font-mono text-lg">${currentAnalysis.stopLoss?.price?.toFixed(2) || 'N/A'}</p>
<p className="text-sm text-gray-400">
{typeof currentAnalysis.stopLoss?.reasoning === 'string'
? currentAnalysis.stopLoss.reasoning
: typeof currentAnalysis.stopLoss?.reasoning === 'object'
? JSON.stringify(currentAnalysis.stopLoss.reasoning)
: 'Real market analysis stop loss level'}
</p>
</div>
{/* Take Profit Targets */}
<div>
<div className="flex items-center mb-2">
<span className="text-blue-400 mr-2">💎</span>
<span className="text-blue-400 font-medium">Take Profit Targets</span>
</div>
<div className="space-y-1">
<div>
<span className="text-blue-400 font-medium">TP1: </span>
<span className="text-white font-mono">${currentAnalysis.takeProfits?.tp1?.price?.toFixed(2) || 'N/A'}</span>
</div>
{currentAnalysis.takeProfits?.tp2 && (
<div>
<span className="text-blue-400 font-medium">TP2: </span>
<span className="text-white font-mono">${currentAnalysis.takeProfits.tp2.price?.toFixed(2)}</span>
</div>
)}
</div>
<p className="text-sm text-gray-400 mt-1">
{typeof currentAnalysis.takeProfits?.reasoning === 'string'
? currentAnalysis.takeProfits.reasoning
: typeof currentAnalysis.takeProfits?.reasoning === 'object'
? JSON.stringify(currentAnalysis.takeProfits.reasoning)
: 'Real market analysis target levels'}
</p>
</div>
</div>
</div>
{/* Risk Management */}
<div className="bg-gray-800/40 rounded-lg p-4">
<h4 className="text-orange-400 font-medium mb-3">Risk Management</h4>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<div className="flex items-center justify-between mb-2">
<span className="text-gray-300">Risk/Reward Ratio</span>
<span className="text-orange-400 font-bold">
{currentAnalysis.riskToReward || 'N/A'}
</span>
</div>
<div className="flex items-center mb-2">
<span className="text-yellow-400 mr-2"></span>
<span className="text-yellow-400 font-medium">Confirmation Trigger</span>
</div>
<p className="text-gray-300 text-sm">
{typeof currentAnalysis.confirmationTrigger === 'string'
? currentAnalysis.confirmationTrigger
: typeof currentAnalysis.confirmationTrigger === 'object'
? JSON.stringify(currentAnalysis.confirmationTrigger)
: 'Real market confirmation signals from analysis'}
</p>
</div>
<div>
<div className="space-y-2">
<div className="flex justify-between">
<span className="text-gray-400">Trend:</span>
<span className="text-white">
{typeof currentAnalysis.trendAnalysis === 'object'
? (currentAnalysis.trendAnalysis?.direction || 'Analyzing...')
: currentAnalysis.trendAnalysis || 'Analyzing...'}
</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400">Momentum:</span>
<span className="text-white">
{typeof currentAnalysis.momentumAnalysis === 'object'
? (currentAnalysis.momentumAnalysis?.status || 'Analyzing...')
: currentAnalysis.momentumAnalysis || 'Analyzing...'}
</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400">Volume:</span>
<span className="text-white">
{typeof currentAnalysis.volumeAnalysis === 'object'
? (currentAnalysis.volumeAnalysis?.trend || 'Analyzing...')
: currentAnalysis.volumeAnalysis || 'Analyzing...'}
</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400">Timeframe Risk:</span>
<span className="text-white">
{typeof currentAnalysis.timeframeRisk === 'object'
? (currentAnalysis.timeframeRisk?.assessment || 'Medium')
: currentAnalysis.timeframeRisk || 'Medium'}
</span>
</div>
</div>
</div>
</div>
</div>
</div>
)}
{/* AI Learning Insights Panel */}
{learningInsights && (
<div className="bg-gradient-to-br from-indigo-900/30 to-purple-900/30 rounded-lg p-6 border border-indigo-700/50">
<h3 className="text-xl font-bold text-white mb-4 flex items-center">
🧠 AI Learning Insights
<span className="ml-2 text-sm text-indigo-300">Real-time learning from trade outcomes</span>
</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
{/* Learning Status */}
<div className="bg-gray-800/60 rounded-lg p-4">
<h4 className="text-indigo-400 font-medium mb-2">Learning Status</h4>
<div className="space-y-2">
<div className="flex justify-between">
<span className="text-gray-400">Total Decisions:</span>
<span className="text-white font-bold">{learningInsights.status?.totalDecisions || 0}</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400">Success Rate:</span>
<span className="text-green-400 font-bold">
{((learningInsights.status?.successRate || 0) * 100).toFixed(1)}%
</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400">Paper Trades:</span>
<span className="text-blue-400 font-bold">{learningInsights.totalTrades || 0}</span>
</div>
</div>
</div>
{/* Win/Loss Analysis */}
<div className="bg-gray-800/60 rounded-lg p-4">
<h4 className="text-green-400 font-medium mb-2">Trade Outcome</h4>
{learningInsights.lastTrade ? (
<div className="space-y-2">
<div className={`flex items-center ${learningInsights.lastTrade.isWinner ? 'text-green-400' : 'text-red-400'}`}>
<span className="mr-2">{learningInsights.lastTrade.isWinner ? '✅' : '❌'}</span>
<span className="font-bold">
{learningInsights.lastTrade.isWinner ? 'WINNER' : 'LOSER'}
</span>
</div>
<div className="text-sm text-gray-400">
Last: {learningInsights.lastTrade.symbol} ${learningInsights.lastTrade.pnl?.toFixed(2)}
</div>
<div className="text-sm text-gray-400">
Confidence: {learningInsights.lastTrade.confidence}%
</div>
</div>
) : (
<p className="text-gray-400 text-sm">No trades yet</p>
)}
</div>
{/* Current Adjustments */}
<div className="bg-gray-800/60 rounded-lg p-4">
<h4 className="text-purple-400 font-medium mb-2">AI Adjustments</h4>
<div className="space-y-1">
{learningInsights.status?.nextTradeAdjustments?.slice(0, 3).map((adjustment, index) => (
<div key={index} className="text-xs text-gray-300 flex items-start">
<span className="text-purple-400 mr-1"></span>
<span>{adjustment}</span>
</div>
)) || (
<p className="text-gray-400 text-sm">Analyzing patterns...</p>
)}
</div>
</div>
</div>
{/* Learning Reflection */}
{learningInsights.learningPoints && learningInsights.learningPoints.length > 0 && (
<div className="bg-gray-800/40 rounded-lg p-4">
<h4 className="text-indigo-300 font-medium mb-3">AI Reflection & Learning</h4>
<div className="space-y-3">
{learningInsights.learningPoints.slice(-3).map((point, index) => (
<div key={index} className={`p-3 rounded border-l-4 ${
point.impact === 'POSITIVE' ? 'bg-green-900/20 border-green-500' : 'bg-red-900/20 border-red-500'
}`}>
<div className="flex items-center justify-between mb-1">
<span className={`text-sm font-medium ${
point.impact === 'POSITIVE' ? 'text-green-400' : 'text-red-400'
}`}>
{point.impact === 'POSITIVE' ? '📈 Positive Learning' : '📉 Learning from Loss'}
</span>
<span className="text-xs text-gray-500">
{new Date(point.timestamp).toLocaleTimeString()}
</span>
</div>
<p className="text-gray-300 text-sm">{point.insight}</p>
</div>
))}
</div>
</div>
)}
{/* What AI is Using for Next Trade */}
<div className="bg-blue-900/20 rounded-lg p-4 mt-4">
<h4 className="text-blue-300 font-medium mb-3">🔮 AI Database for Next Trade</h4>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<h5 className="text-blue-400 text-sm font-medium mb-2">Current Thresholds:</h5>
<div className="space-y-1 text-xs">
<div className="flex justify-between">
<span className="text-gray-400">Emergency Distance:</span>
<span className="text-white">{learningInsights.status?.currentThresholds?.emergency || 0.5}%</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400">Risk Distance:</span>
<span className="text-white">{learningInsights.status?.currentThresholds?.risk || 1.5}%</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400">Min Confidence:</span>
<span className="text-white">{learningInsights.status?.currentThresholds?.confidence || 75}%</span>
</div>
</div>
</div>
<div>
<h5 className="text-blue-400 text-sm font-medium mb-2">Pattern Recognition:</h5>
<div className="space-y-1 text-xs text-gray-300">
<div> {symbol} multi-timeframe: {learningInsights.status?.totalDecisions || 0} total decisions in database</div>
<div> Success rate: {((learningInsights.status?.successRate || 0) * 100).toFixed(1)}%</div>
<div> Learning phase: {learningInsights.status?.phase || 'INITIALIZATION'}</div>
<div> Days active: {learningInsights.status?.daysActive || 0} days</div>
{currentAnalysis?.timeframes && currentAnalysis.timeframes.length > 1 && (
<div> Current analysis: {currentAnalysis.timeframes.map(tf =>
timeframes.find(t => t.value === tf)?.label || tf
).join(' + ')} confluence</div>
)}
</div>
</div>
</div>
</div>
</div>
)}
{/* Open Trades */}
{openTrades.length > 0 && (
<div className="bg-gray-800/50 rounded-lg p-6 border border-gray-700">
<h3 className="text-lg font-bold text-white mb-4">📈 Open Paper Positions</h3>
<div className="space-y-3">
{openTrades.map(trade => (
<div key={trade.id} className="bg-gray-700/50 rounded p-4 flex justify-between items-center">
<div className="flex-1">
<div className="flex items-center space-x-4">
<span className={`px-2 py-1 rounded text-xs font-medium ${
trade.side === 'BUY' ? 'bg-green-600 text-white' : 'bg-red-600 text-white'
}`}>
{trade.side}
</span>
<span className="text-white font-medium">{trade.symbol}</span>
<span className="text-gray-400">${trade.entryPrice}</span>
<span className="text-gray-400">Size: ${trade.positionSize?.toFixed(2)}</span>
</div>
<div className="text-xs text-gray-400 mt-1">
Entry: {new Date(trade.timestamp).toLocaleString()} |
Confidence: {trade.confidence}%
</div>
</div>
<button
onClick={() => {
const exitPrice = prompt(`Exit price for ${trade.symbol}:`, trade.entryPrice)
if (exitPrice) closeSafePaperTrade(trade.id, parseFloat(exitPrice))
}}
className="bg-yellow-600 hover:bg-yellow-700 text-white px-3 py-1 rounded text-sm"
>
Close
</button>
</div>
))}
</div>
</div>
)}
{/* Trade History */}
{closedTrades.length > 0 && (
<div className="bg-gray-800/50 rounded-lg p-6 border border-gray-700">
<div className="flex justify-between items-center mb-4">
<h3 className="text-lg font-bold text-white">📈 Safe Paper Trade History</h3>
<button
onClick={resetSafePaperTrading}
className="bg-red-600 hover:bg-red-700 text-white px-3 py-2 rounded text-sm"
>
Reset All Data
</button>
</div>
<div className="space-y-2 max-h-96 overflow-y-auto">
{closedTrades.slice(0, 20).map(trade => (
<div key={trade.id} className={`p-3 rounded border-l-4 ${
(trade.pnl || 0) >= 0 ? 'bg-green-900/20 border-green-500' : 'bg-red-900/20 border-red-500'
}`}>
<div className="flex justify-between items-center">
<div className="flex items-center space-x-4">
<span className={`px-2 py-1 rounded text-xs font-medium ${
trade.side === 'BUY' ? 'bg-green-600 text-white' : 'bg-red-600 text-white'
}`}>
{trade.side}
</span>
<span className="text-white">{trade.symbol}</span>
<span className="text-gray-400">${trade.entryPrice} ${trade.exitPrice}</span>
<span className={`font-medium ${
(trade.pnl || 0) >= 0 ? 'text-green-400' : 'text-red-400'
}`}>
${(trade.pnl || 0).toFixed(2)}
</span>
<span className={`text-xs px-2 py-1 rounded ${
trade.isWinner ? 'bg-green-600 text-white' : 'bg-red-600 text-white'
}`}>
{trade.isWinner ? 'WIN' : 'LOSS'}
</span>
</div>
</div>
<div className="text-xs text-gray-400 mt-1">
{new Date(trade.timestamp).toLocaleDateString()} | Confidence: {trade.confidence}%
</div>
</div>
))}
</div>
</div>
)}
{/* Analysis History Panel */}
{analysisHistory.length > 0 && (
<div className="bg-gradient-to-br from-gray-800/30 to-gray-900/30 rounded-lg p-6 border border-gray-700/50">
<div className="flex items-center justify-between mb-4">
<h3 className="text-xl font-bold text-white flex items-center">
📊 Analysis History
<span className="ml-2 text-sm text-gray-400 bg-gray-700/50 px-2 py-1 rounded">
{analysisHistory.length} entries
</span>
</h3>
<span className="text-sm text-gray-400">Recent analyses are automatically saved</span>
</div>
<div className="space-y-3 max-h-96 overflow-y-auto">
{analysisHistory.map((analysis, index) => (
<div key={analysis.analysisId || index} className="bg-gray-800/60 rounded-lg p-4 border border-gray-700">
<div className="flex items-center justify-between mb-2">
<div className="flex items-center space-x-3">
<span className={`text-lg font-bold ${
analysis.recommendation === 'BUY' ? 'text-green-400' :
analysis.recommendation === 'SELL' ? 'text-red-400' : 'text-yellow-400'
}`}>
{analysis.recommendation}
</span>
<span className="text-blue-400 font-bold">{analysis.confidence}%</span>
<span className="text-sm text-gray-400">
{analysis.symbol} {analysis.timeframes?.join(', ')}
</span>
</div>
<div className="text-xs text-gray-500">
{new Date(analysis.timestamp).toLocaleString()}
</div>
</div>
<div className="grid grid-cols-3 gap-4 text-sm">
<div>
<span className="text-gray-400">Entry: </span>
<span className="text-white font-mono">${analysis.entry?.price?.toFixed(2) || 'N/A'}</span>
</div>
<div>
<span className="text-gray-400">Stop: </span>
<span className="text-white font-mono">${analysis.stopLoss?.price?.toFixed(2) || 'N/A'}</span>
</div>
<div>
<span className="text-gray-400">Target: </span>
<span className="text-white font-mono">${analysis.takeProfits?.tp1?.price?.toFixed(2) || 'N/A'}</span>
</div>
</div>
{analysis.analysisType === 'CONTINUOUS_LEARNING' && (
<div className="mt-2 text-xs text-purple-400 flex items-center">
🎓 <span className="ml-1">Continuous learning analysis</span>
</div>
)}
</div>
))}
</div>
</div>
)}
</div>
)
}