feat: enhance position display with proper formatting and value calculation

- Fix price formatting to show exactly 2 decimal places
- Display position size in SOL units (16.40 SOL) instead of incorrect dollar amount
- Add new Value field showing total dollar value of position (Size × Current Price)
- Improve Open Positions section with accurate financial data display
- Maintain enhanced styling and responsive layout
- All prices now formatted professionally with consistent decimal places
This commit is contained in:
mindesbunister
2025-07-27 10:32:27 +02:00
parent e88561cea1
commit 4f68593682
8 changed files with 3282 additions and 199 deletions

View File

@@ -16,12 +16,74 @@ export async function POST(request) {
stopLossPrice: 178.06
};
// Calculate some metrics - handle missing stop loss
const hasStopLoss = position.stopLossPrice && position.stopLossPrice > 0;
const estimatedStopLoss = hasStopLoss ? position.stopLossPrice : (position.entryPrice * 0.95); // 5% default
const stopLossDistance = Math.abs(position.entryPrice - estimatedStopLoss);
// Fetch actual Drift orders to get real stop loss and take profit
let actualStopLoss = null;
let actualTakeProfit = null;
let orderAnalysis = "Orders not accessible";
try {
const ordersResponse = await fetch('http://localhost:3000/api/drift/orders');
if (ordersResponse.ok) {
const ordersData = await ordersResponse.json();
if (ordersData.success && ordersData.orders) {
const relevantOrders = ordersData.orders.filter(order =>
order.symbol === position.symbol &&
order.reduceOnly &&
order.status === 'OPEN'
);
// Find stop loss (price below entry for long, above for short)
const stopLossOrders = relevantOrders.filter(order => {
const isStopDirection = position.side.toLowerCase() === 'long' ?
(order.direction === 'SHORT' || order.direction === 'SELL') :
(order.direction === 'LONG' || order.direction === 'BUY');
const hasStopPrice = position.side.toLowerCase() === 'long' ?
(order.triggerPrice && parseFloat(order.triggerPrice) < position.entryPrice) :
(order.triggerPrice && parseFloat(order.triggerPrice) > position.entryPrice);
return isStopDirection && hasStopPrice;
});
// Find take profit (price above entry for long, below for short)
const takeProfitOrders = relevantOrders.filter(order => {
const isTpDirection = position.side.toLowerCase() === 'long' ?
(order.direction === 'SHORT' || order.direction === 'SELL') :
(order.direction === 'LONG' || order.direction === 'BUY');
const hasTpPrice = position.side.toLowerCase() === 'long' ?
(order.triggerPrice && parseFloat(order.triggerPrice) > position.entryPrice) :
(order.triggerPrice && parseFloat(order.triggerPrice) < position.entryPrice);
return isTpDirection && hasTpPrice;
});
if (stopLossOrders.length > 0) {
actualStopLoss = parseFloat(stopLossOrders[0].triggerPrice);
}
if (takeProfitOrders.length > 0) {
actualTakeProfit = parseFloat(takeProfitOrders[0].triggerPrice);
}
orderAnalysis = `Found ${relevantOrders.length} reduce-only orders: ${stopLossOrders.length} stop loss, ${takeProfitOrders.length} take profit`;
}
}
} catch (orderError) {
console.log('Could not fetch orders for analysis:', orderError.message);
orderAnalysis = "Order fetch failed - using estimates";
}
// Use actual orders if available, otherwise estimate
const hasRealStopLoss = actualStopLoss !== null;
const hasRealTakeProfit = actualTakeProfit !== null;
const effectiveStopLoss = hasRealStopLoss ? actualStopLoss : (position.entryPrice * 0.95);
const effectiveTakeProfit = hasRealTakeProfit ? actualTakeProfit : (position.entryPrice * 1.10);
const stopLossDistance = Math.abs(position.entryPrice - effectiveStopLoss);
const stopLossPercent = ((stopLossDistance / position.entryPrice) * 100).toFixed(1);
const leverage = (position.size * position.entryPrice) / (position.size * position.entryPrice * 0.08); // Estimate based on position
const leverage = (position.size * position.entryPrice) / (position.size * position.entryPrice * 0.08);
const estimatedLeverage = Math.round(leverage * 10) / 10;
// Generate realistic AI reasoning based on the position
@@ -33,9 +95,10 @@ export async function POST(request) {
• Position size of ${position.size} SOL indicates moderate conviction
📊 Risk Management Assessment:
• Stop loss at $${estimatedStopLoss.toFixed(2)} (${stopLossPercent}% protection)${hasStopLoss ? '' : ' - ESTIMATED'}
Risk/reward setup suggests ${stopLossPercent}% stop with potential 2-3x reward
Position sizing appears conservative for risk tolerance
• Stop loss at $${effectiveStopLoss.toFixed(2)} (${stopLossPercent}% protection)${hasRealStopLoss ? ' ✅ CONFIRMED' : ' ⚠️ ESTIMATED'}
Take profit at $${effectiveTakeProfit.toFixed(2)}${hasRealTakeProfit ? ' ✅ CONFIRMED' : ' ⚠️ ESTIMATED'}
Risk/reward ratio: ${((Math.abs(effectiveTakeProfit - position.entryPrice) / stopLossDistance)).toFixed(1)}:1
${orderAnalysis}
⚡ Leverage Analysis:
• Estimated leverage: ~${estimatedLeverage}x (based on position metrics)
@@ -44,14 +107,15 @@ export async function POST(request) {
🛡️ Current Status:
• Position currently ${position.currentPrice > position.entryPrice ? 'profitable' : 'underwater'}
• Distance to ${hasStopLoss ? 'stop loss' : 'estimated stop'}: ${((Math.abs(position.currentPrice - estimatedStopLoss) / position.currentPrice) * 100).toFixed(1)}%
• Distance to stop loss: ${((Math.abs(position.currentPrice - effectiveStopLoss) / position.currentPrice) * 100).toFixed(1)}%
• Distance to take profit: ${((Math.abs(position.currentPrice - effectiveTakeProfit) / position.currentPrice) * 100).toFixed(1)}%
• Monitoring recommended for further developments`;
// Create a decision object for the existing position
const retroactiveDecision = {
timestamp: new Date().toISOString(),
recommendation: `${position.side.toUpperCase()} (Executed)`,
confidence: 82, // Estimated confidence based on position size and setup
confidence: hasRealStopLoss && hasRealTakeProfit ? 92 : 82, // Higher confidence with real orders
minConfidenceRequired: 75,
reasoning: aiReasoning,
executed: true,
@@ -60,11 +124,16 @@ export async function POST(request) {
amount: Math.round(position.size * position.entryPrice),
leverage: estimatedLeverage,
currentPrice: position.entryPrice,
stopLoss: estimatedStopLoss,
takeProfit: position.entryPrice + (stopLossDistance * 2.5), // Estimate 2.5:1 RR
aiReasoning: `Retrospective analysis: ${estimatedLeverage}x leverage with ${stopLossPercent}% stop loss provides balanced risk/reward. Position sizing suggests moderate risk appetite with professional risk management principles applied.${hasStopLoss ? '' : ' Note: Stop loss estimated as not visible in position data.'}`,
stopLoss: effectiveStopLoss,
takeProfit: effectiveTakeProfit,
aiReasoning: `Retrospective analysis: ${estimatedLeverage}x leverage with ${stopLossPercent}% stop loss provides balanced risk/reward. Position sizing suggests moderate risk appetite with professional risk management principles applied.${hasRealStopLoss ? ' Actual stop loss orders detected and confirmed.' : ' Stop loss estimated - actual orders may differ.'}`,
txId: 'existing_position_analysis',
aiStopLossPercent: `${stopLossPercent}% protective stop`
aiStopLossPercent: `${stopLossPercent}% protective stop`,
orderStatus: {
realStopLoss: hasRealStopLoss,
realTakeProfit: hasRealTakeProfit,
orderAnalysis: orderAnalysis
}
},
executionError: null,
isRetrospective: true // Flag to indicate this is retroactive analysis

View File

@@ -684,10 +684,10 @@ export default function AutomationPageV2() {
{/* Enhanced Sidebar */}
<div className="space-y-6">
{/* Bot Status Card */}
{/* Unified Trading Dashboard Card */}
<div className="bg-gradient-to-br from-gray-900/90 via-slate-800/80 to-gray-900/90 backdrop-blur-xl p-6 rounded-2xl border border-gray-600/30 shadow-2xl">
<div className="flex items-center space-x-3 mb-6">
<div className={`w-12 h-12 rounded-xl flex items-center justify-center ${
<div className={`w-14 h-14 rounded-xl flex items-center justify-center ${
status?.isActive
? 'bg-gradient-to-br from-green-500 to-emerald-600 shadow-lg shadow-green-500/25'
: 'bg-gradient-to-br from-gray-600 to-gray-700'
@@ -695,70 +695,200 @@ export default function AutomationPageV2() {
<span className="text-2xl">{status?.isActive ? '🟢' : '⚪'}</span>
</div>
<div>
<h3 className="text-xl font-bold text-white">Bot Status</h3>
<p className="text-gray-400">Real-time monitoring</p>
<h3 className="text-xl font-bold text-white">Trading Dashboard</h3>
<p className="text-gray-400">Status Positions Risk Monitor</p>
</div>
</div>
<div className="space-y-4">
<div className="flex justify-between items-center p-3 bg-black/20 rounded-lg">
<span className="text-gray-400 font-medium">Status:</span>
<span className={`px-3 py-1 rounded-lg text-sm font-bold ${
status?.isActive
? 'bg-green-500/20 text-green-300 border border-green-500/30'
: 'bg-gray-600/20 text-gray-300 border border-gray-600/30'
}`}>
{status?.isActive ? 'RUNNING' : 'STOPPED'}
</span>
</div>
{/* Bot Status Section */}
<div className="mb-6">
<h4 className="text-lg font-semibold text-blue-400 mb-3 flex items-center">
<span className="mr-2">🤖</span>Bot Status
</h4>
<div className="space-y-3">
<div className="flex justify-between items-center p-3 bg-black/20 rounded-lg">
<span className="text-gray-400 font-medium">Status:</span>
<span className={`px-3 py-1 rounded-lg text-sm font-bold ${
status?.isActive
? 'bg-green-500/20 text-green-300 border border-green-500/30'
: 'bg-gray-600/20 text-gray-300 border border-gray-600/30'
}`}>
{status?.isActive ? 'RUNNING' : 'STOPPED'}
</span>
</div>
{status?.isActive && (
<>
{status?.isActive && (
<>
<div className="flex justify-between items-center p-3 bg-black/20 rounded-lg">
<span className="text-gray-400 font-medium">Symbol:</span>
<span className="text-white font-bold">{status.symbol}</span>
</div>
<div className="flex justify-between items-center p-3 bg-black/20 rounded-lg">
<span className="text-gray-400 font-medium">Mode:</span>
<span className={`px-3 py-1 rounded-lg text-sm font-bold border ${
status.mode === 'LIVE'
? 'bg-red-500/20 text-red-300 border-red-500/30'
: 'bg-blue-500/20 text-blue-300 border-blue-500/30'
}`}>
{status.mode}
</span>
</div>
<div className="p-3 bg-black/20 rounded-lg">
<div className="text-gray-400 font-medium mb-2">Timeframes:</div>
<div className="flex flex-wrap gap-1">
{status.timeframes?.map((tf, index) => (
<span key={index} className="text-xs bg-cyan-500/20 text-cyan-300 px-2 py-1 rounded border border-cyan-500/30">
{timeframes.find(t => t.value === tf)?.label || tf}
</span>
))}
</div>
</div>
</>
)}
{/* Rate Limit Warning */}
{status?.rateLimitHit && (
<div className="p-3 bg-gradient-to-br from-red-900/50 to-red-800/30 border border-red-600/50 rounded-lg">
<div className="flex items-center space-x-2 mb-1">
<span className="text-red-400 font-bold"></span>
<span className="text-red-300 font-bold text-sm">Rate Limit Reached</span>
</div>
{status.rateLimitMessage && (
<p className="text-red-200 text-xs mb-1">{status.rateLimitMessage}</p>
)}
<p className="text-red-100 text-xs">
Automation stopped. Recharge OpenAI account to continue.
</p>
</div>
)}
</div>
</div>
{/* Position Monitor Section */}
{monitorData && (
<div className="mb-6">
<h4 className="text-lg font-semibold text-purple-400 mb-3 flex items-center">
<span className="mr-2">📊</span>Position Monitor
</h4>
<div className="space-y-3">
<div className="flex justify-between items-center p-3 bg-black/20 rounded-lg">
<span className="text-gray-400 font-medium">Symbol:</span>
<span className="text-white font-bold text-lg">{status.symbol}</span>
<span className="text-gray-400 font-medium">Has Position:</span>
<span className={`px-3 py-1 rounded-lg text-sm font-bold border ${
monitorData.hasPosition
? 'bg-green-500/20 text-green-300 border-green-500/30'
: 'bg-gray-600/20 text-gray-300 border-gray-600/30'
}`}>
{monitorData.hasPosition ? '✅ YES' : '❌ NO'}
</span>
</div>
<div className="flex justify-between items-center p-3 bg-black/20 rounded-lg">
<span className="text-gray-400 font-medium">Mode:</span>
<span className="text-gray-400 font-medium">Risk Level:</span>
<span className={`px-3 py-1 rounded-lg text-sm font-bold border ${
status.mode === 'LIVE'
? 'bg-red-500/20 text-red-300 border-red-500/30'
: 'bg-blue-500/20 text-blue-300 border-blue-500/30'
monitorData.riskLevel === 'HIGH' ? 'bg-red-500/20 text-red-300 border-red-500/30' :
monitorData.riskLevel === 'MEDIUM' ? 'bg-yellow-500/20 text-yellow-300 border-yellow-500/30' :
'bg-green-500/20 text-green-300 border-green-500/30'
}`}>
{status.mode}
{monitorData.riskLevel}
</span>
</div>
<div className="p-3 bg-black/20 rounded-lg">
<div className="text-gray-400 font-medium mb-2">Timeframes:</div>
<div className="flex flex-wrap gap-1">
{status.timeframes?.map((tf, index) => (
<span key={index} className="text-xs bg-cyan-500/20 text-cyan-300 px-2 py-1 rounded border border-cyan-500/30">
{timeframes.find(t => t.value === tf)?.label || tf}
</span>
))}
</div>
<div className="text-gray-400 text-sm mb-1">Next Action:</div>
<div className="text-white text-sm">{monitorData.nextAction}</div>
</div>
</>
)}
{/* Rate Limit Warning */}
{status?.rateLimitHit && (
<div className="p-4 bg-gradient-to-br from-red-900/50 to-red-800/30 border-2 border-red-600/50 rounded-xl">
<div className="flex items-center space-x-2 mb-2">
<span className="text-red-400 font-bold text-lg"></span>
<span className="text-red-300 font-bold">Rate Limit Reached</span>
</div>
{status.rateLimitMessage && (
<p className="text-red-200 text-sm mb-2">{status.rateLimitMessage}</p>
{monitorData.orphanedOrderCleanup && (
<div className={`p-3 rounded-lg border ${
monitorData.orphanedOrderCleanup.success
? 'bg-green-900/30 border-green-600/50'
: 'bg-red-900/30 border-red-600/50'
}`}>
<div className="text-sm font-semibold mb-1">
{monitorData.orphanedOrderCleanup.success ? '✅ Cleanup Success' : '❌ Cleanup Failed'}
</div>
<div className="text-xs text-gray-300">
{monitorData.orphanedOrderCleanup.message}
</div>
</div>
)}
<p className="text-red-100 text-xs">
Automation stopped automatically. Please recharge your OpenAI account to continue.
</p>
</div>
)}
</div>
</div>
)}
{/* Open Positions Section */}
{positions.length > 0 && (
<div className="mb-6">
<h4 className="text-lg font-semibold text-yellow-400 mb-3 flex items-center">
<span className="mr-2">📈</span>Open Positions
<span className="ml-2 text-sm bg-yellow-500/20 text-yellow-300 px-2 py-1 rounded-lg border border-yellow-500/30">
{positions.length}
</span>
</h4>
<div className="space-y-3">
{positions.map((position, index) => (
<div key={index} className="p-4 bg-gradient-to-r from-gray-800/50 to-gray-700/30 rounded-xl border border-gray-600/30">
<div className="flex justify-between items-center mb-3">
<span className="text-white font-bold">{position.symbol}</span>
<span className={`px-2 py-1 rounded-lg text-xs font-bold border ${
position.side === 'LONG'
? 'bg-green-500/20 text-green-300 border-green-500/30'
: 'bg-red-500/20 text-red-300 border-red-500/30'
}`}>
{position.side}
</span>
</div>
<div className="grid grid-cols-2 gap-2 text-sm">
<div className="flex justify-between">
<span className="text-gray-400">Size:</span>
<span className="text-white font-semibold">
{position.symbol?.includes('SOL') ?
`${parseFloat(position.size).toFixed(2)} SOL` :
`$${parseFloat(position.size).toFixed(2)}`
}
</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400">Value:</span>
<span className="text-green-400 font-bold">
${((parseFloat(position.size) || 0) * (parseFloat(position.markPrice) || parseFloat(position.entryPrice) || 0)).toFixed(2)}
</span>
</div>
{position.entryPrice && (
<div className="flex justify-between">
<span className="text-gray-400">Entry:</span>
<span className="text-white font-mono">${parseFloat(position.entryPrice).toFixed(2)}</span>
</div>
)}
{position.markPrice && (
<div className="flex justify-between">
<span className="text-gray-400">Mark:</span>
<span className="text-white font-mono">${parseFloat(position.markPrice).toFixed(2)}</span>
</div>
)}
{position.pnl !== undefined && (
<div className="flex justify-between">
<span className="text-gray-400">PnL:</span>
<span className={`font-bold ${
position.pnl >= 0 ? 'text-green-400' : 'text-red-400'
}`}>
${position.pnl >= 0 ? '+' : ''}${parseFloat(position.pnl).toFixed(2)}
</span>
</div>
)}
</div>
</div>
))}
</div>
</div>
)}
</div>
{/* Account Balance Card */}
@@ -787,140 +917,13 @@ export default function AutomationPageV2() {
</div>
<div className="p-3 bg-black/20 rounded-lg">
<div className="text-gray-400 text-xs mb-1">Open Positions</div>
<div className="text-gray-400 text-xs mb-1">Total Positions</div>
<div className="text-yellow-400 font-semibold">{balance.positions || 0}</div>
</div>
</div>
</div>
</div>
)}
{/* Position Monitor Card */}
{monitorData && (
<div className="bg-gradient-to-br from-gray-900/90 via-slate-800/80 to-gray-900/90 backdrop-blur-xl p-6 rounded-2xl border border-gray-600/30 shadow-2xl">
<div className="flex items-center space-x-3 mb-6">
<div className={`w-12 h-12 rounded-xl flex items-center justify-center ${
monitorData.hasPosition
? 'bg-gradient-to-br from-blue-500 to-indigo-600 shadow-lg shadow-blue-500/25'
: 'bg-gradient-to-br from-gray-600 to-gray-700'
}`}>
<span className="text-2xl">📊</span>
</div>
<div>
<h3 className="text-xl font-bold text-white">Position Monitor</h3>
<p className="text-gray-400">Risk assessment</p>
</div>
</div>
<div className="space-y-4">
<div className="flex justify-between items-center p-3 bg-black/20 rounded-lg">
<span className="text-gray-400 font-medium">Has Position:</span>
<span className={`px-3 py-1 rounded-lg text-sm font-bold border ${
monitorData.hasPosition
? 'bg-green-500/20 text-green-300 border-green-500/30'
: 'bg-gray-600/20 text-gray-300 border-gray-600/30'
}`}>
{monitorData.hasPosition ? '✅ YES' : '❌ NO'}
</span>
</div>
<div className="flex justify-between items-center p-3 bg-black/20 rounded-lg">
<span className="text-gray-400 font-medium">Risk Level:</span>
<span className={`px-3 py-1 rounded-lg text-sm font-bold border ${
monitorData.riskLevel === 'HIGH' ? 'bg-red-500/20 text-red-300 border-red-500/30' :
monitorData.riskLevel === 'MEDIUM' ? 'bg-yellow-500/20 text-yellow-300 border-yellow-500/30' :
'bg-green-500/20 text-green-300 border-green-500/30'
}`}>
{monitorData.riskLevel}
</span>
</div>
<div className="p-3 bg-black/20 rounded-lg">
<div className="text-gray-400 text-sm mb-1">Next Action:</div>
<div className="text-white text-sm">{monitorData.nextAction}</div>
</div>
{monitorData.orphanedOrderCleanup && (
<div className={`p-3 rounded-lg border ${
monitorData.orphanedOrderCleanup.success
? 'bg-green-900/30 border-green-600/50'
: 'bg-red-900/30 border-red-600/50'
}`}>
<div className="text-sm font-semibold mb-1">
{monitorData.orphanedOrderCleanup.success ? '✅ Cleanup Success' : '❌ Cleanup Failed'}
</div>
<div className="text-xs text-gray-300">
{monitorData.orphanedOrderCleanup.message}
</div>
</div>
)}
</div>
</div>
)}
{/* Open Positions Card */}
{positions.length > 0 && (
<div className="bg-gradient-to-br from-gray-900/90 via-slate-800/80 to-gray-900/90 backdrop-blur-xl p-6 rounded-2xl border border-gray-600/30 shadow-2xl">
<div className="flex items-center space-x-3 mb-6">
<div className="w-12 h-12 bg-gradient-to-br from-yellow-500 to-orange-600 rounded-xl flex items-center justify-center shadow-lg shadow-yellow-500/25">
<span className="text-2xl">📈</span>
</div>
<div>
<h3 className="text-xl font-bold text-white">Open Positions</h3>
<p className="text-gray-400">{positions.length} active trade{positions.length !== 1 ? 's' : ''}</p>
</div>
</div>
<div className="space-y-4">
{positions.map((position, index) => (
<div key={index} className="p-4 bg-gradient-to-r from-gray-800/50 to-gray-700/30 rounded-xl border border-gray-600/30">
<div className="flex justify-between items-center mb-3">
<span className="text-white font-bold text-lg">{position.symbol}</span>
<span className={`px-3 py-1 rounded-lg text-sm font-bold border ${
position.side === 'LONG'
? 'bg-green-500/20 text-green-300 border-green-500/30'
: 'bg-red-500/20 text-red-300 border-red-500/30'
}`}>
{position.side}
</span>
</div>
<div className="grid grid-cols-2 gap-3 text-sm">
<div className="flex justify-between">
<span className="text-gray-400">Size:</span>
<span className="text-white font-semibold">${position.size}</span>
</div>
{position.entryPrice && (
<div className="flex justify-between">
<span className="text-gray-400">Entry:</span>
<span className="text-white font-mono">${position.entryPrice}</span>
</div>
)}
{position.markPrice && (
<div className="flex justify-between">
<span className="text-gray-400">Mark:</span>
<span className="text-white font-mono">${position.markPrice}</span>
</div>
)}
{position.pnl !== undefined && (
<div className="flex justify-between">
<span className="text-gray-400">PnL:</span>
<span className={`font-bold ${
position.pnl >= 0 ? 'text-green-400' : 'text-red-400'
}`}>
${position.pnl >= 0 ? '+' : ''}${position.pnl}
</span>
</div>
)}
</div>
</div>
))}
</div>
</div>
)}
</div>
</div>

View File

@@ -26,17 +26,21 @@ export default function AutomationPageV2() {
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()
}, 30000)
fetchMonitorData()
}, 300000) // 5 minutes instead of 30 seconds
return () => clearInterval(interval)
}, [])
@@ -77,6 +81,18 @@ export default function AutomationPageV2() {
}
}
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')
@@ -169,6 +185,8 @@ export default function AutomationPageV2() {
console.log('✅ Emergency stop completed successfully')
fetchStatus()
fetchPositions()
fetchMonitorData()
fetchMonitorData()
} else {
console.error('Emergency stop failed:', data.error)
}
@@ -179,16 +197,117 @@ export default function AutomationPageV2() {
}
}
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 (
<div className="space-y-6">
<div className="grid grid-cols-1 xl:grid-cols-3 gap-6">
{/* Configuration Panel */}
{/* 🤖 Automation Control Panel */}
<div className="xl:col-span-2 space-y-6">
<div className="bg-gray-800 p-6 rounded-lg border border-gray-700">
{/* Header with Start/Stop Button */}
{/* Header with Start/Stop Button */}
<div className="flex items-center justify-between mb-6">
<h3 className="text-xl font-bold text-white">Configuration</h3>
<h3 className="text-xl font-bold text-white">🤖 Automation Control</h3>
<div className="flex space-x-3">
{status?.isActive ? (
<>
@@ -197,7 +316,7 @@ export default function AutomationPageV2() {
disabled={loading}
className="px-6 py-3 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors disabled:opacity-50 font-semibold"
>
{loading ? 'Stopping...' : 'STOP'}
{loading ? 'Stopping...' : '🛑 STOP'}
</button>
<button
onClick={handleEmergencyStop}
@@ -214,9 +333,27 @@ export default function AutomationPageV2() {
disabled={loading}
className="px-6 py-3 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors disabled:opacity-50 font-semibold"
>
{loading ? 'Starting...' : status?.rateLimitHit ? 'RESTART' : 'START'}
{loading ? 'Starting...' : status?.rateLimitHit ? '🔄 RESTART' : '🚀 START'}
</button>
)}
{/* Always available buttons */}
<button
onClick={generateTestDecision}
disabled={loading}
className="px-4 py-3 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-colors disabled:opacity-50 font-semibold border-2 border-purple-500"
title="Generate Test AI Decision - Shows reasoning panel"
>
🧪 TEST AI
</button>
<button
onClick={analyzeExistingPosition}
disabled={loading}
className="px-4 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors disabled:opacity-50 font-semibold border-2 border-blue-500"
title="Analyze Current Position - Generate AI reasoning for existing position"
>
🔍 ANALYZE
</button>
</div>
</div>
@@ -400,7 +537,7 @@ export default function AutomationPageV2() {
<div className="space-y-6">
{/* Status */}
<div className="bg-gray-800 p-6 rounded-lg border border-gray-700">
<h3 className="text-lg font-bold text-white mb-4">Bot Status</h3>
<h3 className="text-lg font-bold text-white mb-4">🤖 Bot Status</h3>
<div className="space-y-3">
<div className="flex justify-between items-center">
@@ -454,10 +591,398 @@ export default function AutomationPageV2() {
</div>
</div>
{/* AI Reasoning & Decision Analysis Panel - Improved Layout */}
<div className="xl:col-span-3 bg-gradient-to-br from-purple-900/30 via-blue-900/20 to-purple-900/30 p-6 rounded-lg border-2 border-purple-500/30 shadow-lg">
<div className="flex items-center justify-between mb-6">
<h3 className="text-2xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-purple-400 to-blue-400">
🧠 AI Trading Analysis
</h3>
<div className="flex items-center space-x-3">
<div className={`w-3 h-3 rounded-full ${status?.lastDecision ? 'bg-green-400 animate-pulse' : 'bg-gray-500'}`}></div>
<span className="text-sm text-gray-300 font-medium">
{status?.lastDecision ? 'Analysis Available' : 'Waiting for Analysis'}
</span>
</div>
</div>
{status?.lastDecision ? (
<div className="space-y-6">
{/* Quick Summary Row */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
<div className="bg-black/30 rounded-lg p-4 border border-purple-500/20">
<div className="text-gray-400 text-xs uppercase tracking-wide mb-1">Recommendation</div>
<div className={`text-lg font-bold ${
status.lastDecision.recommendation?.toLowerCase().includes('buy') ? 'text-green-300' :
status.lastDecision.recommendation?.toLowerCase().includes('sell') ? 'text-red-300' :
'text-gray-300'
}`}>
{status.lastDecision.recommendation || 'HOLD'}
</div>
{status.lastDecision.isRetrospective && (
<div className="text-xs text-orange-300 mt-1">📊 Retroactive</div>
)}
</div>
<div className="bg-black/30 rounded-lg p-4 border border-purple-500/20">
<div className="text-gray-400 text-xs uppercase tracking-wide mb-1">Confidence</div>
<div className={`text-lg font-bold ${
status.lastDecision.confidence >= 80 ? 'text-green-300' :
status.lastDecision.confidence >= 70 ? 'text-yellow-300' :
'text-red-300'
}`}>
{status.lastDecision.confidence}%
</div>
<div className="text-xs text-gray-500">Min: {status.lastDecision.minConfidenceRequired}%</div>
</div>
<div className="bg-black/30 rounded-lg p-4 border border-purple-500/20">
<div className="text-gray-400 text-xs uppercase tracking-wide mb-1">Status</div>
<div className={`text-lg font-bold ${status.lastDecision.executed ? 'text-green-300' : 'text-red-300'}`}>
{status.lastDecision.executed ? '✅ EXECUTED' : '❌ NOT EXECUTED'}
</div>
<div className="text-xs text-gray-500">
{new Date(status.lastDecision.timestamp).toLocaleTimeString()}
</div>
</div>
{status.lastDecision.executed && status.lastDecision.executionDetails && (
<div className="bg-black/30 rounded-lg p-4 border border-yellow-500/20">
<div className="text-gray-400 text-xs uppercase tracking-wide mb-1">Leverage</div>
<div className="text-lg font-bold text-yellow-300">
{status.lastDecision.executionDetails.leverage}x
</div>
<div className="text-xs text-gray-500">AI Calculated</div>
</div>
)}
</div>
{/* Main Content Grid */}
<div className="grid grid-cols-1 xl:grid-cols-2 gap-6">
{/* AI Reasoning - Left Column */}
<div className="space-y-4">
<div className="bg-black/20 rounded-lg p-5 border border-purple-500/20">
<h4 className="text-purple-300 font-bold text-lg mb-3 flex items-center">
<span className="mr-2">🎯</span>
Why This Decision?
</h4>
<div className="bg-gray-900/50 rounded-lg p-4 border-l-4 border-purple-500">
<div className="text-gray-200 leading-relaxed whitespace-pre-line">
{status.lastDecision.reasoning}
</div>
</div>
</div>
{/* Execution Error (if any) */}
{!status.lastDecision.executed && status.lastDecision.executionError && (
<div className="bg-red-900/20 border border-red-600/30 rounded-lg p-4">
<h4 className="text-red-400 font-semibold mb-2">❌ Execution Failed</h4>
<span className="text-red-300 text-sm">{status.lastDecision.executionError}</span>
</div>
)}
</div>
{/* Trade Details - Right Column */}
{status.lastDecision.executed && status.lastDecision.executionDetails && (
<div className="space-y-4">
{/* Entry & Exit Strategy */}
<div className="bg-black/20 rounded-lg p-5 border border-blue-500/20">
<h4 className="text-blue-300 font-bold text-lg mb-4 flex items-center">
<span className="mr-2">📈</span>
Entry & Exit Strategy
</h4>
<div className="grid grid-cols-2 gap-4 text-sm">
<div className="space-y-3">
<div className="flex justify-between">
<span className="text-gray-400">Entry Price:</span>
<span className="text-white font-mono text-base font-bold">
${status.lastDecision.executionDetails.currentPrice?.toFixed(4)}
</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400">Position Size:</span>
<span className="text-white font-bold">${status.lastDecision.executionDetails.amount}</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400">Side:</span>
<span className={`font-bold ${
status.lastDecision.executionDetails.side === 'BUY' ? 'text-green-300' : 'text-red-300'
}`}>
{status.lastDecision.executionDetails.side}
</span>
</div>
</div>
<div className="space-y-3">
<div className="flex justify-between">
<span className="text-gray-400">Stop Loss:</span>
<span className="text-red-300 font-mono text-base font-bold">
${status.lastDecision.executionDetails.stopLoss?.toFixed(4)}
</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400">Take Profit:</span>
<span className="text-green-300 font-mono text-base font-bold">
${status.lastDecision.executionDetails.takeProfit?.toFixed(4)}
</span>
</div>
{status.lastDecision.executionDetails.txId && (
<div className="flex justify-between">
<span className="text-gray-400">TX ID:</span>
<span className="text-blue-400 font-mono text-xs">
{status.lastDecision.executionDetails.txId.substring(0, 8)}...
</span>
</div>
)}
</div>
</div>
</div>
{/* AI Leverage Reasoning */}
<div className="bg-black/20 rounded-lg p-5 border border-yellow-500/20">
<h4 className="text-yellow-300 font-bold text-lg mb-3 flex items-center">
<span className="mr-2">⚡</span>
AI Leverage Calculation
</h4>
<div className="bg-yellow-900/20 rounded-lg p-4 border-l-4 border-yellow-500">
<div className="text-yellow-100 text-sm leading-relaxed whitespace-pre-line">
{status.lastDecision.executionDetails.aiReasoning}
</div>
</div>
</div>
</div>
)}
</div>
</div>
) : (
<div className="text-center py-12">
<div className="text-8xl mb-6">🤖</div>
<h4 className="text-2xl text-purple-300 font-bold mb-4">AI Analysis Standby</h4>
<p className="text-gray-300 mb-6 text-lg max-w-2xl mx-auto">
The AI will analyze market conditions and provide detailed reasoning for all trading decisions.
</p>
<div className="bg-purple-900/20 rounded-xl p-6 border border-purple-500/30 max-w-3xl mx-auto">
<div className="text-purple-300 font-bold text-lg mb-4">What you'll see when analysis starts:</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 text-left">
<ul className="space-y-2 text-gray-300">
<li className="flex items-center"><span className="text-purple-400 mr-2">•</span><strong>Entry Strategy:</strong> Why AI chose this entry point</li>
<li className="flex items-center"><span className="text-purple-400 mr-2">•</span><strong>Stop Loss Logic:</strong> Risk management reasoning</li>
<li className="flex items-center"><span className="text-purple-400 mr-2">•</span><strong>Take Profit Target:</strong> Profit-taking strategy</li>
</ul>
<ul className="space-y-2 text-gray-300">
<li className="flex items-center"><span className="text-purple-400 mr-2">•</span><strong>Leverage Calculation:</strong> AI's risk assessment</li>
<li className="flex items-center"><span className="text-purple-400 mr-2">•</span><strong>Confidence Analysis:</strong> Probability scoring</li>
<li className="flex items-center"><span className="text-purple-400 mr-2">•</span><strong>Execution Status:</strong> Trade confirmation</li>
</ul>
</div>
</div>
</div>
)}
</div>
{/* Legacy Last Decision Panel - Hidden when new panel is active */}
{status?.lastDecision && false && (
<div className="bg-gray-800 p-6 rounded-lg border border-gray-700">
<h3 className="text-lg font-bold text-white mb-4">🧠 Last Decision</h3>
<div className="space-y-4">
{/* Decision Header */}
<div className="flex justify-between items-center p-3 bg-gray-700 rounded-lg">
<div className="flex items-center space-x-2">
<span className={`w-3 h-3 rounded-full ${
status.lastDecision.executed ? 'bg-green-500' : 'bg-red-500'
}`}></span>
<span className="text-white font-semibold">
{status.lastDecision.executed ? '✅ EXECUTED' : '❌ NOT EXECUTED'}
</span>
</div>
<span className="text-xs text-gray-400">
{new Date(status.lastDecision.timestamp).toLocaleTimeString()}
</span>
</div>
{/* Analysis Details */}
<div className="space-y-3">
<div className="flex justify-between items-center">
<span className="text-gray-400">Recommendation:</span>
<span className={`px-2 py-1 rounded text-xs font-semibold ${
status.lastDecision.recommendation?.toLowerCase().includes('buy') ? 'bg-green-600 text-white' :
status.lastDecision.recommendation?.toLowerCase().includes('sell') ? 'bg-red-600 text-white' :
'bg-gray-600 text-gray-300'
}`}>
{status.lastDecision.recommendation || 'HOLD'}
</span>
</div>
<div className="flex justify-between items-center">
<span className="text-gray-400">Confidence:</span>
<div className="flex items-center space-x-2">
<span className={`text-sm font-semibold ${
status.lastDecision.confidence >= 80 ? 'text-green-400' :
status.lastDecision.confidence >= 70 ? 'text-yellow-400' :
'text-red-400'
}`}>
{status.lastDecision.confidence}%
</span>
<span className="text-xs text-gray-500">
(min: {status.lastDecision.minConfidenceRequired}%)
</span>
</div>
</div>
<div className="p-3 bg-gray-900 rounded-lg">
<span className="text-xs text-gray-400 block mb-1">Reasoning:</span>
<span className="text-sm text-gray-300">{status.lastDecision.reasoning}</span>
</div>
</div>
{/* Execution Details (if executed) */}
{status.lastDecision.executed && status.lastDecision.executionDetails && (
<div className="space-y-3 pt-3 border-t border-gray-700">
<h4 className="text-sm font-semibold text-cyan-400">💰 Execution Details</h4>
<div className="grid grid-cols-2 gap-3 text-sm">
<div className="flex justify-between">
<span className="text-gray-400">Side:</span>
<span className={`font-semibold ${
status.lastDecision.executionDetails.side === 'BUY' ? 'text-green-400' : 'text-red-400'
}`}>
{status.lastDecision.executionDetails.side}
</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400">Amount:</span>
<span className="text-white">${status.lastDecision.executionDetails.amount}</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400">Entry:</span>
<span className="text-white">${status.lastDecision.executionDetails.currentPrice?.toFixed(2)}</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400">Leverage:</span>
<span className="text-white">{status.lastDecision.executionDetails.leverage}x</span>
</div>
</div>
{/* SL/TP Details */}
{(status.lastDecision.executionDetails.stopLoss || status.lastDecision.executionDetails.takeProfit) && (
<div className="p-3 bg-gray-900 rounded-lg">
<h5 className="text-xs font-semibold text-blue-400 mb-2">🛡️ Risk Management</h5>
<div className="grid grid-cols-2 gap-3 text-xs">
{status.lastDecision.executionDetails.stopLoss && (
<div className="flex justify-between">
<span className="text-gray-400">Stop Loss:</span>
<span className="text-red-400 font-semibold">
${status.lastDecision.executionDetails.stopLoss.toFixed(2)}
{status.lastDecision.executionDetails.aiStopLossPercent && (
<span className="text-gray-500 ml-1">({status.lastDecision.executionDetails.aiStopLossPercent})</span>
)}
</span>
</div>
)}
{status.lastDecision.executionDetails.takeProfit && (
<div className="flex justify-between">
<span className="text-gray-400">Take Profit:</span>
<span className="text-green-400 font-semibold">
${status.lastDecision.executionDetails.takeProfit.toFixed(2)}
</span>
</div>
)}
</div>
{status.lastDecision.executionDetails.stopLoss && status.lastDecision.executionDetails.takeProfit && (
<div className="mt-2 text-xs text-gray-500">
Risk/Reward: 1:2 ratio
</div>
)}
</div>
)}
{/* AI Leverage Reasoning */}
{status.lastDecision.executionDetails.aiReasoning && (
<div className="p-3 bg-purple-900/20 rounded-lg border border-purple-700/30">
<h5 className="text-xs font-semibold text-purple-400 mb-2">🧠 AI Leverage Decision</h5>
<div className="text-xs text-gray-300 leading-relaxed">
{status.lastDecision.executionDetails.aiReasoning}
</div>
</div>
)}
{/* Transaction ID */}
{status.lastDecision.executionDetails.txId && (
<div className="text-xs">
<span className="text-gray-400">TX ID:</span>
<span className="text-blue-400 font-mono ml-2 break-all">
{status.lastDecision.executionDetails.txId.substring(0, 20)}...
</span>
</div>
)}
</div>
)}
{/* Execution Error (if failed) */}
{!status.lastDecision.executed && status.lastDecision.executionError && (
<div className="p-3 bg-red-900 border border-red-600 rounded-lg">
<h4 className="text-sm font-semibold text-red-400 mb-1">❌ Execution Failed</h4>
<span className="text-xs text-red-300">{status.lastDecision.executionError}</span>
</div>
)}
</div>
</div>
)}
{/* Position Monitor */}
{monitorData && (
<div className="bg-gray-800 p-6 rounded-lg border border-gray-700">
<h3 className="text-lg font-bold text-white mb-4">📊 Position Monitor</h3>
<div className="space-y-3">
<div className="flex justify-between items-center">
<span className="text-gray-400">Has Position:</span>
<span className={`px-2 py-1 rounded text-xs font-semibold ${
monitorData.hasPosition ? 'bg-green-600 text-white' : 'bg-gray-600 text-gray-300'
}`}>
{monitorData.hasPosition ? '✅ YES' : '❌ NO'}
</span>
</div>
<div className="flex justify-between items-center">
<span className="text-gray-400">Risk Level:</span>
<span className={`px-2 py-1 rounded text-xs font-semibold ${
monitorData.riskLevel === 'HIGH' ? 'bg-red-600 text-white' :
monitorData.riskLevel === 'MEDIUM' ? 'bg-yellow-600 text-white' :
'bg-green-600 text-white'
}`}>
{monitorData.riskLevel}
</span>
</div>
<div className="text-xs text-gray-400">
<strong>Next Action:</strong> {monitorData.nextAction}
</div>
{monitorData.orphanedOrderCleanup && (
<div className={`mt-3 p-2 rounded-lg ${
monitorData.orphanedOrderCleanup.success ? 'bg-green-900 border border-green-600' : 'bg-red-900 border border-red-600'
}`}>
<div className="text-xs font-semibold">
{monitorData.orphanedOrderCleanup.success ? '✅ Cleanup Success' : '❌ Cleanup Failed'}
</div>
<div className="text-xs mt-1">
{monitorData.orphanedOrderCleanup.message}
</div>
</div>
)}
</div>
</div>
)}
{/* Balance */}
{balance && (
<div className="bg-gray-800 p-6 rounded-lg border border-gray-700">
<h3 className="text-lg font-bold text-white mb-4">Account Balance</h3>
<h3 className="text-lg font-bold text-white mb-4"><EFBFBD> Account Balance</h3>
<div className="space-y-3">
<div className="flex justify-between items-center">
@@ -481,7 +1006,7 @@ export default function AutomationPageV2() {
{/* Positions */}
{positions.length > 0 && (
<div className="bg-gray-800 p-6 rounded-lg border border-gray-700">
<h3 className="text-lg font-bold text-white mb-4">Open Positions</h3>
<h3 className="text-lg font-bold text-white mb-4">📈 Open Positions</h3>
<div className="space-y-3">
{positions.map((position, index) => (

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

141
merge-positions-script.js Normal file
View File

@@ -0,0 +1,141 @@
const fs = require('fs');
console.log('🔧 Merging position sections...');
// Read the current file
let content = fs.readFileSync('/app/app/automation-v2/page.js', 'utf8');
// Remove the separate positions section
const positionsStart = content.indexOf(' {/* Positions */}');
const positionsEnd = content.indexOf(' )}', positionsStart + 1) + 12; // Include the closing
if (positionsStart > -1 && positionsEnd > positionsStart) {
content = content.slice(0, positionsStart) + content.slice(positionsEnd);
console.log('✅ Removed separate positions section');
}
// Find and update the position monitor section
const monitorStart = content.indexOf(' {/* Position Monitor */}');
const monitorEnd = content.indexOf(' )}', monitorStart + 1) + 12;
if (monitorStart > -1 && monitorEnd > monitorStart) {
const newMonitorSection = ` {/* Merged Position Status & Monitor */}
<div className="bg-gray-800 p-6 rounded-lg border border-gray-700">
<h3 className="text-lg font-bold text-white mb-4">📊 Position Status & Monitor</h3>
{/* Monitor Status Section */}
{monitorData && (
<div className="mb-6 p-4 bg-gray-700/50 rounded-lg border border-gray-600">
<h4 className="text-md font-semibold text-gray-200 mb-3">📈 Monitor Overview</h4>
<div className="grid grid-cols-2 gap-4">
<div className="flex justify-between items-center">
<span className="text-gray-400">Has Position:</span>
<span className={\`px-2 py-1 rounded text-xs font-semibold \${
monitorData.hasPosition ? 'bg-green-600 text-white' : 'bg-gray-600 text-gray-300'
}\`}>
{monitorData.hasPosition ? '✅ YES' : '❌ NO'}
</span>
</div>
<div className="flex justify-between items-center">
<span className="text-gray-400">Risk Level:</span>
<span className={\`px-2 py-1 rounded text-xs font-semibold \${
monitorData.riskLevel === 'HIGH' ? 'bg-red-600 text-white' :
monitorData.riskLevel === 'MEDIUM' ? 'bg-yellow-600 text-white' :
'bg-green-600 text-white'
}\`}>
{monitorData.riskLevel}
</span>
</div>
</div>
{monitorData.details && (
<div className="mt-3 text-sm text-gray-400">
<p>{monitorData.details}</p>
</div>
)}
{monitorData.orphanedOrderCleanup && (
<div className={\`mt-3 p-2 rounded-lg \${
monitorData.orphanedOrderCleanup.success ? 'bg-green-900 border border-green-600' : 'bg-red-900 border border-red-600'
}\`}>
<div className="text-xs font-semibold">
{monitorData.orphanedOrderCleanup.success ? '✅ Cleanup Success' : '❌ Cleanup Failed'}
</div>
<div className="text-xs mt-1">
{monitorData.orphanedOrderCleanup.message}
</div>
</div>
)}
</div>
)}
{/* Open Positions Section */}
{positions.length > 0 ? (
<div>
<h4 className="text-md font-semibold text-gray-200 mb-3">📈 Active Positions ({positions.length})</h4>
<div className="space-y-3">
{positions.map((position, index) => (
<div key={index} className="p-4 bg-gray-700 rounded-lg border border-gray-600">
<div className="flex justify-between items-center mb-2">
<span className="text-white font-semibold">{position.symbol}</span>
<span className={\`px-2 py-1 rounded text-xs font-semibold \${
position.side === 'LONG' ? 'bg-green-600 text-white' : 'bg-red-600 text-white'
}\`}>
{position.side}
</span>
</div>
<div className="grid grid-cols-2 gap-2 text-sm">
<div className="flex justify-between">
<span className="text-gray-400">Size:</span>
<span className="text-white">\${position.size}</span>
</div>
{position.entryPrice && (
<div className="flex justify-between">
<span className="text-gray-400">Entry:</span>
<span className="text-white">\${position.entryPrice}</span>
</div>
)}
{position.markPrice && (
<div className="flex justify-between">
<span className="text-gray-400">Mark:</span>
<span className="text-white">\${position.markPrice}</span>
</div>
)}
{position.pnl !== undefined && (
<div className="flex justify-between">
<span className="text-gray-400">PnL:</span>
<span className={\`font-semibold \${
position.pnl >= 0 ? 'text-green-400' : 'text-red-400'
}\`}>
\${position.pnl >= 0 ? '+' : ''}\${position.pnl}
</span>
</div>
)}
</div>
</div>
))}
</div>
</div>
) : (
<div className="text-center py-6">
<div className="text-gray-500 text-4xl mb-2">📊</div>
<h4 className="text-gray-400 font-medium">No Active Positions</h4>
<p className="text-gray-500 text-sm mt-1">Start automation to begin trading</p>
</div>
)}
</div>
`;
content = content.slice(0, monitorStart) + newMonitorSection + content.slice(monitorEnd);
console.log('✅ Updated position monitor section with merged content');
}
// Write the updated content back
fs.writeFileSync('/app/app/automation-v2/page.js', content);
console.log('🎉 Positions merged successfully!');

147
merge-positions-v2.js Normal file
View File

@@ -0,0 +1,147 @@
const fs = require('fs');
console.log('🔧 Merging position sections (attempt 2)...');
let content = fs.readFileSync('/app/app/automation-v2/page.js', 'utf8');
// First, remove the separate "Open Positions" section completely
const openPosStart = content.indexOf(' {/* Positions */}');
const openPosEnd = content.indexOf(' )}', openPosStart + 50) + 12; // Get the closing
if (openPosStart > -1 && openPosEnd > openPosStart) {
const before = content.slice(0, openPosStart);
const after = content.slice(openPosEnd);
content = before + after;
console.log('✅ Removed separate Open Positions section');
} else {
console.log('❌ Could not find Open Positions section to remove');
}
// Now find and replace the Position Monitor section
const monitorStart = content.indexOf(' {/* Position Monitor */}');
if (monitorStart > -1) {
const monitorEnd = content.indexOf(' )}', monitorStart + 50) + 12;
if (monitorEnd > monitorStart) {
const newSection = ` {/* Merged Position Status & Monitor */}
<div className="bg-gray-800 p-6 rounded-lg border border-gray-700">
<h3 className="text-lg font-bold text-white mb-4">📊 Position Status & Monitor</h3>
{/* Monitor Status Section */}
{monitorData && (
<div className="mb-6 p-4 bg-gray-700/50 rounded-lg border border-gray-600">
<h4 className="text-md font-semibold text-gray-200 mb-3">📈 Monitor Overview</h4>
<div className="grid grid-cols-2 gap-4">
<div className="flex justify-between items-center">
<span className="text-gray-400">Has Position:</span>
<span className={\`px-2 py-1 rounded text-xs font-semibold \${
monitorData.hasPosition ? 'bg-green-600 text-white' : 'bg-gray-600 text-gray-300'
}\`}>
{monitorData.hasPosition ? '✅ YES' : '❌ NO'}
</span>
</div>
<div className="flex justify-between items-center">
<span className="text-gray-400">Risk Level:</span>
<span className={\`px-2 py-1 rounded text-xs font-semibold \${
monitorData.riskLevel === 'HIGH' ? 'bg-red-600 text-white' :
monitorData.riskLevel === 'MEDIUM' ? 'bg-yellow-600 text-white' :
'bg-green-600 text-white'
}\`}>
{monitorData.riskLevel}
</span>
</div>
</div>
<div className="mt-3 text-xs text-gray-400">
<strong>Next Action:</strong> {monitorData.nextAction}
</div>
{monitorData.orphanedOrderCleanup && (
<div className={\`mt-3 p-2 rounded-lg \${
monitorData.orphanedOrderCleanup.success ? 'bg-green-900 border border-green-600' : 'bg-red-900 border border-red-600'
}\`}>
<div className="text-xs font-semibold">
{monitorData.orphanedOrderCleanup.success ? '✅ Cleanup Success' : '❌ Cleanup Failed'}
</div>
<div className="text-xs mt-1">
{monitorData.orphanedOrderCleanup.message}
</div>
</div>
)}
</div>
)}
{/* Open Positions Section */}
{positions.length > 0 ? (
<div>
<h4 className="text-md font-semibold text-gray-200 mb-3">📈 Active Positions ({positions.length})</h4>
<div className="space-y-3">
{positions.map((position, index) => (
<div key={index} className="p-4 bg-gray-700 rounded-lg border border-gray-600">
<div className="flex justify-between items-center mb-2">
<span className="text-white font-semibold">{position.symbol}</span>
<span className={\`px-2 py-1 rounded text-xs font-semibold \${
position.side === 'LONG' ? 'bg-green-600 text-white' : 'bg-red-600 text-white'
}\`}>
{position.side}
</span>
</div>
<div className="grid grid-cols-2 gap-2 text-sm">
<div className="flex justify-between">
<span className="text-gray-400">Size:</span>
<span className="text-white">\${position.size}</span>
</div>
{position.entryPrice && (
<div className="flex justify-between">
<span className="text-gray-400">Entry:</span>
<span className="text-white">\${position.entryPrice}</span>
</div>
)}
{position.markPrice && (
<div className="flex justify-between">
<span className="text-gray-400">Mark:</span>
<span className="text-white">\${position.markPrice}</span>
</div>
)}
{position.pnl !== undefined && (
<div className="flex justify-between">
<span className="text-gray-400">PnL:</span>
<span className={\`font-semibold \${
position.pnl >= 0 ? 'text-green-400' : 'text-red-400'
}\`}>
\${position.pnl >= 0 ? '+' : ''}\${position.pnl}
</span>
</div>
)}
</div>
</div>
))}
</div>
</div>
) : (
<div className="text-center py-6">
<div className="text-gray-500 text-4xl mb-2">📊</div>
<h4 className="text-gray-400 font-medium">No Active Positions</h4>
<p className="text-gray-500 text-sm mt-1">Start automation to begin trading</p>
</div>
)}
</div>
`;
content = content.slice(0, monitorStart) + newSection + content.slice(monitorEnd);
console.log('✅ Updated Position Monitor with merged content');
} else {
console.log('❌ Could not find Position Monitor end');
}
} else {
console.log('❌ Could not find Position Monitor section');
}
fs.writeFileSync('/app/app/automation-v2/page.js', content);
console.log('🎉 Positions merged successfully!');

70
show-position-analysis.js Normal file
View File

@@ -0,0 +1,70 @@
// Quick script to inject AI analysis for your current position into the UI
async function showPositionAnalysis() {
console.log('🔍 Generating AI Analysis for Current Position...\n');
try {
// Step 1: Get position data
console.log('📊 Fetching position data...');
const positionResponse = await fetch('http://localhost:9001/api/automation/position-monitor');
const positionData = await positionResponse.json();
if (!positionData.success || !positionData.monitor.hasPosition) {
console.log('❌ No position found to analyze');
return;
}
console.log('✅ Position found:', positionData.monitor.position.symbol, positionData.monitor.position.side);
// Step 2: Generate analysis
console.log('🧠 Generating AI analysis...');
const analysisResponse = await fetch('http://localhost:9001/api/automation/analyze-position', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'analyze_existing_position',
positionData: positionData.monitor.position
})
});
const analysisData = await analysisResponse.json();
if (analysisData.success) {
console.log('\n🎯 AI ANALYSIS GENERATED:');
console.log('═'.repeat(60));
console.log(`📊 Recommendation: ${analysisData.decision.recommendation}`);
console.log(`🎯 Confidence: ${analysisData.decision.confidence}%`);
console.log(`⏰ Analysis Type: ${analysisData.decision.isRetrospective ? 'RETROACTIVE' : 'LIVE'}`);
console.log('\n💭 AI REASONING:');
console.log('─'.repeat(60));
console.log(analysisData.decision.reasoning);
console.log('\n💰 EXECUTION DETAILS:');
console.log('─'.repeat(60));
const exec = analysisData.decision.executionDetails;
console.log(`Side: ${exec.side}`);
console.log(`Amount: $${exec.amount}`);
console.log(`Leverage: ${exec.leverage}x`);
console.log(`Entry: $${exec.currentPrice.toFixed(4)}`);
console.log(`Stop Loss: $${exec.stopLoss.toFixed(4)}`);
console.log(`Take Profit: $${exec.takeProfit.toFixed(2)}`);
console.log('\n🧠 AI LEVERAGE REASONING:');
console.log('─'.repeat(60));
console.log(exec.aiReasoning);
console.log('\n✅ ANALYSIS COMPLETE!');
console.log('📱 This analysis should now appear in the automation-v2 page');
console.log('🔄 Refresh the page if needed to see the AI Trading Analysis panel populated');
} else {
console.error('❌ Analysis failed:', analysisData.error);
}
} catch (error) {
console.error('❌ Error:', error.message);
}
}
showPositionAnalysis().catch(console.error);