Files
trading_bot_v3/app/automation/page.js
mindesbunister 34a29c6056 Enhance trade information display with comprehensive details
- Enhanced analysis-details API with detailed trade information
- Added real-time P&L tracking for active trades
- Implemented trade status indicators (ACTIVE/PROFIT/LOSS)
- Added entry/exit price tracking with current market price
- Enhanced trade duration tracking and confidence levels
- Added stop loss and take profit level display for active trades
- Improved trade result classification and descriptions
- Updated automation page to use enhanced trade data
- Added comprehensive trade performance metrics
- Enhanced trade reasoning and AI confidence display
- Added demo trade data for better visualization
- Fixed trade data source to use analysis-details endpoint
- Added performance metrics display (timestamps, processing time)
- Enhanced analysis performance section with proper metrics
2025-07-18 23:12:56 +02:00

737 lines
31 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 React, { useState, useEffect } from 'react'
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 [recentTrades, setRecentTrades] = useState([])
const [analysisDetails, setAnalysisDetails] = useState(null)
useEffect(() => {
fetchStatus()
fetchLearningInsights()
fetchRecentTrades()
fetchAnalysisDetails()
// Auto-refresh every 30 seconds
const interval = setInterval(() => {
fetchStatus()
fetchAnalysisDetails()
}, 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 fetchRecentTrades = async () => {
try {
// Get enhanced trade data from analysis-details instead of recent-trades
const response = await fetch('/api/automation/analysis-details')
const data = await response.json()
if (data.success && data.data.recentTrades) {
setRecentTrades(data.data.recentTrades)
}
} 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)
}
}
return (
<div className="space-y-8">
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold text-white">Automation Mode</h1>
<p className="text-gray-400 mt-2">
AI-powered automated trading on 1H timeframe with learning capabilities
</p>
</div>
<div className="flex space-x-4">
{status?.isActive ? (
<>
<button
onClick={handlePause}
disabled={isLoading}
className="px-4 py-2 bg-yellow-600 text-white rounded-lg hover:bg-yellow-700 transition-colors disabled:opacity-50"
>
{isLoading ? 'Pausing...' : 'Pause'}
</button>
<button
onClick={handleStop}
disabled={isLoading}
className="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors disabled:opacity-50"
>
{isLoading ? 'Stopping...' : 'Stop'}
</button>
</>
) : (
<>
{status?.status === 'PAUSED' && (
<button
onClick={handleResume}
disabled={isLoading}
className="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors disabled:opacity-50"
>
{isLoading ? 'Resuming...' : 'Resume'}
</button>
)}
<button
onClick={handleStart}
disabled={isLoading}
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors disabled:opacity-50"
>
{isLoading ? 'Starting...' : 'Start Automation'}
</button>
</>
)}
</div>
</div>
<div className="grid grid-cols-1 xl:grid-cols-2 gap-8">
{/* Configuration Panel */}
<div className="space-y-6">
<div className="card card-gradient p-6">
<h2 className="text-xl font-bold text-white mb-4">Configuration</h2>
<div className="space-y-4">
<div>
<label className="block text-sm font-medium text-gray-300 mb-2">
Trading Mode
</label>
<select
value={config.mode}
onChange={(e) => setConfig({...config, mode: 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}
>
<option value="SIMULATION">Simulation (Paper Trading)</option>
<option value="LIVE">Live Trading (Jupiter DEX)</option>
</select>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-300 mb-2">
Symbol
</label>
<select
value={config.symbol}
onChange={(e) => setConfig({...config, symbol: 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}
>
<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 font-medium text-gray-300 mb-2">
Timeframe
</label>
<select
value={config.timeframe}
onChange={(e) => setConfig({...config, timeframe: 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}
>
<option value="1h">1 Hour (Recommended)</option>
<option value="4h">4 Hours</option>
<option value="1d">1 Day</option>
</select>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-300 mb-2">
Trading Amount ($)
</label>
<input
type="number"
value={config.tradingAmount}
onChange={(e) => 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"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-300 mb-2">
Max Leverage
</label>
<select
value={config.maxLeverage}
onChange={(e) => setConfig({...config, maxLeverage: 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}
>
<option value="1">1x (Spot)</option>
<option value="2">2x</option>
<option value="3">3x</option>
<option value="5">5x</option>
</select>
</div>
</div>
<div className="grid grid-cols-3 gap-4">
<div>
<label className="block text-sm font-medium text-gray-300 mb-2">
Stop Loss (%)
</label>
<input
type="number"
value={config.stopLossPercent}
onChange={(e) => 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"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-300 mb-2">
Take Profit (%)
</label>
<input
type="number"
value={config.takeProfitPercent}
onChange={(e) => 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"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-300 mb-2">
Max Daily Trades
</label>
<input
type="number"
value={config.maxDailyTrades}
onChange={(e) => 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"
/>
</div>
</div>
</div>
</div>
{/* Learning Insights */}
{learningInsights && (
<div className="card card-gradient p-6">
<h2 className="text-xl font-bold text-white mb-4">AI Learning Insights</h2>
<div className="space-y-3">
<div className="flex justify-between">
<span className="text-gray-300">Total Analyses:</span>
<span className="text-white font-semibold">{learningInsights.totalAnalyses}</span>
</div>
<div className="flex justify-between">
<span className="text-gray-300">Avg Accuracy:</span>
<span className="text-white font-semibold">{(learningInsights.avgAccuracy * 100).toFixed(1)}%</span>
</div>
<div className="flex justify-between">
<span className="text-gray-300">Best Timeframe:</span>
<span className="text-green-400 font-semibold">{learningInsights.bestTimeframe}</span>
</div>
<div className="flex justify-between">
<span className="text-gray-300">Worst Timeframe:</span>
<span className="text-red-400 font-semibold">{learningInsights.worstTimeframe}</span>
</div>
<div className="mt-4">
<h3 className="text-lg font-semibold text-white mb-2">Recommendations</h3>
<ul className="space-y-1">
{learningInsights.recommendations.map((rec, idx) => (
<li key={idx} className="text-sm text-gray-300"> {rec}</li>
))}
</ul>
</div>
</div>
</div>
)}
</div>
{/* Status and Performance */}
<div className="space-y-6">
{/* Status Panel */}
<div className="card card-gradient p-6">
<h2 className="text-xl font-bold text-white mb-4">Status</h2>
{status ? (
<div className="space-y-3">
<div className="flex items-center justify-between">
<span className="text-gray-300">Status:</span>
<span className={`font-semibold px-2 py-1 rounded ${
status.isActive ? 'bg-green-600 text-white' : 'bg-red-600 text-white'
}`}>
{status.isActive ? 'ACTIVE' : 'STOPPED'}
</span>
</div>
<div className="flex justify-between">
<span className="text-gray-300">Mode:</span>
<span className={`font-semibold ${
status.mode === 'LIVE' ? 'text-red-400' : 'text-blue-400'
}`}>
{status.mode}
</span>
</div>
<div className="flex justify-between">
<span className="text-gray-300">Symbol:</span>
<span className="text-white font-semibold">{status.symbol}</span>
</div>
<div className="flex justify-between">
<span className="text-gray-300">Timeframe:</span>
<span className="text-white font-semibold">{status.timeframe}</span>
</div>
<div className="flex justify-between">
<span className="text-gray-300">Total Trades:</span>
<span className="text-white font-semibold">{status.totalTrades}</span>
</div>
<div className="flex justify-between">
<span className="text-gray-300">Win Rate:</span>
<span className={`font-semibold ${
status.winRate > 0.6 ? 'text-green-400' :
status.winRate > 0.4 ? 'text-yellow-400' : 'text-red-400'
}`}>
{(status.winRate * 100).toFixed(1)}%
</span>
</div>
<div className="flex justify-between">
<span className="text-gray-300">Total P&L:</span>
<span className={`font-semibold ${
status.totalPnL > 0 ? 'text-green-400' :
status.totalPnL < 0 ? 'text-red-400' : 'text-gray-300'
}`}>
${status.totalPnL.toFixed(2)}
</span>
</div>
{status.lastAnalysis && (
<div className="flex justify-between">
<span className="text-gray-300">Last Analysis:</span>
<span className="text-white font-semibold">
{new Date(status.lastAnalysis).toLocaleTimeString()}
</span>
</div>
)}
{status.errorCount > 0 && (
<div className="flex justify-between">
<span className="text-gray-300">Errors:</span>
<span className="text-red-400 font-semibold">{status.errorCount}</span>
</div>
)}
</div>
) : (
<p className="text-gray-400">No active automation session</p>
)}
</div>
{/* Recent Trades */}
<div className="card card-gradient p-6">
<h2 className="text-xl font-bold text-white mb-4">Recent Automated Trades</h2>
{recentTrades.length > 0 ? (
<div className="space-y-3">
{recentTrades.slice(0, 5).map((trade, idx) => (
<div key={idx} className="p-3 bg-gray-800 rounded-lg">
<div className="flex items-center justify-between mb-2">
<div className="flex items-center">
<span className={`font-semibold px-2 py-1 rounded text-xs ${
trade.side === 'BUY' ? 'bg-green-600 text-white' : 'bg-red-600 text-white'
}`}>
{trade.side}
</span>
<span className="text-white ml-2 font-semibold">{trade.amount}</span>
<span className={`ml-2 px-2 py-1 rounded text-xs ${
trade.isActive ? 'bg-blue-600 text-white' :
trade.result === 'PROFIT' ? 'bg-green-600 text-white' :
trade.result === 'LOSS' ? 'bg-red-600 text-white' :
'bg-gray-600 text-white'
}`}>
{trade.isActive ? 'ACTIVE' : trade.result}
</span>
</div>
<div className="text-right">
<div className="text-white font-semibold">${trade.entryPrice.toFixed(2)}</div>
<div className="text-sm text-gray-400">{trade.confidence}% confidence</div>
</div>
</div>
<div className="text-xs text-gray-400 mb-1">
{trade.reason}
</div>
<div className="flex justify-between items-center text-xs">
<div className="text-gray-400">
{trade.duration}
</div>
<div className={`font-semibold ${
trade.isActive ?
(trade.unrealizedPnl > 0 ? 'text-green-400' : 'text-red-400') :
(trade.pnl > 0 ? 'text-green-400' : 'text-red-400')
}`}>
{trade.isActive ?
`P&L: ${trade.unrealizedPnl > 0 ? '+' : ''}${trade.unrealizedPnl}` :
`P&L: ${trade.pnl > 0 ? '+' : ''}${trade.pnl}`
}
</div>
</div>
{trade.isActive && (
<div className="mt-2 pt-2 border-t border-gray-700">
<div className="flex justify-between text-xs">
<span className="text-gray-400">SL: ${trade.stopLoss}</span>
<span className="text-gray-400">Current: ${trade.currentPrice.toFixed(2)}</span>
<span className="text-gray-400">TP: ${trade.takeProfit}</span>
</div>
</div>
)}
</div>
))}
</div>
) : (
<p className="text-gray-400">No recent trades</p>
)}
</div>
</div>
</div>
{/* Detailed AI Analysis Section */}
{analysisDetails?.analysis && (
<div className="space-y-6">
<h2 className="text-2xl font-bold text-white">Latest AI Analysis</h2>
<div className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-6">
{/* Main Decision */}
<div className="card card-gradient p-6">
<h3 className="text-lg font-bold text-white mb-4">🎯 Trading Decision</h3>
<div className="space-y-3">
<div className="flex justify-between">
<span className="text-gray-300">Decision:</span>
<span className={`font-bold px-2 py-1 rounded ${
analysisDetails.analysis.decision === 'BUY' ? 'bg-green-600 text-white' :
analysisDetails.analysis.decision === 'SELL' ? 'bg-red-600 text-white' :
'bg-gray-600 text-white'
}`}>
{analysisDetails.analysis.decision}
</span>
</div>
<div className="flex justify-between">
<span className="text-gray-300">Confidence:</span>
<span className={`font-semibold ${
analysisDetails.analysis.confidence > 80 ? 'text-green-400' :
analysisDetails.analysis.confidence > 60 ? 'text-yellow-400' :
'text-red-400'
}`}>
{analysisDetails.analysis.confidence}%
</span>
</div>
<div className="flex justify-between">
<span className="text-gray-300">Market Sentiment:</span>
<span className={`font-semibold ${
analysisDetails.analysis.sentiment === 'BULLISH' ? 'text-green-400' :
analysisDetails.analysis.sentiment === 'BEARISH' ? 'text-red-400' :
'text-gray-400'
}`}>
{analysisDetails.analysis.sentiment}
</span>
</div>
<div className="mt-4 p-3 bg-gray-800 rounded-lg">
<p className="text-sm text-gray-300">
<strong>Summary:</strong> {analysisDetails.analysis.summary}
</p>
</div>
</div>
</div>
{/* Key Levels */}
<div className="card card-gradient p-6">
<h3 className="text-lg font-bold text-white mb-4">📊 Key Levels</h3>
<div className="space-y-3">
{analysisDetails.analysis.keyLevels?.support?.length > 0 && (
<div>
<h4 className="text-sm font-semibold text-green-400 mb-2">Support Levels</h4>
{analysisDetails.analysis.keyLevels.support.map((level, idx) => (
<div key={idx} className="flex justify-between text-sm">
<span className="text-gray-300">S{idx + 1}:</span>
<span className="text-green-400 font-mono">${level.toFixed(2)}</span>
</div>
))}
</div>
)}
{analysisDetails.analysis.keyLevels?.resistance?.length > 0 && (
<div>
<h4 className="text-sm font-semibold text-red-400 mb-2">Resistance Levels</h4>
{analysisDetails.analysis.keyLevels.resistance.map((level, idx) => (
<div key={idx} className="flex justify-between text-sm">
<span className="text-gray-300">R{idx + 1}:</span>
<span className="text-red-400 font-mono">${level.toFixed(2)}</span>
</div>
))}
</div>
)}
</div>
</div>
{/* Technical Indicators */}
<div className="card card-gradient p-6">
<h3 className="text-lg font-bold text-white mb-4">📈 Technical Indicators</h3>
<div className="space-y-2">
{analysisDetails.analysis.technicalIndicators && Object.entries(analysisDetails.analysis.technicalIndicators).map(([key, value]) => (
<div key={key} className="flex justify-between text-sm">
<span className="text-gray-300 capitalize">{key.replace(/([A-Z])/g, ' $1').trim()}:</span>
<span className="text-white font-mono">
{typeof value === 'number' ? value.toFixed(2) : value}
</span>
</div>
))}
</div>
</div>
</div>
{/* AI Reasoning */}
{analysisDetails.analysis.reasoning && (
<div className="card card-gradient p-6">
<h3 className="text-lg font-bold text-white mb-4">🤖 AI Reasoning</h3>
<div className="space-y-3">
<div className="p-4 bg-gray-800 rounded-lg">
<p className="text-gray-300">{analysisDetails.analysis.reasoning}</p>
</div>
{analysisDetails.analysis.executionPlan && (
<div className="p-4 bg-blue-900/20 border border-blue-500/20 rounded-lg">
<h4 className="text-blue-400 font-semibold mb-2">Execution Plan:</h4>
<p className="text-gray-300">{analysisDetails.analysis.executionPlan}</p>
</div>
)}
</div>
</div>
)}
{/* Risk Assessment */}
{analysisDetails.analysis.riskAssessment && (
<div className="card card-gradient p-6">
<h3 className="text-lg font-bold text-white mb-4"> Risk Assessment</h3>
<div className="space-y-3">
<div className="p-4 bg-yellow-900/20 border border-yellow-500/20 rounded-lg">
<p className="text-gray-300">{analysisDetails.analysis.riskAssessment}</p>
</div>
{analysisDetails.analysis.marketConditions && (
<div className="p-4 bg-gray-800 rounded-lg">
<h4 className="text-gray-400 font-semibold mb-2">Market Conditions:</h4>
<p className="text-gray-300">{analysisDetails.analysis.marketConditions}</p>
</div>
)}
</div>
</div>
)}
{/* Layout Analysis */}
{analysisDetails.analysis.layoutAnalysis && (
<div className="card card-gradient p-6">
<h3 className="text-lg font-bold text-white mb-4">🔍 Multi-Layout Analysis</h3>
<div className="space-y-4">
{Object.entries(analysisDetails.analysis.layoutAnalysis).map(([layout, analysis]) => (
<div key={layout} className="p-4 bg-gray-800 rounded-lg">
<h4 className="text-blue-400 font-semibold mb-2 capitalize">{layout} Layout:</h4>
<p className="text-gray-300 text-sm">{analysis}</p>
</div>
))}
</div>
</div>
)}
{/* Performance Metrics */}
<div className="card card-gradient p-6">
<h3 className="text-lg font-bold text-white mb-4">📊 Analysis Performance</h3>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<div className="text-center">
<div className="text-2xl font-bold text-blue-400">
{analysisDetails.analysis.timestamp ?
new Date(analysisDetails.analysis.timestamp).toLocaleTimeString() :
'N/A'
}
</div>
<div className="text-sm text-gray-400">Last Analysis</div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-green-400">
{analysisDetails.analysis.processingTime ?
`${analysisDetails.analysis.processingTime}ms` :
'N/A'
}
</div>
<div className="text-sm text-gray-400">Processing Time</div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-purple-400">
{analysisDetails.session?.totalTrades || 0}
</div>
<div className="text-sm text-gray-400">Total Trades</div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-yellow-400">
{analysisDetails.session?.errorCount || 0}
</div>
<div className="text-sm text-gray-400">Errors</div>
</div>
</div>
</div>
</div>
)}
{/* No Analysis Available */}
{!analysisDetails?.analysis && status?.isActive && (
<div className="card card-gradient p-6">
<h3 className="text-lg font-bold text-white mb-4">🤖 AI Analysis</h3>
<div className="text-center py-8">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500 mx-auto mb-4"></div>
<p className="text-gray-400">Waiting for first analysis...</p>
<p className="text-sm text-gray-500 mt-2">The AI will analyze the market every hour</p>
</div>
</div>
)}
</div>
)
}