#!/usr/bin/env node /** * Enhanced 24/7 Automation with Global Market Sentiment * Integrates Fear & Greed Index and macro indicators for better trading decisions */ // Import M2 Money Supply indicator const M2MoneySupplyIndicator = require('./m2-money-supply-indicator'); class EnhancedGlobalAutomation { constructor() { this.config = { symbol: 'SOLUSD', timeframe: '60', intervalMinutes: 60, autoExecuteThreshold: 60, // API endpoint for container environment apiHost: '192.168.0.1:9001', // Enhanced with sentiment-based adjustments sentimentThresholds: { extremeFear: 75, // Lower threshold during extreme fear (more aggressive) fear: 65, // Moderate lowering during fear neutral: 60, // Base threshold greed: 70, // Higher threshold during greed (more selective) extremeGreed: 80 // Much higher threshold during extreme greed } }; this.cycleCount = 0; this.m2Indicator = new M2MoneySupplyIndicator(); this.marketSentiment = { fearGreedIndex: null, bitcoinDominance: null, m2Analysis: null, marketRegime: 'UNKNOWN', riskLevel: 'MODERATE', lastUpdate: null }; this.stats = { startTime: new Date(), totalCycles: 0, totalTrades: 0, sentimentAdjustments: 0, regimeChanges: 0 }; } async log(message) { const timestamp = new Date().toISOString(); const logEntry = `[${timestamp}] ${message}`; console.log(logEntry); } async updateMarketSentiment() { try { await this.log('πŸ“Š Updating global market sentiment...'); // Try to get Fear & Greed Index const fearGreed = await this.getFearGreedIndex(); // Get Bitcoin Dominance (mock for now - in production use real API) const btcDominance = await this.getBitcoinDominance(); // Calculate overall market regime const regime = this.calculateMarketRegime(fearGreed, btcDominance); // Update sentiment state this.marketSentiment = { fearGreedIndex: fearGreed, bitcoinDominance: btcDominance, marketRegime: regime.regime, riskLevel: regime.riskLevel, lastUpdate: new Date(), tradingImplication: regime.tradingImplication }; await this.log(`πŸ“ˆ Market Regime: ${regime.regime} | Risk: ${regime.riskLevel} | F&G: ${fearGreed || 'N/A'}`); return this.marketSentiment; } catch (error) { await this.log(`❌ Sentiment update error: ${error.message}`); return this.marketSentiment; } } async getFearGreedIndex() { try { // Try multiple sources for Fear & Greed data const sources = [ 'https://api.alternative.me/fng/', // Could add backup sources here ]; for (const source of sources) { try { const { stdout } = await execAsync(`timeout 10 curl -s "${source}"`); const data = JSON.parse(stdout); if (data.data && data.data[0]) { return { value: parseInt(data.data[0].value), classification: data.data[0].value_classification, timestamp: data.data[0].timestamp }; } } catch (error) { continue; // Try next source } } // Fallback: estimate from recent price action return await this.estimateFearGreedFromPriceAction(); } catch (error) { await this.log(`⚠️ Fear & Greed unavailable, using price-based estimate`); return await this.estimateFearGreedFromPriceAction(); } } async estimateFearGreedFromPriceAction() { try { // Get recent analysis to estimate sentiment const response = await fetch(`http://${this.config.apiHost}/api/ai-analysis/latest?symbol=${this.config.symbol}&timeframe=${this.config.timeframe}`); const data = await response.json(); if (data.success && data.data && data.data.analysis) { const analysis = data.data.analysis; // Estimate Fear & Greed from technical indicators let fearGreedEstimate = 50; // Neutral baseline // Confidence level indicates sentiment strength if (analysis.recommendation === 'BUY' && analysis.confidence > 70) { fearGreedEstimate = 65; // Moderate greed } else if (analysis.recommendation === 'SELL' && analysis.confidence > 70) { fearGreedEstimate = 35; // Moderate fear } else if (analysis.confidence < 50) { fearGreedEstimate = 45; // Slight fear (uncertainty) } return { value: fearGreedEstimate, classification: this.classifyFearGreed(fearGreedEstimate), timestamp: Date.now(), source: 'price_action_estimate' }; } return { value: 50, classification: 'Neutral', timestamp: Date.now(), source: 'fallback' }; } catch (error) { return { value: 50, classification: 'Neutral', timestamp: Date.now(), source: 'error_fallback' }; } } classifyFearGreed(value) { if (value <= 25) return 'Extreme Fear'; if (value <= 45) return 'Fear'; if (value <= 55) return 'Neutral'; if (value <= 75) return 'Greed'; return 'Extreme Greed'; } async getBitcoinDominance() { // Mock implementation - in production, use real API like CoinGecko // Estimate based on recent market conditions return { value: 52.5, trend: 'stable', interpretation: 'BTC holding ground vs altcoins' }; } calculateMarketRegime(fearGreed, btcDominance) { let regime = 'NEUTRAL'; let riskLevel = 'MODERATE'; let tradingImplication = {}; if (fearGreed) { const fgValue = fearGreed.value; if (fgValue <= 25) { regime = 'EXTREME_FEAR'; riskLevel = 'LOW'; // Low risk to buy during extreme fear tradingImplication = { action: 'AGGRESSIVE_BUY', adjustedThreshold: this.config.sentimentThresholds.extremeFear, reasoning: 'Extreme fear - contrarian opportunity' }; } else if (fgValue <= 45) { regime = 'FEAR'; riskLevel = 'LOW_MODERATE'; tradingImplication = { action: 'CAUTIOUS_BUY', adjustedThreshold: this.config.sentimentThresholds.fear, reasoning: 'Fear present - good buying opportunity' }; } else if (fgValue <= 55) { regime = 'NEUTRAL'; riskLevel = 'MODERATE'; tradingImplication = { action: 'NORMAL', adjustedThreshold: this.config.sentimentThresholds.neutral, reasoning: 'Balanced market - rely on technical analysis' }; } else if (fgValue <= 75) { regime = 'GREED'; riskLevel = 'MODERATE_HIGH'; tradingImplication = { action: 'CAUTIOUS_SELL', adjustedThreshold: this.config.sentimentThresholds.greed, reasoning: 'Greed emerging - be more selective' }; } else { regime = 'EXTREME_GREED'; riskLevel = 'HIGH'; tradingImplication = { action: 'DEFENSIVE', adjustedThreshold: this.config.sentimentThresholds.extremeGreed, reasoning: 'Extreme greed - potential market top' }; } } return { regime, riskLevel, tradingImplication }; } async start() { await this.log('πŸš€ Enhanced 24/7 Automation with Global Sentiment Started'); await this.log(`πŸ“Š Base config: ${this.config.symbol} every ${this.config.intervalMinutes}m`); // Update sentiment immediately await this.updateMarketSentiment(); // Run first analysis cycle await this.runEnhancedCycle(); // Schedule recurring cycles setInterval(() => this.runEnhancedCycle().catch(console.error), this.config.intervalMinutes * 60 * 1000); // Update sentiment every 30 minutes (more frequent than trading) setInterval(() => this.updateMarketSentiment().catch(console.error), 30 * 60 * 1000); await this.log(`⏰ Next cycle: ${new Date(Date.now() + this.config.intervalMinutes * 60 * 1000).toLocaleTimeString()}`); } async runEnhancedCycle() { this.stats.totalCycles++; await this.log(`πŸ”„ Enhanced analysis cycle #${this.stats.totalCycles}`); try { // Update sentiment first await this.updateMarketSentiment(); // Get current technical analysis const response = await fetch(`http://${this.config.apiHost}/api/ai-analysis/latest?symbol=${this.config.symbol}&timeframe=${this.config.timeframe}`); const data = await response.json(); if (data.success && data.data && data.data.analysis) { const analysis = data.data.analysis; // Apply sentiment-based threshold adjustment const adjustedThreshold = this.getAdjustedThreshold(); await this.log(`πŸ“Š Technical: ${analysis.recommendation} (${analysis.confidence}%)`); await this.log(`🎯 Threshold: ${adjustedThreshold}% (adjusted for ${this.marketSentiment.marketRegime})`); if (analysis.confidence >= adjustedThreshold) { await this.log(`🎯 EXECUTING: ${analysis.confidence}% β‰₯ ${adjustedThreshold}% (${this.marketSentiment.tradingImplication?.reasoning})`); await this.executeEnhancedTrade(analysis); } else { await this.log(`⏸️ NO TRADE: ${analysis.confidence}% < ${adjustedThreshold}% (sentiment-adjusted threshold)`); // Log why sentiment affected the decision if (adjustedThreshold !== this.config.autoExecuteThreshold) { this.stats.sentimentAdjustments++; await this.log(`πŸ“ˆ Sentiment Impact: ${this.marketSentiment.marketRegime} adjusted threshold by ${adjustedThreshold - this.config.autoExecuteThreshold}%`); } } } else { await this.log('❌ No technical analysis available'); } } catch (error) { await this.log(`❌ Enhanced cycle error: ${error.message}`); } } getAdjustedThreshold() { const baseThreshold = this.config.autoExecuteThreshold; if (!this.marketSentiment.tradingImplication) { return baseThreshold; } return this.marketSentiment.tradingImplication.adjustedThreshold || baseThreshold; } async executeEnhancedTrade(analysis) { try { // Enhance trade data with sentiment context const tradeData = { symbol: this.config.symbol, side: analysis.recommendation, amount: this.calculateSentimentAdjustedAmount(), entry: analysis.entry, stopLoss: analysis.stopLoss, takeProfit: analysis.takeProfit, confidence: analysis.confidence, reasoning: analysis.reasoning, source: 'enhanced_24x7_sentiment', // Enhanced fields marketRegime: this.marketSentiment.marketRegime, fearGreedValue: this.marketSentiment.fearGreedIndex?.value, riskLevel: this.marketSentiment.riskLevel, sentimentAdjustment: this.marketSentiment.tradingImplication?.reasoning }; // Create enhanced paper trade const response = await fetch(`http://${this.config.apiHost}/api/safe-paper-trading/create-trade`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(tradeData) }); const result = await response.json(); if (result.success) { this.stats.totalTrades++; await this.log(`βœ… ENHANCED TRADE: ${result.trade.id} | Regime: ${this.marketSentiment.marketRegime}`); } else { await this.log(`❌ TRADE FAILED: ${result.message}`); } } catch (error) { await this.log(`❌ Enhanced trade execution error: ${error.message}`); } } calculateSentimentAdjustedAmount() { let baseAmount = 100; // Adjust position size based on market sentiment switch (this.marketSentiment.marketRegime) { case 'EXTREME_FEAR': return baseAmount * 1.5; // 50% larger positions during extreme fear case 'FEAR': return baseAmount * 1.2; // 20% larger during fear case 'NEUTRAL': return baseAmount; // Normal size case 'GREED': return baseAmount * 0.8; // 20% smaller during greed case 'EXTREME_GREED': return baseAmount * 0.5; // 50% smaller during extreme greed default: return baseAmount; } } getStatus() { const uptime = Math.floor((Date.now() - this.stats.startTime.getTime()) / 1000); return { isRunning: true, config: this.config, marketSentiment: this.marketSentiment, stats: { ...this.stats, uptime: `${Math.floor(uptime / 3600)}h ${Math.floor((uptime % 3600) / 60)}m`, sentimentAdjustmentRate: `${this.stats.sentimentAdjustments}/${this.stats.totalCycles}`, nextCycle: new Date(Date.now() + (this.config.intervalMinutes * 60 * 1000)) }, enhancement: { sentimentIntegration: 'ACTIVE', fearGreedTracking: this.marketSentiment.fearGreedIndex ? 'ACTIVE' : 'ESTIMATED', riskAdjustment: 'DYNAMIC', positionSizing: 'SENTIMENT_BASED' } }; } } // Create and start enhanced automation const enhancedAutomation = new EnhancedGlobalAutomation(); enhancedAutomation.start();