bourahima commited on
Commit
bad22a3
·
verified ·
1 Parent(s): 0e9eb74

Add 1 files

Browse files
Files changed (1) hide show
  1. index.html +355 -28
index.html CHANGED
@@ -3,9 +3,10 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Crypto Tracker - Suivi des cryptomonnaies en temps réel</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
 
9
  <style>
10
  @keyframes pulse {
11
  0%, 100% { opacity: 1; }
@@ -32,6 +33,31 @@
32
  background-color: #2d3748;
33
  border-color: #4a5568;
34
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  </style>
36
  </head>
37
  <body class="bg-gray-100 font-sans">
@@ -42,7 +68,7 @@
42
  <div class="flex justify-between items-center">
43
  <div class="flex items-center space-x-2">
44
  <i class="fab fa-bitcoin text-3xl text-yellow-400"></i>
45
- <h1 class="text-2xl font-bold">Crypto Tracker</h1>
46
  </div>
47
  <div class="flex items-center space-x-4">
48
  <button id="refreshBtn" class="bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded-lg flex items-center">
@@ -57,8 +83,8 @@
57
  <div class="mt-8">
58
  <div class="flex flex-col md:flex-row justify-between items-center">
59
  <div>
60
- <h2 class="text-xl font-semibold">Suivi des cryptomonnaies en temps réel</h2>
61
- <p class="text-blue-200">Données actualisées toutes les minutes</p>
62
  </div>
63
  <div class="mt-4 md:mt-0 relative">
64
  <input type="text" id="searchInput" placeholder="Rechercher une crypto..."
@@ -74,13 +100,14 @@
74
  <main class="container mx-auto px-4 py-8">
75
  <!-- Market Overview -->
76
  <div class="bg-white rounded-xl shadow-md p-6 mb-8 dark-mode">
77
- <h2 class="text-xl font-bold mb-4">Aperçu du marché</h2>
78
- <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
79
  <div class="bg-blue-50 p-4 rounded-lg dark:bg-gray-700">
80
  <div class="flex justify-between items-center">
81
  <div>
82
  <p class="text-gray-600 dark:text-gray-300">Capitalisation totale</p>
83
  <h3 id="totalMarketCap" class="text-2xl font-bold">Chargement...</h3>
 
84
  </div>
85
  <i class="fas fa-chart-line text-blue-500 text-3xl"></i>
86
  </div>
@@ -90,6 +117,7 @@
90
  <div>
91
  <p class="text-gray-600 dark:text-gray-300">Volume 24h</p>
92
  <h3 id="totalVolume" class="text-2xl font-bold">Chargement...</h3>
 
93
  </div>
94
  <i class="fas fa-exchange-alt text-green-500 text-3xl"></i>
95
  </div>
@@ -99,19 +127,30 @@
99
  <div>
100
  <p class="text-gray-600 dark:text-gray-300">Dominance BTC</p>
101
  <h3 id="btcDominance" class="text-2xl font-bold">Chargement...</h3>
 
102
  </div>
103
  <i class="fab fa-bitcoin text-purple-500 text-3xl"></i>
104
  </div>
105
  </div>
 
 
 
 
 
 
 
 
 
 
106
  </div>
107
  </div>
108
 
109
  <!-- Crypto List -->
110
  <div class="mb-8">
111
  <div class="flex justify-between items-center mb-4">
112
- <h2 class="text-xl font-bold">Top Cryptomonnaies</h2>
113
  <div class="flex space-x-2">
114
- <button id="sortMarketCap" class="bg-gray-200 hover:bg-gray-300 px-3 py-1 rounded text-sm dark:bg-gray-700 dark:hover:bg-gray-600">
115
  Par capitalisation
116
  </button>
117
  <button id="sortVolume" class="bg-gray-200 hover:bg-gray-300 px-3 py-1 rounded text-sm dark:bg-gray-700 dark:hover:bg-gray-600">
@@ -120,14 +159,17 @@
120
  <button id="sortChange" class="bg-gray-200 hover:bg-gray-300 px-3 py-1 rounded text-sm dark:bg-gray-700 dark:hover:bg-gray-600">
121
  Par variation
122
  </button>
 
 
 
123
  </div>
124
  </div>
125
 
126
  <div id="cryptoList" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
127
  <!-- Les cartes de cryptomonnaies seront ajoutées ici par JavaScript -->
128
- <div class="animate-pulse bg-gray-200 rounded-xl p-6 h-40 dark:bg-gray-700"></div>
129
- <div class="animate-pulse bg-gray-200 rounded-xl p-6 h-40 dark:bg-gray-700"></div>
130
- <div class="animate-pulse bg-gray-200 rounded-xl p-6 h-40 dark:bg-gray-700"></div>
131
  </div>
132
  </div>
133
 
@@ -151,8 +193,8 @@
151
  <div class="container mx-auto px-4">
152
  <div class="flex flex-col md:flex-row justify-between items-center">
153
  <div class="mb-4 md:mb-0">
154
- <p>&copy; 2023 Crypto Tracker. Tous droits réservés.</p>
155
- <p class="text-gray-400 text-sm">Données fournies par CoinGecko API</p>
156
  </div>
157
  <div class="flex space-x-4">
158
  <a href="#" class="hover:text-blue-300"><i class="fab fa-twitter"></i></a>
@@ -181,15 +223,22 @@
181
  const totalMarketCap = document.getElementById('totalMarketCap');
182
  const totalVolume = document.getElementById('totalVolume');
183
  const btcDominance = document.getElementById('btcDominance');
 
 
 
 
 
184
  const sortMarketCap = document.getElementById('sortMarketCap');
185
  const sortVolume = document.getElementById('sortVolume');
186
  const sortChange = document.getElementById('sortChange');
 
187
 
188
  // Variables d'état
189
  let cryptoData = [];
190
  let favorites = JSON.parse(localStorage.getItem(favoritesKey)) || [];
191
  let currentSort = 'market_cap';
192
  let isDarkMode = localStorage.getItem('darkMode') === 'true';
 
193
 
194
  // Initialisation
195
  if (isDarkMode) {
@@ -206,15 +255,16 @@
206
  sortMarketCap.addEventListener('click', () => sortCryptos('market_cap'));
207
  sortVolume.addEventListener('click', () => sortCryptos('volume'));
208
  sortChange.addEventListener('click', () => sortCryptos('price_change_percentage_24h'));
 
209
 
210
  // Fonctions
211
  async function fetchData() {
212
  try {
213
  loadingIndicator.classList.remove('hidden');
214
  cryptoList.innerHTML = `
215
- <div class="animate-pulse bg-gray-200 rounded-xl p-6 h-40 dark:bg-gray-700"></div>
216
- <div class="animate-pulse bg-gray-200 rounded-xl p-6 h-40 dark:bg-gray-700"></div>
217
- <div class="animate-pulse bg-gray-200 rounded-xl p-6 h-40 dark:bg-gray-700"></div>
218
  `;
219
 
220
  // Récupérer les données globales
@@ -222,10 +272,16 @@
222
  const globalData = await globalResponse.json();
223
  updateGlobalData(globalData.data);
224
 
225
- // Récupérer les cryptomonnaies
226
- const response = await fetch(`${apiUrl}/coins/markets?vs_currency=eur&order=market_cap_desc&per_page=30&page=1&sparkline=false&price_change_percentage=24h`);
 
 
 
227
  cryptoData = await response.json();
228
 
 
 
 
229
  renderCryptoList(cryptoData);
230
  updateFavoritesSection();
231
 
@@ -241,10 +297,104 @@
241
  }
242
  }
243
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
  function updateGlobalData(data) {
245
  totalMarketCap.textContent = formatCurrency(data.total_market_cap.eur);
246
  totalVolume.textContent = formatCurrency(data.total_volume.eur);
247
  btcDominance.textContent = `${data.market_cap_percentage.btc.toFixed(1)}%`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
  }
249
 
250
  function renderCryptoList(data) {
@@ -265,6 +415,16 @@
265
  const changeClass = priceChange >= 0 ? 'text-green-500' : 'text-red-500';
266
  const changeIcon = priceChange >= 0 ? 'fa-arrow-up' : 'fa-arrow-down';
267
 
 
 
 
 
 
 
 
 
 
 
268
  const card = document.createElement('div');
269
  card.className = 'coin-card bg-white rounded-xl shadow-md p-6 transition-all duration-300 dark-mode';
270
  card.innerHTML = `
@@ -276,11 +436,22 @@
276
  <p class="text-gray-500 text-sm">${crypto.symbol.toUpperCase()}</p>
277
  </div>
278
  </div>
279
- <button class="favorite-btn text-${isFavorite ? 'yellow' : 'gray'}-400 hover:text-yellow-500 focus:outline-none" data-id="${crypto.id}">
280
- <i class="fas fa-star"></i>
281
- </button>
 
 
 
 
 
 
 
 
 
 
282
  </div>
283
- <div class="flex justify-between items-end">
 
284
  <div>
285
  <p class="text-gray-500 text-sm">Prix</p>
286
  <p class="text-xl font-bold">${formatCurrency(crypto.current_price)}</p>
@@ -293,6 +464,22 @@
293
  </p>
294
  </div>
295
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
296
  <div class="mt-4 pt-4 border-t border-gray-200 dark:border-gray-600">
297
  <div class="flex justify-between text-sm">
298
  <div>
@@ -308,6 +495,11 @@
308
  `;
309
 
310
  cryptoList.appendChild(card);
 
 
 
 
 
311
  });
312
 
313
  // Ajouter les événements aux boutons favoris
@@ -319,6 +511,80 @@
319
  });
320
  }
321
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322
  function toggleFavorite(cryptoId) {
323
  const index = favorites.indexOf(cryptoId);
324
  if (index === -1) {
@@ -356,6 +622,14 @@
356
  const changeClass = priceChange >= 0 ? 'text-green-500' : 'text-red-500';
357
  const changeIcon = priceChange >= 0 ? 'fa-arrow-up' : 'fa-arrow-down';
358
 
 
 
 
 
 
 
 
 
359
  const card = document.createElement('div');
360
  card.className = 'coin-card bg-white rounded-xl shadow-md p-6 transition-all duration-300 dark-mode';
361
  card.innerHTML = `
@@ -367,11 +641,22 @@
367
  <p class="text-gray-500 text-sm">${crypto.symbol.toUpperCase()}</p>
368
  </div>
369
  </div>
370
- <button class="favorite-btn text-yellow-400 hover:text-yellow-500 focus:outline-none" data-id="${crypto.id}">
371
- <i class="fas fa-star"></i>
372
- </button>
 
 
 
 
 
 
 
 
 
 
373
  </div>
374
- <div class="flex justify-between items-end">
 
375
  <div>
376
  <p class="text-gray-500 text-sm">Prix</p>
377
  <p class="text-xl font-bold">${formatCurrency(crypto.current_price)}</p>
@@ -384,6 +669,22 @@
384
  </p>
385
  </div>
386
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
387
  <div class="mt-4 pt-4 border-t border-gray-200 dark:border-gray-600">
388
  <div class="flex justify-between text-sm">
389
  <div>
@@ -399,6 +700,11 @@
399
  `;
400
 
401
  favoritesList.appendChild(card);
 
 
 
 
 
402
  });
403
 
404
  // Ajouter les événements aux boutons favoris
@@ -435,13 +741,17 @@
435
  });
436
 
437
  const activeBtn = document.getElementById(`sort${sortBy.charAt(0).toUpperCase() + sortBy.slice(1).replace('_', ' ').split(' ')[0]}`);
438
- activeBtn.classList.remove('bg-gray-200', 'dark:bg-gray-700');
439
- activeBtn.classList.add('bg-blue-500', 'text-white');
 
 
440
 
441
  // Trier les données
442
  const sorted = [...cryptoData].sort((a, b) => {
443
  if (sortBy === 'price_change_percentage_24h') {
444
  return b[sortBy] - a[sortBy];
 
 
445
  } else {
446
  return b[sortBy] - a[sortBy];
447
  }
@@ -461,6 +771,12 @@
461
  darkModeToggle.innerHTML = '<i class="fas fa-moon"></i>';
462
  localStorage.setItem('darkMode', 'false');
463
  }
 
 
 
 
 
 
464
  }
465
 
466
  function formatCurrency(value) {
@@ -472,6 +788,17 @@
472
  }).format(value);
473
  }
474
 
 
 
 
 
 
 
 
 
 
 
 
475
  // Actualiser les données toutes les minutes
476
  setInterval(fetchData, 60000);
477
  });
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Crypto Tracker Pro - Analyse des cryptomonnaies</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
10
  <style>
11
  @keyframes pulse {
12
  0%, 100% { opacity: 1; }
 
33
  background-color: #2d3748;
34
  border-color: #4a5568;
35
  }
36
+ .chart-container {
37
+ position: relative;
38
+ height: 200px;
39
+ width: 100%;
40
+ }
41
+ .trend-indicator {
42
+ display: inline-flex;
43
+ align-items: center;
44
+ padding: 2px 8px;
45
+ border-radius: 12px;
46
+ font-size: 12px;
47
+ font-weight: 600;
48
+ }
49
+ .trend-up {
50
+ background-color: rgba(16, 185, 129, 0.1);
51
+ color: #10b981;
52
+ }
53
+ .trend-down {
54
+ background-color: rgba(239, 68, 68, 0.1);
55
+ color: #ef4444;
56
+ }
57
+ .trend-neutral {
58
+ background-color: rgba(156, 163, 175, 0.1);
59
+ color: #9ca3af;
60
+ }
61
  </style>
62
  </head>
63
  <body class="bg-gray-100 font-sans">
 
68
  <div class="flex justify-between items-center">
69
  <div class="flex items-center space-x-2">
70
  <i class="fab fa-bitcoin text-3xl text-yellow-400"></i>
71
+ <h1 class="text-2xl font-bold">Crypto Tracker Pro</h1>
72
  </div>
73
  <div class="flex items-center space-x-4">
74
  <button id="refreshBtn" class="bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded-lg flex items-center">
 
83
  <div class="mt-8">
84
  <div class="flex flex-col md:flex-row justify-between items-center">
85
  <div>
86
+ <h2 class="text-xl font-semibold">Analyse technique des cryptomonnaies</h2>
87
+ <p class="text-blue-200">Tendances, moyennes mobiles et indicateurs techniques</p>
88
  </div>
89
  <div class="mt-4 md:mt-0 relative">
90
  <input type="text" id="searchInput" placeholder="Rechercher une crypto..."
 
100
  <main class="container mx-auto px-4 py-8">
101
  <!-- Market Overview -->
102
  <div class="bg-white rounded-xl shadow-md p-6 mb-8 dark-mode">
103
+ <h2 class="text-xl font-bold mb-4">Indicateurs du marché</h2>
104
+ <div class="grid grid-cols-1 md:grid-cols-4 gap-4">
105
  <div class="bg-blue-50 p-4 rounded-lg dark:bg-gray-700">
106
  <div class="flex justify-between items-center">
107
  <div>
108
  <p class="text-gray-600 dark:text-gray-300">Capitalisation totale</p>
109
  <h3 id="totalMarketCap" class="text-2xl font-bold">Chargement...</h3>
110
+ <p id="marketCapChange" class="text-sm mt-1">Chargement...</p>
111
  </div>
112
  <i class="fas fa-chart-line text-blue-500 text-3xl"></i>
113
  </div>
 
117
  <div>
118
  <p class="text-gray-600 dark:text-gray-300">Volume 24h</p>
119
  <h3 id="totalVolume" class="text-2xl font-bold">Chargement...</h3>
120
+ <p id="volumeChange" class="text-sm mt-1">Chargement...</p>
121
  </div>
122
  <i class="fas fa-exchange-alt text-green-500 text-3xl"></i>
123
  </div>
 
127
  <div>
128
  <p class="text-gray-600 dark:text-gray-300">Dominance BTC</p>
129
  <h3 id="btcDominance" class="text-2xl font-bold">Chargement...</h3>
130
+ <p id="btcDominanceChange" class="text-sm mt-1">Chargement...</p>
131
  </div>
132
  <i class="fab fa-bitcoin text-purple-500 text-3xl"></i>
133
  </div>
134
  </div>
135
+ <div class="bg-yellow-50 p-4 rounded-lg dark:bg-gray-700">
136
+ <div class="flex justify-between items-center">
137
+ <div>
138
+ <p class="text-gray-600 dark:text-gray-300">Indice de peur et avidité</p>
139
+ <h3 id="fearGreed" class="text-2xl font-bold">Chargement...</h3>
140
+ <p id="fearGreedText" class="text-sm mt-1">Chargement...</p>
141
+ </div>
142
+ <i class="fas fa-brain text-yellow-500 text-3xl"></i>
143
+ </div>
144
+ </div>
145
  </div>
146
  </div>
147
 
148
  <!-- Crypto List -->
149
  <div class="mb-8">
150
  <div class="flex justify-between items-center mb-4">
151
+ <h2 class="text-xl font-bold">Analyse des cryptomonnaies</h2>
152
  <div class="flex space-x-2">
153
+ <button id="sortMarketCap" class="bg-blue-500 text-white px-3 py-1 rounded text-sm">
154
  Par capitalisation
155
  </button>
156
  <button id="sortVolume" class="bg-gray-200 hover:bg-gray-300 px-3 py-1 rounded text-sm dark:bg-gray-700 dark:hover:bg-gray-600">
 
159
  <button id="sortChange" class="bg-gray-200 hover:bg-gray-300 px-3 py-1 rounded text-sm dark:bg-gray-700 dark:hover:bg-gray-600">
160
  Par variation
161
  </button>
162
+ <button id="sortTrend" class="bg-gray-200 hover:bg-gray-300 px-3 py-1 rounded text-sm dark:bg-gray-700 dark:hover:bg-gray-600">
163
+ Par tendance
164
+ </button>
165
  </div>
166
  </div>
167
 
168
  <div id="cryptoList" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
169
  <!-- Les cartes de cryptomonnaies seront ajoutées ici par JavaScript -->
170
+ <div class="animate-pulse bg-gray-200 rounded-xl p-6 h-96 dark:bg-gray-700"></div>
171
+ <div class="animate-pulse bg-gray-200 rounded-xl p-6 h-96 dark:bg-gray-700"></div>
172
+ <div class="animate-pulse bg-gray-200 rounded-xl p-6 h-96 dark:bg-gray-700"></div>
173
  </div>
174
  </div>
175
 
 
193
  <div class="container mx-auto px-4">
194
  <div class="flex flex-col md:flex-row justify-between items-center">
195
  <div class="mb-4 md:mb-0">
196
+ <p>&copy; 2023 Crypto Tracker Pro. Tous droits réservés.</p>
197
+ <p class="text-gray-400 text-sm">Données fournies par CoinGecko API et TradingView</p>
198
  </div>
199
  <div class="flex space-x-4">
200
  <a href="#" class="hover:text-blue-300"><i class="fab fa-twitter"></i></a>
 
223
  const totalMarketCap = document.getElementById('totalMarketCap');
224
  const totalVolume = document.getElementById('totalVolume');
225
  const btcDominance = document.getElementById('btcDominance');
226
+ const marketCapChange = document.getElementById('marketCapChange');
227
+ const volumeChange = document.getElementById('volumeChange');
228
+ const btcDominanceChange = document.getElementById('btcDominanceChange');
229
+ const fearGreed = document.getElementById('fearGreed');
230
+ const fearGreedText = document.getElementById('fearGreedText');
231
  const sortMarketCap = document.getElementById('sortMarketCap');
232
  const sortVolume = document.getElementById('sortVolume');
233
  const sortChange = document.getElementById('sortChange');
234
+ const sortTrend = document.getElementById('sortTrend');
235
 
236
  // Variables d'état
237
  let cryptoData = [];
238
  let favorites = JSON.parse(localStorage.getItem(favoritesKey)) || [];
239
  let currentSort = 'market_cap';
240
  let isDarkMode = localStorage.getItem('darkMode') === 'true';
241
+ let previousGlobalData = null;
242
 
243
  // Initialisation
244
  if (isDarkMode) {
 
255
  sortMarketCap.addEventListener('click', () => sortCryptos('market_cap'));
256
  sortVolume.addEventListener('click', () => sortCryptos('volume'));
257
  sortChange.addEventListener('click', () => sortCryptos('price_change_percentage_24h'));
258
+ sortTrend.addEventListener('click', () => sortCryptos('trend_strength'));
259
 
260
  // Fonctions
261
  async function fetchData() {
262
  try {
263
  loadingIndicator.classList.remove('hidden');
264
  cryptoList.innerHTML = `
265
+ <div class="animate-pulse bg-gray-200 rounded-xl p-6 h-96 dark:bg-gray-700"></div>
266
+ <div class="animate-pulse bg-gray-200 rounded-xl p-6 h-96 dark:bg-gray-700"></div>
267
+ <div class="animate-pulse bg-gray-200 rounded-xl p-6 h-96 dark:bg-gray-700"></div>
268
  `;
269
 
270
  // Récupérer les données globales
 
272
  const globalData = await globalResponse.json();
273
  updateGlobalData(globalData.data);
274
 
275
+ // Récupérer l'indice de peur et avidité (simulé)
276
+ updateFearGreedIndex();
277
+
278
+ // Récupérer les cryptomonnaies avec les données de prix historiques
279
+ const response = await fetch(`${apiUrl}/coins/markets?vs_currency=eur&order=market_cap_desc&per_page=30&page=1&sparkline=true&price_change_percentage=24h,7d,30d`);
280
  cryptoData = await response.json();
281
 
282
+ // Ajouter des données techniques simulées (moyennes mobiles et tendances)
283
+ cryptoData = await enhanceWithTechnicalData(cryptoData);
284
+
285
  renderCryptoList(cryptoData);
286
  updateFavoritesSection();
287
 
 
297
  }
298
  }
299
 
300
+ async function enhanceWithTechnicalData(cryptoData) {
301
+ // Simuler des données techniques pour chaque crypto
302
+ return cryptoData.map(crypto => {
303
+ // Générer des moyennes mobiles simulées (7 et 30 jours)
304
+ const currentPrice = crypto.current_price;
305
+ const volatility = currentPrice * 0.1; // 10% de volatilité
306
+
307
+ // Générer des données de prix historiques simulées si sparkline n'est pas disponible
308
+ const sparklineData = crypto.sparkline_in_7d?.price || Array(7).fill(0).map((_, i) => {
309
+ const daysAgo = 7 - i;
310
+ const trendFactor = crypto.price_change_percentage_7d_in_currency / 100;
311
+ return currentPrice * (1 - trendFactor * (daysAgo / 7) + (Math.random() * 0.1 - 0.05));
312
+ });
313
+
314
+ // Calculer les moyennes mobiles
315
+ const ma7 = calculateMovingAverage(sparklineData.slice(-7));
316
+ const ma30 = calculateMovingAverage(sparklineData);
317
+
318
+ // Déterminer la tendance
319
+ const trendStrength = calculateTrendStrength(sparklineData);
320
+ const trendDirection = trendStrength > 0.5 ? 'up' : trendStrength < -0.5 ? 'down' : 'neutral';
321
+
322
+ return {
323
+ ...crypto,
324
+ technicals: {
325
+ ma7,
326
+ ma30,
327
+ trend_strength: trendStrength,
328
+ trend_direction: trendDirection,
329
+ sparkline: sparklineData
330
+ }
331
+ };
332
+ });
333
+ }
334
+
335
+ function calculateMovingAverage(data) {
336
+ if (!data || data.length === 0) return 0;
337
+ const sum = data.reduce((a, b) => a + b, 0);
338
+ return sum / data.length;
339
+ }
340
+
341
+ function calculateTrendStrength(data) {
342
+ if (!data || data.length < 2) return 0;
343
+ const first = data[0];
344
+ const last = data[data.length - 1];
345
+ const change = last - first;
346
+ const range = Math.max(...data) - Math.min(...data);
347
+
348
+ if (range === 0) return 0;
349
+ return change / range; // Retourne une valeur entre -1 et 1
350
+ }
351
+
352
  function updateGlobalData(data) {
353
  totalMarketCap.textContent = formatCurrency(data.total_market_cap.eur);
354
  totalVolume.textContent = formatCurrency(data.total_volume.eur);
355
  btcDominance.textContent = `${data.market_cap_percentage.btc.toFixed(1)}%`;
356
+
357
+ // Calculer les variations si nous avons des données précédentes
358
+ if (previousGlobalData) {
359
+ const marketCapChangeValue = ((data.total_market_cap.eur - previousGlobalData.total_market_cap.eur) / previousGlobalData.total_market_cap.eur) * 100;
360
+ const volumeChangeValue = ((data.total_volume.eur - previousGlobalData.total_volume.eur) / previousGlobalData.total_volume.eur) * 100;
361
+ const btcDominanceChangeValue = data.market_cap_percentage.btc - previousGlobalData.market_cap_percentage.btc;
362
+
363
+ marketCapChange.innerHTML = formatChange(marketCapChangeValue);
364
+ volumeChange.innerHTML = formatChange(volumeChangeValue);
365
+ btcDominanceChange.innerHTML = formatChange(btcDominanceChangeValue, true);
366
+ }
367
+
368
+ previousGlobalData = data;
369
+ }
370
+
371
+ function updateFearGreedIndex() {
372
+ // Simuler l'indice de peur et avidité (0-100)
373
+ const index = Math.floor(Math.random() * 100);
374
+ fearGreed.textContent = index;
375
+
376
+ let text = "";
377
+ let colorClass = "";
378
+
379
+ if (index >= 75) {
380
+ text = "Extrême avidité";
381
+ colorClass = "text-red-500";
382
+ } else if (index >= 55) {
383
+ text = "Avidité";
384
+ colorClass = "text-yellow-500";
385
+ } else if (index >= 45) {
386
+ text = "Neutre";
387
+ colorClass = "text-gray-500";
388
+ } else if (index >= 25) {
389
+ text = "Peur";
390
+ colorClass = "text-blue-500";
391
+ } else {
392
+ text = "Extrême peur";
393
+ colorClass = "text-green-500";
394
+ }
395
+
396
+ fearGreed.className = `text-2xl font-bold ${colorClass}`;
397
+ fearGreedText.innerHTML = `<span class="${colorClass}">${text}</span>`;
398
  }
399
 
400
  function renderCryptoList(data) {
 
415
  const changeClass = priceChange >= 0 ? 'text-green-500' : 'text-red-500';
416
  const changeIcon = priceChange >= 0 ? 'fa-arrow-up' : 'fa-arrow-down';
417
 
418
+ // Données techniques
419
+ const ma7 = crypto.technicals?.ma7 || 0;
420
+ const ma30 = crypto.technicals?.ma30 || 0;
421
+ const trendDirection = crypto.technicals?.trend_direction || 'neutral';
422
+ const trendStrength = crypto.technicals?.trend_strength || 0;
423
+ const sparklineData = crypto.technicals?.sparkline || [];
424
+
425
+ // Créer un canvas pour le graphique
426
+ const canvasId = `chart-${crypto.id}`;
427
+
428
  const card = document.createElement('div');
429
  card.className = 'coin-card bg-white rounded-xl shadow-md p-6 transition-all duration-300 dark-mode';
430
  card.innerHTML = `
 
436
  <p class="text-gray-500 text-sm">${crypto.symbol.toUpperCase()}</p>
437
  </div>
438
  </div>
439
+ <div class="flex items-center">
440
+ <span class="trend-indicator trend-${trendDirection} mr-2">
441
+ ${trendDirection === 'up' ? '↑' : trendDirection === 'down' ? '↓' : '→'}
442
+ ${Math.abs(trendStrength * 100).toFixed(0)}%
443
+ </span>
444
+ <button class="favorite-btn text-${isFavorite ? 'yellow' : 'gray'}-400 hover:text-yellow-500 focus:outline-none" data-id="${crypto.id}">
445
+ <i class="fas fa-star"></i>
446
+ </button>
447
+ </div>
448
+ </div>
449
+
450
+ <div class="chart-container mb-4">
451
+ <canvas id="${canvasId}"></canvas>
452
  </div>
453
+
454
+ <div class="flex justify-between items-end mb-2">
455
  <div>
456
  <p class="text-gray-500 text-sm">Prix</p>
457
  <p class="text-xl font-bold">${formatCurrency(crypto.current_price)}</p>
 
464
  </p>
465
  </div>
466
  </div>
467
+
468
+ <div class="grid grid-cols-2 gap-2 text-sm mb-2">
469
+ <div>
470
+ <p class="text-gray-500">MA7</p>
471
+ <p class="${crypto.current_price > ma7 ? 'text-green-500' : 'text-red-500'}">
472
+ ${formatCurrency(ma7)}
473
+ </p>
474
+ </div>
475
+ <div class="text-right">
476
+ <p class="text-gray-500">MA30</p>
477
+ <p class="${crypto.current_price > ma30 ? 'text-green-500' : 'text-red-500'}">
478
+ ${formatCurrency(ma30)}
479
+ </p>
480
+ </div>
481
+ </div>
482
+
483
  <div class="mt-4 pt-4 border-t border-gray-200 dark:border-gray-600">
484
  <div class="flex justify-between text-sm">
485
  <div>
 
495
  `;
496
 
497
  cryptoList.appendChild(card);
498
+
499
+ // Rendre le graphique après que l'élément a été ajouté au DOM
500
+ setTimeout(() => {
501
+ renderSparklineChart(canvasId, sparklineData, crypto.current_price, ma7, ma30);
502
+ }, 100);
503
  });
504
 
505
  // Ajouter les événements aux boutons favoris
 
511
  });
512
  }
513
 
514
+ function renderSparklineChart(canvasId, sparklineData, currentPrice, ma7, ma30) {
515
+ const ctx = document.getElementById(canvasId).getContext('2d');
516
+ const chartColor = isDarkMode ? '#3b82f6' : '#2563eb';
517
+ const bgColor = isDarkMode ? 'rgba(59, 130, 246, 0.1)' : 'rgba(37, 99, 235, 0.1)';
518
+
519
+ // Préparer les données pour le graphique
520
+ const labels = Array(sparklineData.length).fill('');
521
+ const ma7Data = Array(sparklineData.length).fill(ma7);
522
+ const ma30Data = Array(sparklineData.length).fill(ma30);
523
+
524
+ new Chart(ctx, {
525
+ type: 'line',
526
+ data: {
527
+ labels: labels,
528
+ datasets: [
529
+ {
530
+ label: 'Prix',
531
+ data: sparklineData,
532
+ borderColor: chartColor,
533
+ backgroundColor: bgColor,
534
+ borderWidth: 2,
535
+ fill: true,
536
+ tension: 0.4
537
+ },
538
+ {
539
+ label: 'MA7',
540
+ data: ma7Data,
541
+ borderColor: '#10b981',
542
+ borderWidth: 1,
543
+ borderDash: [5, 5],
544
+ pointRadius: 0,
545
+ tension: 0
546
+ },
547
+ {
548
+ label: 'MA30',
549
+ data: ma30Data,
550
+ borderColor: '#8b5cf6',
551
+ borderWidth: 1,
552
+ borderDash: [5, 5],
553
+ pointRadius: 0,
554
+ tension: 0
555
+ }
556
+ ]
557
+ },
558
+ options: {
559
+ responsive: true,
560
+ maintainAspectRatio: false,
561
+ plugins: {
562
+ legend: {
563
+ display: false
564
+ },
565
+ tooltip: {
566
+ enabled: false
567
+ }
568
+ },
569
+ scales: {
570
+ x: {
571
+ display: false
572
+ },
573
+ y: {
574
+ display: false,
575
+ suggestedMin: Math.min(...sparklineData) * 0.95,
576
+ suggestedMax: Math.max(...sparklineData) * 1.05
577
+ }
578
+ },
579
+ elements: {
580
+ point: {
581
+ radius: 0
582
+ }
583
+ }
584
+ }
585
+ });
586
+ }
587
+
588
  function toggleFavorite(cryptoId) {
589
  const index = favorites.indexOf(cryptoId);
590
  if (index === -1) {
 
622
  const changeClass = priceChange >= 0 ? 'text-green-500' : 'text-red-500';
623
  const changeIcon = priceChange >= 0 ? 'fa-arrow-up' : 'fa-arrow-down';
624
 
625
+ // Données techniques
626
+ const ma7 = crypto.technicals?.ma7 || 0;
627
+ const ma30 = crypto.technicals?.ma30 || 0;
628
+ const trendDirection = crypto.technicals?.trend_direction || 'neutral';
629
+ const trendStrength = crypto.technicals?.trend_strength || 0;
630
+ const sparklineData = crypto.technicals?.sparkline || [];
631
+ const canvasId = `fav-chart-${crypto.id}`;
632
+
633
  const card = document.createElement('div');
634
  card.className = 'coin-card bg-white rounded-xl shadow-md p-6 transition-all duration-300 dark-mode';
635
  card.innerHTML = `
 
641
  <p class="text-gray-500 text-sm">${crypto.symbol.toUpperCase()}</p>
642
  </div>
643
  </div>
644
+ <div class="flex items-center">
645
+ <span class="trend-indicator trend-${trendDirection} mr-2">
646
+ ${trendDirection === 'up' ? '↑' : trendDirection === 'down' ? '↓' : '→'}
647
+ ${Math.abs(trendStrength * 100).toFixed(0)}%
648
+ </span>
649
+ <button class="favorite-btn text-yellow-400 hover:text-yellow-500 focus:outline-none" data-id="${crypto.id}">
650
+ <i class="fas fa-star"></i>
651
+ </button>
652
+ </div>
653
+ </div>
654
+
655
+ <div class="chart-container mb-4">
656
+ <canvas id="${canvasId}"></canvas>
657
  </div>
658
+
659
+ <div class="flex justify-between items-end mb-2">
660
  <div>
661
  <p class="text-gray-500 text-sm">Prix</p>
662
  <p class="text-xl font-bold">${formatCurrency(crypto.current_price)}</p>
 
669
  </p>
670
  </div>
671
  </div>
672
+
673
+ <div class="grid grid-cols-2 gap-2 text-sm mb-2">
674
+ <div>
675
+ <p class="text-gray-500">MA7</p>
676
+ <p class="${crypto.current_price > ma7 ? 'text-green-500' : 'text-red-500'}">
677
+ ${formatCurrency(ma7)}
678
+ </p>
679
+ </div>
680
+ <div class="text-right">
681
+ <p class="text-gray-500">MA30</p>
682
+ <p class="${crypto.current_price > ma30 ? 'text-green-500' : 'text-red-500'}">
683
+ ${formatCurrency(ma30)}
684
+ </p>
685
+ </div>
686
+ </div>
687
+
688
  <div class="mt-4 pt-4 border-t border-gray-200 dark:border-gray-600">
689
  <div class="flex justify-between text-sm">
690
  <div>
 
700
  `;
701
 
702
  favoritesList.appendChild(card);
703
+
704
+ // Rendre le graphique après que l'élément a été ajouté au DOM
705
+ setTimeout(() => {
706
+ renderSparklineChart(canvasId, sparklineData, crypto.current_price, ma7, ma30);
707
+ }, 100);
708
  });
709
 
710
  // Ajouter les événements aux boutons favoris
 
741
  });
742
 
743
  const activeBtn = document.getElementById(`sort${sortBy.charAt(0).toUpperCase() + sortBy.slice(1).replace('_', ' ').split(' ')[0]}`);
744
+ if (activeBtn) {
745
+ activeBtn.classList.remove('bg-gray-200', 'dark:bg-gray-700');
746
+ activeBtn.classList.add('bg-blue-500', 'text-white');
747
+ }
748
 
749
  // Trier les données
750
  const sorted = [...cryptoData].sort((a, b) => {
751
  if (sortBy === 'price_change_percentage_24h') {
752
  return b[sortBy] - a[sortBy];
753
+ } else if (sortBy === 'trend_strength') {
754
+ return (b.technicals?.trend_strength || 0) - (a.technicals?.trend_strength || 0);
755
  } else {
756
  return b[sortBy] - a[sortBy];
757
  }
 
771
  darkModeToggle.innerHTML = '<i class="fas fa-moon"></i>';
772
  localStorage.setItem('darkMode', 'false');
773
  }
774
+
775
+ // Re-rendre les graphiques avec les nouvelles couleurs
776
+ renderCryptoList(cryptoData);
777
+ if (favoritesSection && !favoritesSection.classList.contains('hidden')) {
778
+ updateFavoritesSection();
779
+ }
780
  }
781
 
782
  function formatCurrency(value) {
 
788
  }).format(value);
789
  }
790
 
791
+ function formatChange(value, isPercentage = false) {
792
+ if (value === undefined || value === null) return '';
793
+
794
+ const absValue = Math.abs(value);
795
+ const formattedValue = isPercentage ? absValue.toFixed(2) : absValue.toFixed(1);
796
+ const arrow = value >= 0 ? '↑' : '↓';
797
+ const colorClass = value >= 0 ? 'text-green-500' : 'text-red-500';
798
+
799
+ return `<span class="${colorClass}">${arrow} ${formattedValue}${isPercentage ? '%' : ''}</span>`;
800
+ }
801
+
802
  // Actualiser les données toutes les minutes
803
  setInterval(fetchData, 60000);
804
  });