Add automation timer and individual timeframe analysis display

Features Added:
 Analysis Timer: Shows countdown to next analysis with progress bar
 Individual Timeframe Results: Display analysis for each timeframe separately
 Real-time Countdown: Updates every second showing time until next analysis
 Enhanced Status API: Includes timing data and individual results
 Cycle Counter: Shows current automation cycle number

UI Improvements:
- Analysis Timer panel with countdown and progress bar
- Individual Timeframe Analysis panel showing recommendation and confidence for each timeframe
- Real-time updates of countdown timer
- Visual indicators for BUY/SELL/HOLD recommendations
- Analysis interval display (15m/1h/etc)

Technical Changes:
- Enhanced AutomationService with timing tracking
- Added nextAnalysisIn, analysisInterval, currentCycle to status
- Individual timeframe results stored and displayed
- Real-time countdown effect in React
- Progress bar visualization of analysis cycle
- Enhanced status API endpoint with automation service integration

Example Display:
 15m analysis: SELL (80% confidence)
 1h analysis: HOLD (65% confidence)

Next Analysis In: 14m 32s [Progress Bar]
Cycle #5 | Analysis Interval: 15m
This commit is contained in:
mindesbunister
2025-07-23 14:39:17 +02:00
parent abc94c06e2
commit a09b4bf8b2
3 changed files with 133 additions and 53 deletions

View File

@@ -30,6 +30,7 @@ export default function AutomationPageV2() {
const [balance, setBalance] = useState(null)
const [positions, setPositions] = useState([])
const [loading, setLoading] = useState(false)
const [nextAnalysisCountdown, setNextAnalysisCountdown] = useState(0)
useEffect(() => {
fetchStatus()
@@ -44,6 +45,51 @@ export default function AutomationPageV2() {
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,
@@ -498,6 +544,82 @@ export default function AutomationPageV2() {
)}
</div>
{/* Analysis Timer */}
{status?.isActive && (
<div className="bg-gray-800 p-6 rounded-lg border border-gray-700">
<div className="flex items-center justify-between mb-4">
<h3 className="text-xl font-bold text-white">Analysis Timer</h3>
<div className="text-xs text-gray-400">
Cycle #{status.currentCycle || 0}
</div>
</div>
<div className="space-y-3">
<div className="text-center">
<div className="text-3xl font-bold text-blue-400 mb-2">
{formatCountdown(nextAnalysisCountdown)}
</div>
<div className="text-sm text-gray-400">
{nextAnalysisCountdown > 0 ? 'Next Analysis In' : 'Analysis Running'}
</div>
</div>
<div className="bg-gray-700 rounded-full h-2">
<div
className="bg-blue-500 h-2 rounded-full transition-all duration-1000"
style={{
width: status.analysisInterval > 0 ?
`${Math.max(0, 100 - (nextAnalysisCountdown / status.analysisInterval) * 100)}%` :
'0%'
}}
></div>
</div>
<div className="text-xs text-gray-400 text-center">
Analysis Interval: {Math.floor((status.analysisInterval || 0) / 60)}m
</div>
</div>
</div>
)}
{/* Individual Timeframe Results */}
{status?.individualTimeframeResults && status.individualTimeframeResults.length > 0 && (
<div className="bg-gray-800 p-6 rounded-lg border border-gray-700">
<h3 className="text-xl font-bold text-white mb-4">Timeframe Analysis</h3>
<div className="space-y-2">
{status.individualTimeframeResults.map((result, index) => (
<div key={index} className="flex items-center justify-between p-3 bg-gray-700/50 rounded-lg">
<div className="flex items-center space-x-3">
<span className="text-cyan-400 font-bold text-sm w-8">
{timeframes.find(tf => tf.value === result.timeframe)?.label || result.timeframe}
</span>
<span className={`font-semibold text-sm px-2 py-1 rounded ${
result.recommendation === 'BUY' ? 'bg-green-600/20 text-green-400' :
result.recommendation === 'SELL' ? 'bg-red-600/20 text-red-400' :
'bg-gray-600/20 text-gray-400'
}`}>
{result.recommendation}
</span>
</div>
<div className="text-right">
<div className="text-white font-semibold text-sm">
{result.confidence}%
</div>
<div className="text-xs text-gray-400">
confidence
</div>
</div>
</div>
))}
</div>
<div className="mt-4 p-3 bg-blue-600/10 border border-blue-600/30 rounded-lg">
<div className="text-xs text-blue-400">
Last Updated: {status.individualTimeframeResults[0]?.timestamp ?
new Date(status.individualTimeframeResults[0].timestamp).toLocaleTimeString() :
'N/A'
}
</div>
</div>
</div>
)}
{/* Trading Metrics */}
<div className="bg-gray-800 p-6 rounded-lg border border-gray-700">
<h3 className="text-xl font-bold text-white mb-4">Trading Metrics</h3>