File size: 6,079 Bytes
27815f8
 
 
 
 
 
 
e46f337
27815f8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d7d21d7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27815f8
 
 
d7d21d7
 
27815f8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e46f337
 
 
 
27815f8
 
 
e46f337
27815f8
 
 
 
e46f337
27815f8
 
 
 
 
 
 
 
 
 
e46f337
27815f8
 
 
 
 
 
 
 
 
 
 
 
 
 
e46f337
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27815f8
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// 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);