🔧 CRITICAL FIX: Price Data Sync & Position Monitor Enhancement

Fixed major price data sync issues:
- Removed hardcoded price (77.63) from position monitor
- Added real-time oracle data instead of stale TWAP pricing
- Implemented cache-busting headers for fresh data
- Updated fallback prices to current market levels

- Real-time P&L tracking with trend indicators (📈📉➡️)
- Enhanced stop loss proximity alerts with color-coded risk levels
- Analysis progress indicators during automation cycles
- Performance metrics (runtime, cycles, trades, errors)
- Fresh data validation and improved error handling

- Price accuracy: 77.63 → 84.47 (matches Drift UI)
- P&L accuracy: -.91 → -.59 (correct calculation)
- Risk assessment: CRITICAL → MEDIUM (proper evaluation)
- Stop loss distance: 0.91% → 4.8% (safe distance)

- CLI monitor script with 8-second updates
- Web dashboard component (PositionMonitor.tsx)
- Real-time automation status tracking
- Database and error monitoring improvements

This fixes the automation showing false emergency alerts when
position was actually performing normally.
This commit is contained in:
mindesbunister
2025-07-25 23:33:06 +02:00
parent 08f9a9b541
commit 9b6a393e06
18 changed files with 6783 additions and 361 deletions

View File

@@ -23,9 +23,192 @@ class EnhancedAutonomousRiskManager {
this.pendingDecisions = new Map(); // Track decisions awaiting outcomes
this.activeSetups = new Map(); // Track R/R setups for outcome learning
this.lastAnalysis = null;
this.baseApiUrl = this.detectApiUrl(); // Docker-aware API URL
this.lastScreenshotAnalysis = null; // Track when we last analyzed screenshots
this.screenshotAnalysisThreshold = 3.5; // Only analyze screenshots when < 3.5% from SL (demo: was 3.0)
this.screenshotAnalysisInterval = 2 * 60 * 1000; // Don't analyze more than once every 2 minutes (demo: was 5)
}
async log(message) {
/**
* Detect the correct API URL based on environment
* Returns localhost for host environment, gateway IP for Docker
*/
detectApiUrl() {
try {
// Check if running inside Docker container
const fs = require('fs');
if (fs.existsSync('/.dockerenv')) {
// Get the default gateway IP from /proc/net/route
try {
const routeData = fs.readFileSync('/proc/net/route', 'utf8');
const lines = routeData.split('\n');
for (const line of lines) {
const parts = line.trim().split(/\s+/);
// Look for default route (destination 00000000)
if (parts[1] === '00000000' && parts[2] && parts[2] !== '00000000') {
// Convert hex gateway to IP
const gatewayHex = parts[2];
const ip = [
parseInt(gatewayHex.substr(6, 2), 16),
parseInt(gatewayHex.substr(4, 2), 16),
parseInt(gatewayHex.substr(2, 2), 16),
parseInt(gatewayHex.substr(0, 2), 16)
].join('.');
return `http://${ip}:9001`;
}
}
// Fallback to known gateway IP
return 'http://192.168.160.1:9001';
} catch (routeError) {
// Fallback to the known gateway IP for this Docker setup
return 'http://192.168.160.1:9001';
}
}
// Check hostname (Docker containers often have specific hostnames)
const os = require('os');
const hostname = os.hostname();
if (hostname && hostname.length === 12 && /^[a-f0-9]+$/.test(hostname)) {
// Same gateway detection for hostname-based detection
try {
const routeData = fs.readFileSync('/proc/net/route', 'utf8');
const lines = routeData.split('\n');
for (const line of lines) {
const parts = line.trim().split(/\s+/);
if (parts[1] === '00000000' && parts[2] && parts[2] !== '00000000') {
const gatewayHex = parts[2];
const ip = [
parseInt(gatewayHex.substr(6, 2), 16),
parseInt(gatewayHex.substr(4, 2), 16),
parseInt(gatewayHex.substr(2, 2), 16),
parseInt(gatewayHex.substr(0, 2), 16)
].join('.');
return `http://${ip}:9001`;
}
}
return 'http://192.168.160.1:9001';
} catch (routeError) {
return 'http://192.168.160.1:9001';
}
}
// Default to localhost for host environment
return 'http://localhost:9001';
} catch (error) {
// Fallback to localhost if detection fails
return 'http://localhost:9001';
}
}
/**
* Determine if we should trigger screenshot analysis based on risk level
*/
shouldTriggerScreenshotAnalysis(distancePercent) {
// Only trigger when approaching critical levels
if (distancePercent > this.screenshotAnalysisThreshold) {
return false;
}
// Don't analyze too frequently
if (this.lastScreenshotAnalysis) {
const timeSinceLastAnalysis = Date.now() - this.lastScreenshotAnalysis.getTime();
if (timeSinceLastAnalysis < this.screenshotAnalysisInterval) {
return false;
}
}
return true;
}
/**
* Request screenshot analysis from the main trading system
*/
async requestScreenshotAnalysis(symbol) {
try {
this.lastScreenshotAnalysis = new Date();
await this.log(`📸 Requesting chart analysis for ${symbol} - risk level requires visual confirmation`);
// Use the enhanced screenshot API with analysis
const response = await HttpUtil.post(`${this.baseApiUrl}/api/enhanced-screenshot`, {
symbol: symbol,
timeframes: ['1h'], // Focus on primary timeframe for speed
layouts: ['ai'], // Only AI layout for faster analysis
analyze: true,
reason: 'RISK_MANAGEMENT_ANALYSIS'
});
if (response.success && response.analysis) {
await this.log(`✅ Chart analysis complete: ${response.analysis.recommendation} (${response.analysis.confidence}% confidence)`);
return {
recommendation: response.analysis.recommendation,
confidence: response.analysis.confidence,
marketSentiment: response.analysis.marketSentiment,
keyLevels: response.analysis.keyLevels,
reasoning: response.analysis.reasoning,
supportNearby: this.detectNearbySupport(response.analysis, symbol),
resistanceNearby: this.detectNearbyResistance(response.analysis, symbol),
technicalStrength: this.assessTechnicalStrength(response.analysis),
timestamp: new Date()
};
}
return null;
} catch (error) {
await this.log(`❌ Error in screenshot analysis: ${error.message}`);
return null;
}
}
/**
* Detect if there's strong support near current price
*/
detectNearbySupport(analysis, symbol) {
if (!analysis.keyLevels?.support) return false;
// Get current price from last position data
const currentPrice = this.lastAnalysis?.monitor?.position?.currentPrice || 0;
if (!currentPrice) return false;
// Check if any support level is within 2% of current price
return analysis.keyLevels.support.some(supportLevel => {
const distance = Math.abs(currentPrice - supportLevel) / currentPrice;
return distance < 0.02; // Within 2%
});
}
/**
* Detect if there's resistance near current price
*/
detectNearbyResistance(analysis, symbol) {
if (!analysis.keyLevels?.resistance) return false;
const currentPrice = this.lastAnalysis?.monitor?.position?.currentPrice || 0;
if (!currentPrice) return false;
return analysis.keyLevels.resistance.some(resistanceLevel => {
const distance = Math.abs(currentPrice - resistanceLevel) / currentPrice;
return distance < 0.02; // Within 2%
});
}
/**
* Assess overall technical strength from chart analysis
*/
assessTechnicalStrength(analysis) {
let strength = 'NEUTRAL';
if (analysis.confidence > 80 && analysis.marketSentiment === 'BULLISH') {
strength = 'STRONG_BULLISH';
} else if (analysis.confidence > 80 && analysis.marketSentiment === 'BEARISH') {
strength = 'STRONG_BEARISH';
} else if (analysis.confidence > 60) {
strength = `MODERATE_${analysis.marketSentiment}`;
}
return strength;
} async log(message) {
const timestamp = new Date().toISOString();
console.log(`[${timestamp}] 🤖 Enhanced Risk AI: ${message}`);
}
@@ -49,6 +232,14 @@ class EnhancedAutonomousRiskManager {
// Update thresholds based on learning
await this.updateThresholdsFromLearning();
// SMART SCREENSHOT ANALYSIS TRIGGER
// Only analyze screenshots when approaching critical levels
let chartAnalysis = null;
if (this.shouldTriggerScreenshotAnalysis(distance)) {
await this.log(`📸 Triggering screenshot analysis - distance: ${distance}%`);
chartAnalysis = await this.requestScreenshotAnalysis(position.symbol);
}
// Get AI recommendation based on learned patterns
const smartRecommendation = await this.learner.getSmartRecommendation({
distanceFromSL: distance,
@@ -57,7 +248,8 @@ class EnhancedAutonomousRiskManager {
price: position.entryPrice, // Current price context
unrealizedPnl: position.unrealizedPnl,
side: position.side
}
},
chartAnalysis: chartAnalysis // Include visual analysis if available
});
let decision;
@@ -129,6 +321,49 @@ class EnhancedAutonomousRiskManager {
await this.log(`⚠️ HIGH RISK: Position ${distance}% from stop loss`);
// Check if we have recent chart analysis data
const chartAnalysis = smartRecommendation.chartAnalysis;
// Use chart analysis to make smarter decisions
if (chartAnalysis) {
await this.log(`📊 Using chart analysis: ${chartAnalysis.technicalStrength} sentiment, ${chartAnalysis.confidence}% confidence`);
// If there's strong support nearby and bullish sentiment, consider holding
if (chartAnalysis.supportNearby &&
chartAnalysis.technicalStrength.includes('BULLISH') &&
chartAnalysis.confidence > 70 &&
position.side === 'long') {
await this.log(`🛡️ Strong support detected near ${position.currentPrice} - holding position with tighter stop`);
return {
action: 'TIGHTEN_STOP_LOSS',
reasoning: `Chart shows strong support nearby (${chartAnalysis.reasoning}). Tightening stop instead of exiting.`,
confidence: chartAnalysis.confidence / 100,
urgency: 'HIGH',
chartEnhanced: true,
parameters: {
newStopLossDistance: distance * 0.8 // Tighten by 20%
}
};
}
// If chart shows weakness, exit more aggressively
if (chartAnalysis.technicalStrength.includes('BEARISH') && chartAnalysis.confidence > 60) {
await this.log(`📉 Chart shows weakness - executing defensive exit`);
return {
action: 'PARTIAL_EXIT',
reasoning: `Chart analysis shows bearish signals (${chartAnalysis.reasoning}). Reducing exposure.`,
confidence: chartAnalysis.confidence / 100,
urgency: 'HIGH',
chartEnhanced: true,
parameters: {
exitPercentage: 70, // More aggressive exit
keepStopLoss: true
}
};
}
}
// Check learning recommendation
if (smartRecommendation.learningBased && smartRecommendation.confidence > 0.7) {
return {
@@ -478,7 +713,7 @@ class EnhancedAutonomousRiskManager {
async checkPositionStatus(symbol) {
// Check if position is still active
try {
const data = await HttpUtil.get('http://localhost:9001/api/automation/position-monitor');
const data = await HttpUtil.get(`${this.baseApiUrl}/api/automation/position-monitor`);
if (data.success && data.monitor?.hasPosition && data.monitor.position?.symbol === symbol) {
return data.monitor;
@@ -547,7 +782,7 @@ class EnhancedAutonomousRiskManager {
async getCurrentPositionStatus(symbol) {
try {
const data = await HttpUtil.get('http://localhost:9001/api/automation/position-monitor');
const data = await HttpUtil.get(`${this.baseApiUrl}/api/automation/position-monitor`);
if (data.success && data.monitor?.hasPosition) {
return {
@@ -604,7 +839,7 @@ class EnhancedAutonomousRiskManager {
async analyzeMarketConditions(symbol) {
// Enhanced market analysis for better decision making
try {
const data = await HttpUtil.get('http://localhost:9001/api/automation/position-monitor');
const data = await HttpUtil.get(`${this.baseApiUrl}/api/automation/position-monitor`);
if (data.success && data.monitor?.position) {
const pnl = data.monitor.position.unrealizedPnl;
@@ -651,7 +886,7 @@ class EnhancedAutonomousRiskManager {
try {
// Check current positions
const data = await HttpUtil.get('http://localhost:9001/api/automation/position-monitor');
const data = await HttpUtil.get(`${this.baseApiUrl}/api/automation/position-monitor`);
if (data.success) {
const decision = await this.analyzePosition(data.monitor);