lonestar108's picture
replace the mock RSI calculation with a real one
d7d21d7 verified
// 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 = `
<div class="p-6">
<div class="flex justify-between items-start">
<div class="flex items-center space-x-3">
<img src="${crypto.image}" alt="${crypto.name}" class="w-10 h-10 rounded-full">
<div>
<h3 class="font-bold text-lg">${crypto.symbol.toUpperCase()}</h3>
<p class="text-gray-400 text-sm">${crypto.name}</p>
</div>
</div>
<span class="px-3 py-1 rounded-full text-xs font-semibold ${rsiClass}">
RSI: ${rsi}
</span>
</div>
<div class="mt-4 h-16">
<canvas class="sparkline" data-prices="${crypto.sparkline_in_7d.price.join(',')}" data-color="${isPumping ? '#10b981' : '#ef4444'}"></canvas>
</div>
<div class="mt-6">
<div class="flex justify-between items-center mb-2">
<span class="text-gray-400">Price</span>
<span class="font-bold">${crypto.current_price.toLocaleString()}</span>
</div>
<div class="flex justify-between items-center mb-2">
<span class="text-gray-400">Market Cap</span>
<span class="font-bold">${(crypto.market_cap / 1000000000).toFixed(2)}B</span>
</div>
<div class="flex justify-between items-center">
<span class="text-gray-400">24h Change</span>
<span class="font-bold ${isPumping ? 'text-secondary-500' : 'text-red-500'}">
${isPumping ? '+' : ''}${crypto.price_change_percentage_24h.toFixed(2)}%
<i data-feather="${isPumping ? 'trending-up' : 'trending-down'}" class="inline ml-1"></i>
</span>
</div>
</div>
</div>
`;
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);