diff --git a/page-temp.js b/page-temp.js new file mode 100644 index 0000000..ac47575 --- /dev/null +++ b/page-temp.js @@ -0,0 +1,711 @@ +'use client' +import React, { useState, useEffect } from 'react' + +// Available timeframes for automation (matching analysis page 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' }, +] + +export default function AutomationPageV2() { + const [config, setConfig] = useState({ + mode: 'SIMULATION', + dexProvider: 'DRIFT', + symbol: 'SOLUSD', + timeframe: '1h', // Primary timeframe for backwards compatibility + selectedTimeframes: ['60'], // Multi-timeframe support + tradingAmount: 100, + balancePercentage: 50, // Default to 50% of available balance + // stopLossPercent and takeProfitPercent removed - AI calculates these automatically + }) + + const [status, setStatus] = useState(null) + const [balance, setBalance] = useState(null) + const [positions, setPositions] = useState([]) + const [loading, setLoading] = useState(false) + const [nextAnalysisCountdown, setNextAnalysisCountdown] = useState(0) + + useEffect(() => { + fetchStatus() + fetchBalance() + fetchPositions() + + const interval = setInterval(() => { + fetchStatus() + fetchBalance() + fetchPositions() + }, 30000) + return () => clearInterval(interval) + }, []) + + // Timer effect for countdown + useEffect(() => { + let countdownInterval = null + + if (status?.isActive && status?.nextAnalysisIn > 0) { + setNextAnalysisCountdown(status.nextAnalysisIn) + + countdownInterval = setInterval(() => { + setNextAnalysisCountdown(prev => { + if (prev <= 1) { + // Refresh status when timer reaches 0 + fetchStatus() + return 0 + } + return prev - 1 + }) + }, 1000) + } else { + setNextAnalysisCountdown(0) + } + + return () => { + if (countdownInterval) { + clearInterval(countdownInterval) + } + } + }, [status?.nextAnalysisIn, status?.isActive]) + + // Helper function to format countdown time + const formatCountdown = (seconds) => { + if (seconds <= 0) return 'Analyzing now...' + + const hours = Math.floor(seconds / 3600) + const minutes = Math.floor((seconds % 3600) / 60) + const secs = seconds % 60 + + if (hours > 0) { + return `${hours}h ${minutes}m ${secs}s` + } else if (minutes > 0) { + return `${minutes}m ${secs}s` + } else { + return `${secs}s` + } + } + + const toggleTimeframe = (timeframe) => { + setConfig(prev => ({ + ...prev, + selectedTimeframes: prev.selectedTimeframes.includes(timeframe) + ? prev.selectedTimeframes.filter(tf => tf !== timeframe) + : [...prev.selectedTimeframes, timeframe] + })) + } + + const fetchStatus = async () => { + try { + const response = await fetch('/api/automation/status') + const data = await response.json() + console.log('Status fetched:', data) // Debug log + if (data.success) { + setStatus(data.status) + } + } catch (error) { + console.error('Failed to fetch status:', error) + } + } + + const fetchBalance = async () => { + try { + const response = await fetch('/api/drift/balance') + const data = await response.json() + if (data.success) { + setBalance(data) + } + } catch (error) { + console.error('Failed to fetch balance:', error) + } + } + + const fetchPositions = async () => { + try { + const response = await fetch('/api/drift/positions') + const data = await response.json() + if (data.success) { + setPositions(data.positions || []) + } + } catch (error) { + console.error('Failed to fetch positions:', error) + } + } + + const handleStart = async () => { + console.log('Start button clicked') // Debug log + setLoading(true) + try { + // Ensure we have selectedTimeframes before starting + if (config.selectedTimeframes.length === 0) { + alert('Please select at least one timeframe for analysis') + setLoading(false) + return + } + + console.log('Starting automation with config:', { + ...config, + selectedTimeframes: config.selectedTimeframes + }) + + 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 { + setLoading(false) + } + } + + const handleStop = async () => { + console.log('Stop button clicked') // Debug log + setLoading(true) + try { + const response = await fetch('/api/automation/stop', { + method: 'POST' + }) + const data = await response.json() + console.log('Stop response:', data) // Debug log + 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 { + setLoading(false) + } + } + + return ( +
+
+ 🚀 NEW AUTOMATION V2 - MULTI-TIMEFRAME READY 🚀 +
+ +
+
+

Automated Trading V2

+

Drift Protocol - Multi-Timeframe Analysis

+
+
+ + {status?.isActive ? ( + + ) : ( + + )} +
+
+ +
+ {/* Configuration Panel */} +
+
+

Configuration

+ + {/* Trading Mode */} +
+
+ +
+ + +
+
+ +
+ + {/* Symbol and Position Size */} +
+
+ + +
+ +
+ + { + const percentage = parseFloat(e.target.value); + const newAmount = balance ? (parseFloat(balance.availableBalance) * percentage / 100) : 100; + setConfig({ + ...config, + balancePercentage: percentage, + tradingAmount: Math.round(newAmount) + }); + }} + disabled={status?.isActive} + /> +
+ 10% + 50% + 100% +
+
+
+ + {/* MULTI-TIMEFRAME SELECTION */} +
+ + + {/* Timeframe Checkboxes */} +
+ {timeframes.map(tf => ( + + ))} +
+ + {/* Selected Timeframes Display */} + {config.selectedTimeframes.length > 0 && ( +
+
+ Selected: + {config.selectedTimeframes.map(tf => timeframes.find(t => t.value === tf)?.label).filter(Boolean).join(', ')} + +
+
+ 💡 Multiple timeframes provide more robust analysis +
+
+ )} + + {/* Quick Selection Buttons */} +
+ + + +
+
+ + {/* AI Risk Management Notice */} +
+
+ 🧠 +

AI-Powered Risk Management

+
+

+ Stop loss and take profit levels are automatically calculated by the AI based on: +

+
    +
  • • Multi-timeframe technical analysis
  • +
  • • Market volatility and support/resistance levels
  • +
  • • Real-time risk assessment and position sizing
  • +
  • • Learning from previous trade outcomes
  • +
+
+

+ ✅ Ultra-tight scalping enabled (0.5%+ stop losses proven effective) +

+
+
+
+
+ + {/* Status Panels */} +
+ {/* Account Status */} +
+
+

Account Status

+ +
+ {balance ? ( +
+
+ Available Balance: + ${parseFloat(balance.availableBalance).toFixed(2)} +
+
+ Account Value: + ${parseFloat(balance.accountValue || balance.availableBalance).toFixed(2)} +
+
+ Unrealized P&L: + 0 ? 'text-green-400' : balance.unrealizedPnl < 0 ? 'text-red-400' : 'text-gray-400'}`}> + ${parseFloat(balance.unrealizedPnl || 0).toFixed(2)} + +
+
+ Open Positions: + {positions.length} +
+
+ ) : ( +
+
Loading account data...
+
+ )} +
+ + {/* Bot Status */} +
+

Bot Status

+ {status ? ( +
+
+ Status: + + {status.isActive ? 'ACTIVE' : 'STOPPED'} + +
+
+ Mode: + + {status.mode} + +
+
+ Protocol: + DRIFT +
+
+ Symbol: + {status.symbol} +
+
+ Timeframes: + + {config.selectedTimeframes.map(tf => timeframes.find(t => t.value === tf)?.label).filter(Boolean).join(', ')} + +
+
+ ) : ( +

Loading bot status...

+ )} +
+ + {/* Analysis Progress */} + {status?.analysisProgress && ( +
+
+

Analysis Progress

+
+ Session: {status.analysisProgress.sessionId.split('-').pop()} +
+
+
+ {/* Overall Progress */} +
+ Step {status.analysisProgress.currentStep} of {status.analysisProgress.totalSteps} + + {Math.round((status.analysisProgress.currentStep / status.analysisProgress.totalSteps) * 100)}% + +
+
+
+
+ + {/* Timeframe Progress */} + {status.analysisProgress.timeframeProgress && ( +
+
+ + Analyzing {status.analysisProgress.timeframeProgress.currentTimeframe || 'timeframes'} + + + {status.analysisProgress.timeframeProgress.current}/{status.analysisProgress.timeframeProgress.total} + +
+
+ )} + + {/* Detailed Steps */} +
+ {status.analysisProgress.steps.map((step, index) => ( +
+ {/* Status Icon */} +
+ {step.status === 'active' ? '⏳' : + step.status === 'completed' ? '✓' : + step.status === 'error' ? '✗' : + index + 1} +
+ + {/* Step Info */} +
+
+ {step.title} +
+
+ {step.details || step.description} +
+
+ + {/* Duration */} + {step.duration && ( +
+ {(step.duration / 1000).toFixed(1)}s +
+ )} +
+ ))} +
+
+
+ )} + + {/* Analysis Timer */} + {status?.isActive && !status?.analysisProgress && ( +
+
+

Analysis Timer

+
+ Cycle #{status.currentCycle || 0} +
+
+
+
+
+ {formatCountdown(nextAnalysisCountdown)} +
+
+ {nextAnalysisCountdown > 0 ? 'Next Analysis In' : 'Analysis Starting Soon'} +
+
+
+
0 ? + `${Math.max(0, 100 - (nextAnalysisCountdown / status.analysisInterval) * 100)}%` : + '0%' + }} + >
+
+
+ Analysis Interval: {Math.floor((status.analysisInterval || 0) / 60)}m +
+
+
+ )} + + {/* Individual Timeframe Results */} + {status?.individualTimeframeResults && status.individualTimeframeResults.length > 0 && ( +
+

Timeframe Analysis

+
+ {status.individualTimeframeResults.map((result, index) => ( +
+
+ + {timeframes.find(tf => tf.value === result.timeframe)?.label || result.timeframe} + + + {result.recommendation} + +
+
+
+ {result.confidence}% +
+
+ confidence +
+
+
+ ))} +
+
+
+ ✅ Last Updated: {status.individualTimeframeResults[0]?.timestamp ? + new Date(status.individualTimeframeResults[0].timestamp).toLocaleTimeString() : + 'N/A' + } +
+
+
+ )} + + {/* Trading Metrics */} +
+

Trading Metrics

+
+
+
+ ${balance ? parseFloat(balance.accountValue || balance.availableBalance).toFixed(2) : '0.00'} +
+
Portfolio
+
+
+
+ {balance ? parseFloat(balance.leverage || 0).toFixed(1) : '0.0'}% +
+
Leverage Used
+
+
+
+ ${balance ? parseFloat(balance.unrealizedPnl || 0).toFixed(2) : '0.00'} +
+
Unrealized P&L
+
+
+
+ {positions.length} +
+
Open Positions
+
+
+
+
+
+
+ ) +} diff --git a/prisma/prisma/dev.db b/prisma/prisma/dev.db index cb0f180..d4675a6 100644 Binary files a/prisma/prisma/dev.db and b/prisma/prisma/dev.db differ