Features Added: - 🤖 Autonomous AI Risk Management System - 🛡️ Smart Stop Loss Proximity Monitoring - 📊 Real-time Position Monitor with Dark Theme - 🚨 Emergency Stop Buttons on All Pages - 🏖️ Full Beach Mode Operation - Emergency exit analysis (< 1% from SL) - Position review and adjustments (1-2% from SL) - Enhanced monitoring (2-5% from SL) - Opportunity scanning (> 5% from SL) - Beautiful dark theme Position Monitor - Emergency stop buttons on automation pages - Real-time P&L tracking with trend indicators - Beach mode demo script - Autonomous risk manager integration - Position monitoring API endpoints - Enhanced automation with AI leverage calculator - CLI monitoring tools with enhanced display Now you can truly relax on the beach while your AI handles everything! 🏖️🤖💰
302 lines
12 KiB
TypeScript
302 lines
12 KiB
TypeScript
'use client';
|
||
|
||
import { useState, useEffect } from 'react';
|
||
|
||
interface Position {
|
||
symbol: string;
|
||
side: string;
|
||
size: number;
|
||
entryPrice: number;
|
||
currentPrice: number;
|
||
unrealizedPnl: number;
|
||
notionalValue: number;
|
||
}
|
||
|
||
interface StopLossProximity {
|
||
stopLossPrice: number;
|
||
currentPrice: number;
|
||
distancePercent: string;
|
||
isNear: boolean;
|
||
}
|
||
|
||
interface MonitorData {
|
||
hasPosition: boolean;
|
||
position?: Position;
|
||
stopLossProximity?: StopLossProximity;
|
||
riskLevel: string;
|
||
nextAction: string;
|
||
recommendation: string;
|
||
}
|
||
|
||
interface AutomationStatus {
|
||
isActive: boolean;
|
||
mode: string;
|
||
symbol: string;
|
||
timeframes: string[];
|
||
totalCycles: number;
|
||
totalTrades: number;
|
||
lastActivity: string;
|
||
consecutiveErrors: number;
|
||
detailedStatus: string;
|
||
}
|
||
|
||
export default function PositionMonitor() {
|
||
const [monitorData, setMonitorData] = useState<MonitorData | null>(null);
|
||
const [automationStatus, setAutomationStatus] = useState<AutomationStatus | null>(null);
|
||
const [lastUpdate, setLastUpdate] = useState<Date>(new Date());
|
||
const [error, setError] = useState<string>('');
|
||
|
||
const fetchData = async () => {
|
||
try {
|
||
// Fetch position data
|
||
const positionResponse = await fetch('/api/automation/position-monitor');
|
||
const positionResult = await positionResponse.json();
|
||
|
||
// Fetch automation status
|
||
const statusResponse = await fetch('/api/automation/status');
|
||
const statusResult = await statusResponse.json();
|
||
|
||
if (positionResult.success) {
|
||
setMonitorData(positionResult.monitor);
|
||
}
|
||
|
||
setAutomationStatus(statusResult);
|
||
setLastUpdate(new Date());
|
||
setError('');
|
||
} catch (err) {
|
||
setError('Failed to fetch monitoring data');
|
||
console.error('Monitor error:', err);
|
||
}
|
||
};
|
||
|
||
useEffect(() => {
|
||
fetchData();
|
||
const interval = setInterval(fetchData, 10000); // Update every 10 seconds
|
||
return () => clearInterval(interval);
|
||
}, []);
|
||
|
||
const getRiskColor = (risk: string) => {
|
||
switch (risk) {
|
||
case 'HIGH': return 'text-red-500';
|
||
case 'MEDIUM': return 'text-yellow-500';
|
||
case 'LOW': return 'text-green-500';
|
||
default: return 'text-gray-500';
|
||
}
|
||
};
|
||
|
||
const getStopLossStatus = (distancePercent: string) => {
|
||
const distance = parseFloat(distancePercent);
|
||
if (distance <= 2) return { icon: '🚨', text: 'DANGER', color: 'text-red-600' };
|
||
if (distance <= 5) return { icon: '⚠️', text: 'WARNING', color: 'text-yellow-600' };
|
||
if (distance <= 10) return { icon: '🟡', text: 'CAUTION', color: 'text-yellow-500' };
|
||
return { icon: '✅', text: 'SAFE', color: 'text-green-500' };
|
||
};
|
||
|
||
if (error) {
|
||
return (
|
||
<div className="bg-red-50 border border-red-200 rounded-lg p-4">
|
||
<div className="flex items-center">
|
||
<span className="text-red-500 mr-2">❌</span>
|
||
<span className="text-red-700">{error}</span>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div className="space-y-6">
|
||
{/* Header */}
|
||
<div className="bg-gray-800 rounded-lg p-4 border border-gray-700">
|
||
<div className="flex justify-between items-center">
|
||
<h2 className="text-lg font-semibold text-white flex items-center">
|
||
<span className="mr-2">🔍</span>
|
||
Position Monitor
|
||
</h2>
|
||
<span className="text-sm text-gray-400">
|
||
Last update: {lastUpdate.toLocaleTimeString()}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Position Status */}
|
||
{monitorData?.hasPosition && monitorData.position ? (
|
||
<div className="bg-gray-800 border border-gray-700 rounded-lg p-6">
|
||
<h3 className="text-lg font-medium text-white mb-4 flex items-center">
|
||
<span className="mr-2">📊</span>
|
||
Active Position
|
||
</h3>
|
||
|
||
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
|
||
<div className="bg-gray-900/50 p-3 rounded-lg">
|
||
<p className="text-sm text-gray-400">Symbol & Side</p>
|
||
<p className="font-medium text-white">{monitorData.position.symbol}</p>
|
||
<p className={`text-sm font-semibold ${monitorData.position.side === 'short' ? 'text-red-400' : 'text-green-400'}`}>
|
||
{monitorData.position.side.toUpperCase()}
|
||
</p>
|
||
</div>
|
||
<div className="bg-gray-900/50 p-3 rounded-lg">
|
||
<p className="text-sm text-gray-400">Size</p>
|
||
<p className="font-medium text-white">{monitorData.position.size} SOL</p>
|
||
</div>
|
||
<div className="bg-gray-900/50 p-3 rounded-lg">
|
||
<p className="text-sm text-gray-400">Entry Price</p>
|
||
<p className="font-medium text-white">${monitorData.position.entryPrice.toFixed(4)}</p>
|
||
</div>
|
||
<div className="bg-gray-900/50 p-3 rounded-lg">
|
||
<p className="text-sm text-gray-400">Current Price</p>
|
||
<p className="font-medium text-white">${monitorData.position.currentPrice.toFixed(4)}</p>
|
||
</div>
|
||
<div className="bg-gray-900/50 p-3 rounded-lg">
|
||
<p className="text-sm text-gray-400">P&L</p>
|
||
<p className={`font-medium ${monitorData.position.unrealizedPnl >= 0 ? 'text-green-400' : 'text-red-400'}`}>
|
||
{monitorData.position.unrealizedPnl >= 0 ? '+' : ''}${monitorData.position.unrealizedPnl.toFixed(2)}
|
||
</p>
|
||
</div>
|
||
<div className="bg-gray-900/50 p-3 rounded-lg">
|
||
<p className="text-sm text-gray-400">Notional Value</p>
|
||
<p className="font-medium text-white">${monitorData.position.notionalValue.toFixed(2)}</p>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Stop Loss Section */}
|
||
{monitorData.stopLossProximity && (
|
||
<div className="mt-6 p-4 bg-gray-900/30 rounded-lg border border-gray-600">
|
||
<h4 className="font-medium text-white mb-3 flex items-center">
|
||
<span className="mr-2">🤖</span>
|
||
AI Autonomous Risk Management
|
||
</h4>
|
||
|
||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||
<div className="bg-gray-800/50 p-3 rounded-lg">
|
||
<p className="text-sm text-gray-400">Stop Loss Price</p>
|
||
<p className="font-medium text-white">${monitorData.stopLossProximity.stopLossPrice.toFixed(4)}</p>
|
||
</div>
|
||
<div className="bg-gray-800/50 p-3 rounded-lg">
|
||
<p className="text-sm text-gray-400">Distance</p>
|
||
<p className="font-medium text-white">{monitorData.stopLossProximity.distancePercent}% away</p>
|
||
</div>
|
||
<div className="bg-gray-800/50 p-3 rounded-lg">
|
||
<p className="text-sm text-gray-400">AI Status</p>
|
||
{(() => {
|
||
const status = getStopLossStatus(monitorData.stopLossProximity.distancePercent);
|
||
const aiActions: Record<string, { text: string; color: string }> = {
|
||
'DANGER': { text: '🚨 Emergency Analysis', color: 'text-red-400' },
|
||
'WARNING': { text: '⚠️ Position Review', color: 'text-yellow-400' },
|
||
'CAUTION': { text: '🟡 Enhanced Watch', color: 'text-yellow-400' },
|
||
'SAFE': { text: '✅ Opportunity Scan', color: 'text-green-400' }
|
||
};
|
||
const aiAction = aiActions[status.text] || aiActions['SAFE'];
|
||
return (
|
||
<p className={`font-medium ${aiAction.color}`}>
|
||
{aiAction.text}
|
||
</p>
|
||
);
|
||
})()}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="mt-3 bg-gray-800/30 p-3 rounded-lg">
|
||
<p className="text-sm text-gray-400">AI Action Plan</p>
|
||
<p className="font-medium text-blue-400">
|
||
{monitorData.nextAction || 'AI monitoring position autonomously'}
|
||
</p>
|
||
</div>
|
||
|
||
{monitorData.stopLossProximity.isNear && (
|
||
<div className="mt-4 p-3 bg-blue-900/30 border border-blue-500/30 rounded-lg">
|
||
<p className="text-blue-300 font-medium">🤖 AI TAKING ACTION: Autonomous risk management activated!</p>
|
||
<p className="text-blue-400 text-sm mt-1">No manual intervention required - enjoy your beach time! 🏖️</p>
|
||
</div>
|
||
)}
|
||
</div>
|
||
)}
|
||
</div>
|
||
) : (
|
||
<div className="bg-gray-800 border border-gray-700 rounded-lg p-6">
|
||
<div className="text-center py-8">
|
||
<p className="text-gray-400 text-lg flex items-center justify-center">
|
||
<span className="mr-2">📊</span>
|
||
No Open Positions
|
||
</p>
|
||
<p className="text-gray-500 mt-2">Scanning for opportunities...</p>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* Automation Status */}
|
||
<div className="bg-gray-800 border border-gray-700 rounded-lg p-6">
|
||
<h3 className="text-lg font-medium text-white mb-4 flex items-center">
|
||
<span className="mr-2">🤖</span>
|
||
Automation Status
|
||
</h3>
|
||
|
||
{automationStatus?.isActive ? (
|
||
<div className="space-y-4">
|
||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||
<div className="bg-gray-900/50 p-3 rounded-lg">
|
||
<p className="text-sm text-gray-400">Status</p>
|
||
<p className="font-medium text-green-400 flex items-center">
|
||
<span className="w-2 h-2 bg-green-400 rounded-full mr-2"></span>
|
||
ACTIVE
|
||
</p>
|
||
</div>
|
||
<div className="bg-gray-900/50 p-3 rounded-lg">
|
||
<p className="text-sm text-gray-400">Mode</p>
|
||
<p className={`font-medium ${automationStatus.mode === 'LIVE' ? 'text-red-400' : 'text-blue-400'}`}>
|
||
{automationStatus.mode}
|
||
</p>
|
||
</div>
|
||
<div className="bg-gray-900/50 p-3 rounded-lg">
|
||
<p className="text-sm text-gray-400">Strategy</p>
|
||
<p className="font-medium text-white">Scalping</p>
|
||
</div>
|
||
<div className="bg-gray-900/50 p-3 rounded-lg">
|
||
<p className="text-sm text-gray-400">Symbol</p>
|
||
<p className="font-medium text-white">{automationStatus.symbol}</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||
<div className="bg-gray-900/50 p-3 rounded-lg">
|
||
<p className="text-sm text-gray-400">Timeframes</p>
|
||
<p className="font-medium text-cyan-400">{automationStatus.timeframes?.join(', ') || 'N/A'}</p>
|
||
</div>
|
||
<div className="bg-gray-900/50 p-3 rounded-lg">
|
||
<p className="text-sm text-gray-400">Cycles</p>
|
||
<p className="font-medium text-white">{automationStatus.totalCycles}</p>
|
||
</div>
|
||
<div className="bg-gray-900/50 p-3 rounded-lg">
|
||
<p className="text-sm text-gray-400">Trades</p>
|
||
<p className="font-medium text-white">{automationStatus.totalTrades}</p>
|
||
</div>
|
||
<div className="bg-gray-900/50 p-3 rounded-lg">
|
||
<p className="text-sm text-gray-400">Errors</p>
|
||
<p className={`font-medium ${automationStatus.consecutiveErrors > 0 ? 'text-yellow-400' : 'text-green-400'}`}>
|
||
{automationStatus.consecutiveErrors}/3
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
{automationStatus.lastActivity && (
|
||
<div className="bg-gray-900/30 p-3 rounded-lg">
|
||
<p className="text-sm text-gray-400">Last Activity</p>
|
||
<p className="font-medium text-white">
|
||
{new Date(automationStatus.lastActivity).toLocaleString()}
|
||
</p>
|
||
</div>
|
||
)}
|
||
</div>
|
||
) : (
|
||
<div className="text-center py-4">
|
||
<p className="text-red-400 font-medium flex items-center justify-center">
|
||
<span className="w-2 h-2 bg-red-400 rounded-full mr-2"></span>
|
||
STOPPED
|
||
</p>
|
||
<p className="text-gray-500 mt-2">{automationStatus?.detailedStatus}</p>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|