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! 🏖️🤖💰
259 lines
9.5 KiB
JavaScript
259 lines
9.5 KiB
JavaScript
import React, { useState, useEffect } from 'react';
|
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { AlertCircle, Eye, TrendingUp, TrendingDown, Activity, Clock } from 'lucide-react';
|
|
|
|
const PositionMonitoringDashboard = () => {
|
|
const [positionData, setPositionData] = useState(null);
|
|
const [automationStatus, setAutomationStatus] = useState(null);
|
|
const [loading, setLoading] = useState(true);
|
|
const [lastUpdate, setLastUpdate] = useState(null);
|
|
|
|
const fetchPositionData = async () => {
|
|
try {
|
|
const response = await fetch('/api/automation/position-monitor');
|
|
const data = await response.json();
|
|
if (data.success) {
|
|
setPositionData(data.monitor);
|
|
setLastUpdate(new Date().toLocaleTimeString());
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to fetch position data:', error);
|
|
}
|
|
};
|
|
|
|
const fetchAutomationStatus = async () => {
|
|
try {
|
|
const response = await fetch('/api/automation/status');
|
|
const data = await response.json();
|
|
setAutomationStatus(data);
|
|
setLoading(false);
|
|
} catch (error) {
|
|
console.error('Failed to fetch automation status:', error);
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
fetchPositionData();
|
|
fetchAutomationStatus();
|
|
|
|
// Update every 10 seconds
|
|
const interval = setInterval(() => {
|
|
fetchPositionData();
|
|
fetchAutomationStatus();
|
|
}, 10000);
|
|
|
|
return () => clearInterval(interval);
|
|
}, []);
|
|
|
|
const getRiskColor = (riskLevel) => {
|
|
switch (riskLevel) {
|
|
case 'CRITICAL': return 'bg-red-500 text-white';
|
|
case 'HIGH': return 'bg-orange-500 text-white';
|
|
case 'MEDIUM': return 'bg-yellow-500 text-black';
|
|
case 'LOW': return 'bg-green-500 text-white';
|
|
default: return 'bg-gray-500 text-white';
|
|
}
|
|
};
|
|
|
|
const getAutomationModeColor = (mode) => {
|
|
if (!automationStatus?.isActive) return 'bg-gray-500 text-white';
|
|
if (automationStatus?.positionMonitoringActive) return 'bg-blue-500 text-white';
|
|
return 'bg-green-500 text-white';
|
|
};
|
|
|
|
if (loading) {
|
|
return (
|
|
<Card className="w-full">
|
|
<CardContent className="p-6">
|
|
<div className="flex items-center justify-center">
|
|
<Activity className="h-6 w-6 animate-spin mr-2" />
|
|
Loading monitoring data...
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
{/* Automation Status Header */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center justify-between">
|
|
<span className="flex items-center">
|
|
<Activity className="h-5 w-5 mr-2" />
|
|
Position-Aware Automation
|
|
</span>
|
|
<div className="flex items-center space-x-2">
|
|
<Badge className={getAutomationModeColor()}>
|
|
{automationStatus?.isActive ? (
|
|
automationStatus?.positionMonitoringActive ? 'MONITORING POSITION' : 'SCANNING OPPORTUNITIES'
|
|
) : 'STOPPED'}
|
|
</Badge>
|
|
{lastUpdate && (
|
|
<span className="text-sm text-gray-500 flex items-center">
|
|
<Clock className="h-4 w-4 mr-1" />
|
|
{lastUpdate}
|
|
</span>
|
|
)}
|
|
</div>
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
<div>
|
|
<p className="text-sm text-gray-600">Status</p>
|
|
<p className="font-semibold">{automationStatus?.detailedStatus || 'Unknown'}</p>
|
|
</div>
|
|
<div>
|
|
<p className="text-sm text-gray-600">Next Action</p>
|
|
<p className="font-semibold">{automationStatus?.nextAction || 'None'}</p>
|
|
</div>
|
|
<div>
|
|
<p className="text-sm text-gray-600">Total Cycles</p>
|
|
<p className="font-semibold">{automationStatus?.totalCycles || 0}</p>
|
|
</div>
|
|
<div>
|
|
<p className="text-sm text-gray-600">Errors</p>
|
|
<p className="font-semibold">{automationStatus?.consecutiveErrors || 0}</p>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Position Status */}
|
|
{positionData?.hasPosition ? (
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center justify-between">
|
|
<span className="flex items-center">
|
|
{positionData.position.side === 'LONG' ?
|
|
<TrendingUp className="h-5 w-5 mr-2 text-green-500" /> :
|
|
<TrendingDown className="h-5 w-5 mr-2 text-red-500" />
|
|
}
|
|
Active Position: {positionData.position.symbol}
|
|
</span>
|
|
<Badge className={getRiskColor(positionData.riskLevel)}>
|
|
{positionData.riskLevel} RISK
|
|
</Badge>
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-4">
|
|
<div>
|
|
<p className="text-sm text-gray-600">Side</p>
|
|
<p className="font-semibold">{positionData.position.side}</p>
|
|
</div>
|
|
<div>
|
|
<p className="text-sm text-gray-600">Size</p>
|
|
<p className="font-semibold">{positionData.position.size}</p>
|
|
</div>
|
|
<div>
|
|
<p className="text-sm text-gray-600">Entry Price</p>
|
|
<p className="font-semibold">${positionData.position.entryPrice}</p>
|
|
</div>
|
|
<div>
|
|
<p className="text-sm text-gray-600">Unrealized PnL</p>
|
|
<p className={`font-semibold ${positionData.position.unrealizedPnl >= 0 ? 'text-green-600' : 'text-red-600'}`}>
|
|
${positionData.position.unrealizedPnl}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Stop Loss Proximity Alert */}
|
|
{positionData.stopLossProximity && (
|
|
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4">
|
|
<div className="flex items-center mb-2">
|
|
<AlertCircle className="h-5 w-5 text-yellow-600 mr-2" />
|
|
<h4 className="font-semibold text-yellow-800">Stop Loss Proximity Alert</h4>
|
|
</div>
|
|
<div className="grid grid-cols-3 gap-4 text-sm">
|
|
<div>
|
|
<p className="text-yellow-600">Distance to SL</p>
|
|
<p className="font-bold">{positionData.stopLossProximity.distancePercent}%</p>
|
|
</div>
|
|
<div>
|
|
<p className="text-yellow-600">Stop Loss Price</p>
|
|
<p className="font-bold">${positionData.stopLossProximity.stopLossPrice}</p>
|
|
</div>
|
|
<div>
|
|
<p className="text-yellow-600">Current Price</p>
|
|
<p className="font-bold">${positionData.stopLossProximity.currentPrice}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Next Action */}
|
|
<div className="mt-4 p-4 bg-blue-50 border border-blue-200 rounded-lg">
|
|
<h4 className="font-semibold text-blue-800 mb-2">What Will Happen Next?</h4>
|
|
<p className="text-blue-700">{positionData.nextAction}</p>
|
|
<p className="text-blue-600 text-sm mt-1">{positionData.recommendation}</p>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
) : (
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center">
|
|
<Eye className="h-5 w-5 mr-2" />
|
|
No Active Positions
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-center py-8">
|
|
<p className="text-gray-600 mb-4">Currently scanning for trading opportunities</p>
|
|
<div className="grid grid-cols-2 gap-4 text-sm">
|
|
<div>
|
|
<p className="text-gray-500">Mode</p>
|
|
<p className="font-semibold">Opportunity Scanning</p>
|
|
</div>
|
|
<div>
|
|
<p className="text-gray-500">Next Check</p>
|
|
<p className="font-semibold">Every 10 minutes</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
)}
|
|
|
|
{/* Automation Controls */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Controls</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex space-x-4">
|
|
<Button
|
|
onClick={() => window.location.reload()}
|
|
variant="outline"
|
|
>
|
|
Refresh Data
|
|
</Button>
|
|
<Button
|
|
onClick={() => {
|
|
if (automationStatus?.isActive) {
|
|
fetch('/api/automation/stop', { method: 'POST' })
|
|
.then(() => window.location.reload());
|
|
} else {
|
|
// Open start automation modal/form
|
|
console.log('Start automation');
|
|
}
|
|
}}
|
|
variant={automationStatus?.isActive ? "destructive" : "default"}
|
|
>
|
|
{automationStatus?.isActive ? 'Stop Automation' : 'Start Automation'}
|
|
</Button>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default PositionMonitoringDashboard;
|