'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',
selectedTimeframes: ['60'], // Multi-timeframe support
tradingAmount: 100,
balancePercentage: 50, // Default to 50% of available balance
})
const [status, setStatus] = useState(null)
const [balance, setBalance] = useState(null)
const [positions, setPositions] = useState([])
const [loading, setLoading] = useState(false)
const [monitorData, setMonitorData] = useState(null)
useEffect(() => {
fetchStatus()
fetchBalance()
fetchPositions()
fetchMonitorData()
fetchMonitorData()
const interval = setInterval(() => {
fetchStatus()
fetchBalance()
fetchPositions()
fetchMonitorData()
}, 300000) // 5 minutes instead of 30 seconds
return () => clearInterval(interval)
}, [])
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 response:', data) // Debug log
if (response.ok && !data.error) {
setStatus(data) // Status data is returned directly, not wrapped in 'success'
} else {
console.error('Status API error:', data.error || 'Unknown error')
}
} 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 fetchMonitorData = async () => {
try {
const response = await fetch('/api/automation/position-monitor')
const data = await response.json()
if (data.success) {
setMonitorData(data.monitor)
}
} catch (error) {
console.error('Failed to fetch monitor data:', 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('๐ Starting automation...')
setLoading(true)
try {
if (config.selectedTimeframes.length === 0) {
console.error('No timeframes selected')
setLoading(false)
return
}
const automationConfig = {
symbol: config.symbol,
selectedTimeframes: config.selectedTimeframes,
mode: config.mode,
tradingAmount: config.tradingAmount,
leverage: config.leverage,
stopLoss: config.stopLoss,
takeProfit: config.takeProfit
}
const response = await fetch('/api/automation/start', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(automationConfig)
})
const data = await response.json()
if (data.success) {
console.log('โ
Automation started successfully')
fetchStatus()
} else {
console.error('Failed to start automation:', data.error)
}
} catch (error) {
console.error('Failed to start automation:', error)
} finally {
setLoading(false)
}
}
const handleStop = async () => {
console.log('๐ Stopping automation...')
setLoading(true)
try {
const response = await fetch('/api/automation/stop', {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
})
const data = await response.json()
if (data.success) {
console.log('โ
Automation stopped successfully')
fetchStatus()
} else {
console.error('Failed to stop automation:', data.error)
}
} catch (error) {
console.error('Failed to stop automation:', error)
} finally {
setLoading(false)
}
}
const handleEmergencyStop = async () => {
console.log('๐จ Emergency stop triggered!')
setLoading(true)
try {
const response = await fetch('/api/automation/emergency-stop', {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
})
const data = await response.json()
if (data.success) {
console.log('โ
Emergency stop completed successfully')
fetchStatus()
fetchPositions()
fetchMonitorData()
fetchMonitorData()
} else {
console.error('Emergency stop failed:', data.error)
}
} catch (error) {
console.error('Emergency stop error:', error)
} finally {
setLoading(false)
}
}
const generateTestDecision = async () => {
console.log('๐งช Generating test AI decision...')
setLoading(true)
try {
const response = await fetch('/api/automation/test-decision', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'generate_test_decision',
analysis: {
recommendation: 'STRONG BUY',
confidence: 89,
reasoning: `๐ฏ BULLISH CONVERGENCE DETECTED:
๐ Technical Analysis:
โข RSI bounced from oversold (28โ54) showing strong recovery momentum
โข MACD histogram turning positive with bullish crossover confirmed
โข Price broke above key resistance at $185.40 with 3x normal volume
โข 20 EMA (184.92) providing strong support, price trending above all major EMAs
๐ Market Structure:
โข Higher lows pattern intact since yesterday's session
โข Volume profile shows accumulation at current levels
โข Order book depth favoring buyers (67% buy-side liquidity)
โก Entry Trigger:
โข Breakout candle closed above $186.00 resistance with conviction
โข Next resistance target: $189.75 (2.1% upside potential)
โข Risk/Reward ratio: 1:2.3 (excellent risk management setup)
๐ก๏ธ Risk Management:
โข Stop loss at $184.20 (1.0% below entry) protects against false breakout
โข Position sizing optimized for 2% account risk tolerance`,
stopLoss: 184.20,
takeProfit: 189.75,
currentPrice: 186.12,
stopLossPercent: '1.0% protective stop'
},
config: {
selectedTimeframes: config.selectedTimeframes,
symbol: config.symbol,
mode: config.mode,
enableTrading: config.enableTrading,
tradingAmount: 62
}
})
})
const data = await response.json()
if (data.success) {
console.log('โ
Test decision generated successfully')
fetchStatus() // Refresh to show the decision
} else {
console.error('Failed to generate test decision:', data.error)
}
} catch (error) {
console.error('Test decision error:', error)
} finally {
setLoading(false)
}
}
const analyzeExistingPosition = async () => {
console.log('๐ Analyzing existing position...')
setLoading(true)
try {
// First get the current position data
const positionResponse = await fetch('/api/automation/position-monitor')
const positionData = await positionResponse.json()
if (positionData.success && positionData.monitor.hasPosition) {
// Analyze the existing position
const response = await fetch('/api/automation/analyze-position', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'analyze_existing_position',
positionData: positionData.monitor.position
})
})
const data = await response.json()
if (data.success) {
console.log('โ
Position analysis generated successfully')
fetchStatus() // Refresh to show the analysis
} else {
console.error('Failed to analyze position:', data.error)
}
} else {
console.log('โน๏ธ No position found to analyze')
alert('No active position found to analyze')
}
} catch (error) {
console.error('Position analysis error:', error)
} finally {
setLoading(false)
}
}
return (
{/* Top Grid: Automation Control (3 cols) + Bot Status (1 col) */}
{/* ๐ค Automation Control Panel */}
{/* Header with Start/Stop Button */}
{/* Header with Start/Stop Button */}
๐ค Automation Control
{status?.isActive ? (
<>
>
) : (
)}
{/* Always available buttons */}
{/* Trading Mode - Side by Side Radio Buttons with Logos */}
{/* Symbol and Position Size */}
{/* 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 || tf).filter(Boolean).join(', ')}
๐ก Multiple timeframes provide more robust analysis
)}
{/* Quick Selection Buttons - Made Bigger */}
{/* Status and Info Panel */}
{/* Status */}
๐ค Bot Status
Status:
{status?.isActive ? 'RUNNING' : 'STOPPED'}
{status?.isActive && (
<>
Symbol:
{status.symbol}
Mode:
{status.mode}
Timeframes:
{status.timeframes?.map(tf => timeframes.find(t => t.value === tf)?.label || tf).join(', ')}
>
)}
{/* Rate Limit Notification */}
{status?.rateLimitHit && (
โ ๏ธ Rate Limit Reached
{status.rateLimitMessage && (
{status.rateLimitMessage}
)}
Automation stopped automatically. Please recharge your OpenAI account to continue.
)}
{/* AI Reasoning & Decision Analysis Panel - Improved Layout */}
๐ง AI Trading Analysis
{status?.lastDecision ? 'Analysis Available' : 'Waiting for Analysis'}
{status?.lastDecision ? (
{/* Quick Summary Row */}
Recommendation
{status.lastDecision.recommendation || 'HOLD'}
{status.lastDecision.isRetrospective && (
๐ Retroactive
)}
Confidence
= 80 ? 'text-green-300' :
status.lastDecision.confidence >= 70 ? 'text-yellow-300' :
'text-red-300'
}`}>
{status.lastDecision.confidence}%
Min: {status.lastDecision.minConfidenceRequired}%
Status
{status.lastDecision.executed ? 'โ
EXECUTED' : 'โ NOT EXECUTED'}
{new Date(status.lastDecision.timestamp).toLocaleTimeString()}
{status.lastDecision.executed && status.lastDecision.executionDetails && (
Leverage
{status.lastDecision.executionDetails.leverage}x
AI Calculated
)}
{/* Main Content Grid */}
{/* AI Reasoning - Left Column */}
๐ฏ
Why This Decision?
{status.lastDecision.reasoning}
{/* Execution Error (if any) */}
{!status.lastDecision.executed && status.lastDecision.executionError && (
โ Execution Failed
{status.lastDecision.executionError}
)}
{/* Trade Details - Right Column */}
{status.lastDecision.executed && status.lastDecision.executionDetails && (
{/* Entry & Exit Strategy */}
๐
Entry & Exit Strategy
Entry Price:
${status.lastDecision.executionDetails.currentPrice?.toFixed(4)}
Position Size:
${status.lastDecision.executionDetails.amount}
Side:
{status.lastDecision.executionDetails.side}
Stop Loss:
${status.lastDecision.executionDetails.stopLoss?.toFixed(4)}
Take Profit:
${status.lastDecision.executionDetails.takeProfit?.toFixed(4)}
{status.lastDecision.executionDetails.txId && (
TX ID:
{status.lastDecision.executionDetails.txId.substring(0, 8)}...
)}
{/* AI Leverage Reasoning */}
โก
AI Leverage Calculation
{status.lastDecision.executionDetails.aiReasoning}
)}
) : (
๐ค
AI Analysis Standby
The AI will analyze market conditions and provide detailed reasoning for all trading decisions.
What you'll see when analysis starts:
- โขEntry Strategy: Why AI chose this entry point
- โขStop Loss Logic: Risk management reasoning
- โขTake Profit Target: Profit-taking strategy
- โขLeverage Calculation: AI's risk assessment
- โขConfidence Analysis: Probability scoring
- โขExecution Status: Trade confirmation
)}
{/* Legacy Last Decision Panel - Hidden when new panel is active */}
{status?.lastDecision && false && (
๐ง Last Decision
{/* Decision Header */}
{status.lastDecision.executed ? 'โ
EXECUTED' : 'โ NOT EXECUTED'}
{new Date(status.lastDecision.timestamp).toLocaleTimeString()}
{/* Analysis Details */}
Recommendation:
{status.lastDecision.recommendation || 'HOLD'}
Confidence:
= 80 ? 'text-green-400' :
status.lastDecision.confidence >= 70 ? 'text-yellow-400' :
'text-red-400'
}`}>
{status.lastDecision.confidence}%
(min: {status.lastDecision.minConfidenceRequired}%)
Reasoning:
{status.lastDecision.reasoning}
{/* Execution Details (if executed) */}
{status.lastDecision.executed && status.lastDecision.executionDetails && (
๐ฐ Execution Details
Side:
{status.lastDecision.executionDetails.side}
Amount:
${status.lastDecision.executionDetails.amount}
Entry:
${status.lastDecision.executionDetails.currentPrice?.toFixed(2)}
Leverage:
{status.lastDecision.executionDetails.leverage}x
{/* SL/TP Details */}
{(status.lastDecision.executionDetails.stopLoss || status.lastDecision.executionDetails.takeProfit) && (
๐ก๏ธ Risk Management
{status.lastDecision.executionDetails.stopLoss && (
Stop Loss:
${status.lastDecision.executionDetails.stopLoss.toFixed(2)}
{status.lastDecision.executionDetails.aiStopLossPercent && (
({status.lastDecision.executionDetails.aiStopLossPercent})
)}
)}
{status.lastDecision.executionDetails.takeProfit && (
Take Profit:
${status.lastDecision.executionDetails.takeProfit.toFixed(2)}
)}
{status.lastDecision.executionDetails.stopLoss && status.lastDecision.executionDetails.takeProfit && (
Risk/Reward: 1:2 ratio
)}
)}
{/* AI Leverage Reasoning */}
{status.lastDecision.executionDetails.aiReasoning && (
๐ง AI Leverage Decision
{status.lastDecision.executionDetails.aiReasoning}
)}
{/* Transaction ID */}
{status.lastDecision.executionDetails.txId && (
TX ID:
{status.lastDecision.executionDetails.txId.substring(0, 20)}...
)}
)}
{/* Execution Error (if failed) */}
{!status.lastDecision.executed && status.lastDecision.executionError && (
โ Execution Failed
{status.lastDecision.executionError}
)}
)}
{/* Position Monitor */}
{monitorData && (
๐ Position Monitor
Has Position:
{monitorData.hasPosition ? 'โ
YES' : 'โ NO'}
Risk Level:
{monitorData.riskLevel}
Next Action: {monitorData.nextAction}
{monitorData.orphanedOrderCleanup && (
{monitorData.orphanedOrderCleanup.success ? 'โ
Cleanup Success' : 'โ Cleanup Failed'}
{monitorData.orphanedOrderCleanup.message}
)}
)}
{/* Balance */}
{balance && (
๏ฟฝ Account Balance
Available:
${parseFloat(balance.availableBalance).toFixed(2)}
Total:
${parseFloat(balance.totalCollateral).toFixed(2)}
Positions:
{balance.positions || 0}
)}
{/* Positions */}
{positions.length > 0 && (
๐ Open Positions
{positions.map((position, index) => (
{position.symbol}
{position.side}
Size:
${position.size}
{position.entryPrice && (
Entry:
${position.entryPrice}
)}
{position.markPrice && (
Mark:
${position.markPrice}
)}
{position.pnl !== undefined && (
PnL:
= 0 ? 'text-green-400' : 'text-red-400'
}`}>
${position.pnl >= 0 ? '+' : ''}${position.pnl}
)}
))}
)}
)
}