/** * 🌍 Global Market Sentiment Dashboard API * Provides comprehensive sentiment data for frontend display */ import { NextRequest, NextResponse } from 'next/server'; import https from 'https'; // Utility function for external API calls function makeRequest(url, options = {}) { return new Promise((resolve, reject) => { const req = https.request(url, options, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => { try { resolve(res.statusCode === 200 ? JSON.parse(data) : null); } catch (e) { resolve(null); } }); }); req.on('error', reject); req.end(); }); } async function getFearGreedIndex() { try { const response = await makeRequest('https://api.alternative.me/fng/'); if (response?.data?.[0]) { const data = response.data[0]; return { value: parseInt(data.value), classification: data.value_classification, timestamp: data.timestamp, source: 'alternative.me' }; } } catch (error) { console.log('Fear & Greed API unavailable, using estimation'); } // Fallback estimation const now = Date.now(); const baseValue = 50 + Math.sin(now / (1000 * 60 * 60 * 24)) * 25; return { value: Math.round(Math.max(0, Math.min(100, baseValue))), classification: 'estimated', timestamp: Math.floor(now / 1000), source: 'estimated' }; } async function getAssetPrice(coinId) { try { const url = `https://api.coingecko.com/api/v3/simple/price?ids=${coinId}&vs_currencies=usd&include_24hr_change=true`; const response = await makeRequest(url); return response?.[coinId]; } catch (error) { console.log(`Price fetch failed for ${coinId}`); return null; } } async function getBitcoinDominance() { try { const url = 'https://api.coingecko.com/api/v3/global'; const response = await makeRequest(url); return response?.data?.market_cap_percentage?.btc || 50; } catch (error) { return 50; // Default assumption } } function calculateVolatilityIndex(prices) { if (!prices || prices.length < 2) return 50; // Calculate simple volatility based on price changes const changes = []; for (let i = 1; i < prices.length; i++) { changes.push(Math.abs((prices[i] - prices[i-1]) / prices[i-1])); } const avgChange = changes.reduce((a, b) => a + b, 0) / changes.length; return Math.min(100, avgChange * 1000); // Scale to 0-100 } function getMarketRegime(fearGreed, btcDom, volatility) { if (fearGreed <= 25) return 'EXTREME_FEAR'; if (fearGreed <= 45) return 'FEAR'; if (fearGreed >= 75) return 'EXTREME_GREED'; if (fearGreed >= 55) return 'GREED'; return 'NEUTRAL'; } function getRiskLevel(regime, volatility) { switch (regime) { case 'EXTREME_FEAR': return volatility > 60 ? 'HIGH_OPPORTUNITY' : 'MODERATE_OPPORTUNITY'; case 'FEAR': return 'MODERATE_OPPORTUNITY'; case 'EXTREME_GREED': return volatility > 60 ? 'EXTREME_RISK' : 'HIGH_RISK'; case 'GREED': return 'MODERATE_RISK'; default: return volatility > 60 ? 'ELEVATED' : 'BALANCED'; } } function getTradingThresholds(regime) { const thresholds = { EXTREME_FEAR: { buy: 55, sell: 75, maxPosition: 1.5 }, FEAR: { buy: 60, sell: 70, maxPosition: 1.2 }, NEUTRAL: { buy: 65, sell: 65, maxPosition: 1.0 }, GREED: { buy: 70, sell: 60, maxPosition: 0.8 }, EXTREME_GREED: { buy: 80, sell: 55, maxPosition: 0.5 } }; return thresholds[regime] || thresholds.NEUTRAL; } export async function GET() { try { console.log('🌍 Fetching global market sentiment data...'); // Fetch all sentiment data in parallel const [fearGreed, btcPrice, ethPrice, solPrice, btcDominance] = await Promise.all([ getFearGreedIndex(), getAssetPrice('bitcoin'), getAssetPrice('ethereum'), getAssetPrice('solana'), getBitcoinDominance() ]); // Calculate derived metrics const priceChanges = [ btcPrice?.usd_24h_change || 0, ethPrice?.usd_24h_change || 0, solPrice?.usd_24h_change || 0 ]; const volatilityIndex = calculateVolatilityIndex(priceChanges); const marketRegime = getMarketRegime(fearGreed.value, btcDominance, volatilityIndex); const riskLevel = getRiskLevel(marketRegime, volatilityIndex); const thresholds = getTradingThresholds(marketRegime); // Calculate correlations (simplified) const avgChange = priceChanges.reduce((a, b) => a + b, 0) / priceChanges.length; const correlationLevel = Math.abs(avgChange) > 5 ? 'HIGH' : 'NORMAL'; const sentimentData = { timestamp: new Date().toISOString(), // Core sentiment indicators fearAndGreed: { value: fearGreed.value, classification: fearGreed.classification, interpretation: getInterpretation(fearGreed.value), source: fearGreed.source }, // Crypto-specific metrics bitcoinDominance: { value: btcDominance, interpretation: btcDominance > 60 ? 'BTC_STRENGTH' : btcDominance < 40 ? 'ALT_STRENGTH' : 'BALANCED' }, // Volatility measures volatility: { index: volatilityIndex, level: volatilityIndex > 60 ? 'HIGH' : volatilityIndex < 30 ? 'LOW' : 'MODERATE' }, // Market classification marketRegime: { current: marketRegime, riskLevel: riskLevel, correlationLevel: correlationLevel }, // Trading parameters tradingThresholds: thresholds, // Asset prices assetPrices: { bitcoin: btcPrice, ethereum: ethPrice, solana: solPrice }, // Market summary summary: { sentiment: `${marketRegime.replace('_', ' ')} market with ${riskLevel.replace('_', ' ')} risk level`, recommendation: getMarketRecommendation(marketRegime, volatilityIndex), keyFactors: getKeyFactors(fearGreed.value, btcDominance, volatilityIndex) } }; console.log(`📊 Sentiment: ${marketRegime} | F&G: ${fearGreed.value} | BTC Dom: ${btcDominance.toFixed(1)}%`); return NextResponse.json({ success: true, data: sentimentData }); } catch (error) { console.error('❌ Global sentiment fetch error:', error); return NextResponse.json({ success: false, error: error.message, data: getDefaultSentimentData() }); } } function getInterpretation(fearGreedValue) { if (fearGreedValue <= 25) return 'Strong contrarian buy signal - market oversold'; if (fearGreedValue <= 45) return 'Cautious buy opportunity - fear dominates'; if (fearGreedValue >= 75) return 'Strong sell signal - market euphoric'; if (fearGreedValue >= 55) return 'Consider profit taking - greed increasing'; return 'Neutral sentiment - technical analysis primary'; } function getMarketRecommendation(regime, volatility) { switch (regime) { case 'EXTREME_FEAR': return volatility > 60 ? 'AGGRESSIVE_BUY' : 'MODERATE_BUY'; case 'FEAR': return 'CAUTIOUS_BUY'; case 'EXTREME_GREED': return volatility > 60 ? 'AGGRESSIVE_SELL' : 'MODERATE_SELL'; case 'GREED': return 'CAUTIOUS_SELL'; default: return 'TECHNICAL_ANALYSIS'; } } function getKeyFactors(fearGreed, btcDom, volatility) { const factors = []; if (fearGreed <= 25) factors.push('Extreme fear presents opportunity'); if (fearGreed >= 75) factors.push('Extreme greed suggests caution'); if (btcDom > 60) factors.push('Bitcoin dominance affecting altcoins'); if (btcDom < 40) factors.push('Altcoin season conditions'); if (volatility > 60) factors.push('High volatility increases risk/reward'); if (volatility < 30) factors.push('Low volatility suggests consolidation'); return factors; } function getDefaultSentimentData() { return { timestamp: new Date().toISOString(), fearAndGreed: { value: 50, classification: 'neutral', interpretation: 'Default neutral sentiment', source: 'default' }, bitcoinDominance: { value: 50, interpretation: 'BALANCED' }, volatility: { index: 50, level: 'MODERATE' }, marketRegime: { current: 'NEUTRAL', riskLevel: 'BALANCED', correlationLevel: 'NORMAL' }, tradingThresholds: { buy: 65, sell: 65, maxPosition: 1.0 }, summary: { sentiment: 'Neutral market with balanced risk level', recommendation: 'TECHNICAL_ANALYSIS', keyFactors: ['Default sentiment data - external APIs unavailable'] } }; }