// API Configuration const API_URL = 'https://api.coingecko.com/api/v3/coins/markets'; const API_PARAMS = { vs_currency: 'usd', order: 'market_cap_desc', per_page: 50, page: 1, sparkline: true, price_change_percentage: '1h,24h,7d' }; // DOM Elements const cryptoGrid = document.getElementById('crypto-grid'); // Fetch crypto data async function fetchCryptoData() { try { const response = await fetch(`${API_URL}?${new URLSearchParams(API_PARAMS)}`); const data = await response.json(); return data; } catch (error) { console.error('Error fetching crypto data:', error); return []; } } // Calculate RSI (Relative Strength Index) function calculateRSI(priceHistory, period = 14) { if (!priceHistory || priceHistory.length < period + 1) return 50; // Default neutral value // Calculate price changes const changes = []; for (let i = 1; i < priceHistory.length; i++) { changes.push(priceHistory[i] - priceHistory[i-1]); } // Separate gains and losses const gains = changes.map(change => change > 0 ? change : 0); const losses = changes.map(change => change < 0 ? Math.abs(change) : 0); // Calculate average gains and losses for the period let avgGain = gains.slice(0, period).reduce((sum, gain) => sum + gain, 0) / period; let avgLoss = losses.slice(0, period).reduce((sum, loss) => sum + loss, 0) / period; // Calculate subsequent average gains/losses using smoothing for (let i = period; i < changes.length; i++) { avgGain = (avgGain * (period - 1) + gains[i]) / period; avgLoss = (avgLoss * (period - 1) + losses[i]) / period; } // Avoid division by zero if (avgLoss === 0) return 100; // Calculate relative strength and RSI const relativeStrength = avgGain / avgLoss; const rsi = 100 - (100 / (1 + relativeStrength)); return Math.round(rsi * 100) / 100; // Round to 2 decimal places } // Create crypto card function createCryptoCard(crypto) { const rsi = calculateRSI(crypto.sparkline_in_7d.price); const isPumping = crypto.price_change_percentage_24h > 0; let rsiClass = 'rsi-medium'; if (rsi < 30) rsiClass = 'rsi-low'; if (rsi > 70) rsiClass = 'rsi-high'; const card = document.createElement('div'); card.className = `bg-gray-800 rounded-xl overflow-hidden shadow-lg smooth-transition hover:shadow-xl hover:-translate-y-1 ${isPumping ? 'border-l-4 border-primary-500' : 'border-l-4 border-red-500'}`; card.innerHTML = `
${crypto.name}

${crypto.symbol.toUpperCase()}

${crypto.name}

RSI: ${rsi}
Price ${crypto.current_price.toLocaleString()}
Market Cap ${(crypto.market_cap / 1000000000).toFixed(2)}B
24h Change ${isPumping ? '+' : ''}${crypto.price_change_percentage_24h.toFixed(2)}%
`; return card; } // Initialize app async function initApp() { const cryptos = await fetchCryptoData(); cryptoGrid.innerHTML = ''; cryptos.forEach(crypto => { const card = createCryptoCard(crypto); cryptoGrid.appendChild(card); }); // Render sparklines document.querySelectorAll('.sparkline').forEach(canvas => { const prices = canvas.dataset.prices.split(',').map(Number); const color = canvas.dataset.color; const ctx = canvas.getContext('2d'); // Set canvas size canvas.width = canvas.offsetWidth; canvas.height = canvas.offsetHeight; // Calculate max and min for scaling const max = Math.max(...prices); const min = Math.min(...prices); const range = max - min || 1; // Avoid division by zero // Draw sparkline ctx.beginPath(); ctx.strokeStyle = color; ctx.lineWidth = 2; prices.forEach((price, i) => { const x = (canvas.width / (prices.length - 1)) * i; const y = canvas.height - ((price - min) / range) * canvas.height; if (i === 0) { ctx.moveTo(x, y); } else { ctx.lineTo(x, y); } }); ctx.stroke(); }); feather.replace(); } // Refresh data every 60 seconds setInterval(initApp, 60000); // Initial load document.addEventListener('DOMContentLoaded', initApp);