Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>CryptoPulse Navigator - Intelligent CoinGlass Dashboard</title> | |
| <link rel="icon" type="image/x-icon" href="/static/favicon.ico"> | |
| <link rel="stylesheet" href="/static/style.css"> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>CryptoPulse Navigator - Intelligent CoinGlass Dashboard</title> | |
| <link rel="icon" type="image/x-icon" href="/static/favicon.ico"> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> | |
| <script src="https://unpkg.com/feather-icons"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.net.min.js"></script> | |
| <script> | |
| tailwind.config = { | |
| theme: { | |
| extend: { | |
| colors: { | |
| primary: '#6366f1', | |
| secondary: '#10b981', | |
| dark: '#1e293b', | |
| darker: '#0f172a' | |
| } | |
| } | |
| } | |
| } | |
| </script> | |
| <style> | |
| @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap'); | |
| body { | |
| font-family: 'Space Grotesk', sans-serif; | |
| } | |
| .glass-card { | |
| backdrop-filter: blur(16px) saturate(180%); | |
| -webkit-backdrop-filter: blur(16px) saturate(180%); | |
| background-color: rgba(30, 41, 59, 0.75); | |
| border: 1px solid rgba(255, 255, 255, 0.125); | |
| } | |
| .phase-badge { | |
| transition: all 0.3s ease; | |
| } | |
| .phase-badge:hover { | |
| transform: scale(1.05); | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-darker text-white min-h-screen"> | |
| <div id="vanta-bg" class="fixed inset-0 -z-10"></div> | |
| <div class="container mx-auto px-4 py-8"> | |
| <!-- Header --> | |
| <header class="flex justify-between items-center mb-8"> | |
| <div> | |
| <h1 class="text-3xl font-bold flex items-center"> | |
| <i data-feather="activity" class="mr-2 text-primary"></i> | |
| CryptoPulse <span class="text-primary">Navigator</span> | |
| </h1> | |
| <p class="text-gray-400">Intelligent CoinGlass Dashboard</p> | |
| </div> | |
| <div class="flex items-center space-x-4"> | |
| <div id="status-badge" class="px-3 py-1 rounded-full bg-opacity-20 bg-green-500 text-green-300 flex items-center"> | |
| <span class="w-2 h-2 rounded-full bg-green-500 mr-2"></span> | |
| <span>Live</span> | |
| </div> | |
| <div id="last-updated" class="text-gray-400 text-sm"> | |
| <i data-feather="clock" class="w-4 h-4 inline mr-1"></i> | |
| <span>Updating...</span> | |
| </div> | |
| <button id="refresh-btn" class="p-2 rounded-full hover:bg-gray-800 transition"> | |
| <i data-feather="refresh-cw" class="w-5 h-5"></i> | |
| </button> | |
| </div> | |
| </header> | |
| <!-- PHI Score and Market Phase --> | |
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-8"> | |
| <!-- PHI Score Card --> | |
| <div class="glass-card p-6 rounded-xl col-span-1 lg:col-span-2"> | |
| <div class="flex justify-between items-start mb-4"> | |
| <div> | |
| <h2 class="text-xl font-semibold">Market Health Index</h2> | |
| <p class="text-gray-400 text-sm">PHI Score (Position Health Index)</p> | |
| </div> | |
| <div id="phase-badge" class="px-3 py-1 rounded-full bg-opacity-20 bg-secondary text-secondary phase-badge"> | |
| Loading... | |
| </div> | |
| </div> | |
| <div class="flex items-center"> | |
| <div class="w-32 h-32 flex items-center justify-center relative"> | |
| <canvas id="phi-gauge" width="160" height="160"></canvas> | |
| <div class="absolute text-center"> | |
| <div id="phi-score" class="text-4xl font-bold">--</div> | |
| <div class="text-xs text-gray-400">PHI Score</div> | |
| </div> | |
| </div> | |
| <div class="ml-6 flex-1"> | |
| <div class="mb-4"> | |
| <div class="flex justify-between text-sm mb-1"> | |
| <span>Volatility (VOLX)</span> | |
| <span id="volx-value" class="font-medium">--</span> | |
| </div> | |
| <div class="w-full bg-gray-700 rounded-full h-2"> | |
| <div id="volx-bar" class="bg-yellow-500 h-2 rounded-full" style="width: 0%"></div> | |
| </div> | |
| </div> | |
| <div class="mb-4"> | |
| <div class="flex justify-between text-sm mb-1"> | |
| <span>Momentum (MOMX)</span> | |
| <span id="momx-value" class="font-medium">--</span> | |
| </div> | |
| <div class="w-full bg-gray-700 rounded-full h-2"> | |
| <div id="momx-bar" class="bg-blue-500 h-2 rounded-full" style="width: 0%"></div> | |
| </div> | |
| </div> | |
| <div class="mb-4"> | |
| <div class="flex justify-between text-sm mb-1"> | |
| <span>Funding Bias (FBS)</span> | |
| <span id="fbs-value" class="font-medium">--</span> | |
| </div> | |
| <div class="w-full bg-gray-700 rounded-full h-2"> | |
| <div id="fbs-bar" class="bg-purple-500 h-2 rounded-full" style="width: 0%"></div> | |
| </div> | |
| </div> | |
| <div> | |
| <div class="flex justify-between text-sm mb-1"> | |
| <span>Leverage (LPI)</span> | |
| <span id="lpi-value" class="font-medium">--</span> | |
| </div> | |
| <div class="w-full bg-gray-700 rounded-full h-2"> | |
| <div id="lpi-bar" class="bg-red-500 h-2 rounded-full" style="width: 0%"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Market Overview --> | |
| <div class="glass-card p-6 rounded-xl"> | |
| <h2 class="text-xl font-semibold mb-4">Market Overview</h2> | |
| <div class="space-y-4"> | |
| <div> | |
| <div class="flex justify-between text-sm mb-1"> | |
| <span>Long/Short Ratio</span> | |
| <span id="ls-ratio-value" class="font-medium">--</span> | |
| </div> | |
| <div class="w-full h-3 bg-gray-700 rounded-full overflow-hidden"> | |
| <div class="h-full flex"> | |
| <div id="long-bar" class="bg-green-500" style="width: 50%"></div> | |
| <div id="short-bar" class="bg-red-500" style="width: 50%"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <div> | |
| <div class="text-sm mb-1">Fear & Greed Index</div> | |
| <div class="w-full bg-gray-700 rounded-full h-2"> | |
| <div id="fear-greed-bar" class="bg-gradient-to-r from-red-500 via-yellow-500 to-green-500 h-2 rounded-full" style="width: 50%"></div> | |
| </div> | |
| <div id="fear-greed-value" class="text-right text-xs mt-1">--</div> | |
| </div> | |
| <div class="pt-2"> | |
| <div class="text-sm mb-1">Market Phase</div> | |
| <div id="phase-description" class="text-sm text-gray-300"> | |
| Loading market phase description... | |
| </div> | |
| </div> | |
| <div class="pt-2"> | |
| <div class="text-sm mb-1">Risk Level</div> | |
| <div id="risk-level" class="text-sm font-medium"> | |
| <span class="px-2 py-1 rounded bg-opacity-20 bg-gray-500">Calculating...</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- BTC/ETH Cards --> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8"> | |
| <!-- BTC Card --> | |
| <div class="glass-card p-6 rounded-xl"> | |
| <div class="flex justify-between items-start mb-4"> | |
| <div class="flex items-center"> | |
| <img src="https://cryptologos.cc/logos/bitcoin-btc-logo.png" alt="BTC" class="w-8 h-8 mr-3"> | |
| <div> | |
| <h2 class="text-xl font-semibold">Bitcoin</h2> | |
| <div class="flex items-center"> | |
| <span id="btc-price" class="text-2xl font-bold">--</span> | |
| <span id="btc-change" class="ml-2 px-2 py-1 rounded text-xs"></span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="text-xs text-gray-400"> | |
| Dominance: <span id="btc-dominance" class="font-medium">--%</span> | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-3 gap-4"> | |
| <div> | |
| <div class="text-xs text-gray-400 mb-1">Funding Rate</div> | |
| <div id="btc-funding" class="text-lg font-medium">--%</div> | |
| </div> | |
| <div> | |
| <div class="text-xs text-gray-400 mb-1">Open Interest</div> | |
| <div id="btc-oi" class="text-lg font-medium">--</div> | |
| </div> | |
| <div> | |
| <div class="text-xs text-gray-400 mb-1">Liquidation</div> | |
| <div class="flex items-center"> | |
| <span id="btc-liquidations" class="text-lg font-medium">--</span> | |
| <span id="btc-liq-change" class="ml-1 text-xs"></span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="mt-4 h-20"> | |
| <canvas id="btc-chart"></canvas> | |
| </div> | |
| </div> | |
| <!-- ETH Card --> | |
| <div class="glass-card p-6 rounded-xl"> | |
| <div class="flex justify-between items-start mb-4"> | |
| <div class="flex items-center"> | |
| <img src="https://cryptologos.cc/logos/ethereum-eth-logo.png" alt="ETH" class="w-8 h-8 mr-3"> | |
| <div> | |
| <h2 class="text-xl font-semibold">Ethereum</h2> | |
| <div class="flex items-center"> | |
| <span id="eth-price" class="text-2xl font-bold">--</span> | |
| <span id="eth-change" class="ml-2 px-2 py-1 rounded text-xs"></span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="text-xs text-gray-400"> | |
| Dominance: <span id="eth-dominance" class="font-medium">--%</span> | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-3 gap-4"> | |
| <div> | |
| <div class="text-xs text-gray-400 mb-1">Funding Rate</div> | |
| <div id="eth-funding" class="text-lg font-medium">--%</div> | |
| </div> | |
| <div> | |
| <div class="text-xs text-gray-400 mb-1">Open Interest</div> | |
| <div id="eth-oi" class="text-lg font-medium">--</div> | |
| </div> | |
| <div> | |
| <div class="text-xs text-gray-400 mb-1">Liquidation</div> | |
| <div class="flex items-center"> | |
| <span id="eth-liquidations" class="text-lg font-medium">--</span> | |
| <span id="eth-liq-change" class="ml-1 text-xs"></span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="mt-4 h-20"> | |
| <canvas id="eth-chart"></canvas> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Gainers & Losers --> | |
| <div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8"> | |
| <!-- Top Gainers --> | |
| <div class="glass-card p-6 rounded-xl"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h2 class="text-xl font-semibold">Top Gainers</h2> | |
| <span class="px-2 py-1 rounded-full bg-opacity-20 bg-green-500 text-green-300 text-xs">24h</span> | |
| </div> | |
| <div id="gainers-list" class="space-y-3"> | |
| <div class="flex items-center justify-between p-3 rounded-lg bg-gray-800 bg-opacity-50 animate-pulse"> | |
| <div class="flex items-center"> | |
| <div class="w-8 h-8 rounded-full bg-gray-700 mr-3"></div> | |
| <div class="w-20 h-4 bg-gray-700 rounded"></div> | |
| </div> | |
| <div class="w-16 h-4 bg-gray-700 rounded"></div> | |
| </div> | |
| <div class="flex items-center justify-between p-3 rounded-lg bg-gray-800 bg-opacity-50 animate-pulse"> | |
| <div class="flex items-center"> | |
| <div class="w-8 h-8 rounded-full bg-gray-700 mr-3"></div> | |
| <div class="w-20 h-4 bg-gray-700 rounded"></div> | |
| </div> | |
| <div class="w-16 h-4 bg-gray-700 rounded"></div> | |
| </div> | |
| <div class="flex items-center justify-between p-3 rounded-lg bg-gray-800 bg-opacity-50 animate-pulse"> | |
| <div class="flex items-center"> | |
| <div class="w-8 h-8 rounded-full bg-gray-700 mr-3"></div> | |
| <div class="w-20 h-4 bg-gray-700 rounded"></div> | |
| </div> | |
| <div class="w-16 h-4 bg-gray-700 rounded"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Top Losers --> | |
| <div class="glass-card p-6 rounded-xl"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h2 class="text-xl font-semibold">Top Losers</h2> | |
| <span class="px-2 py-1 rounded-full bg-opacity-20 bg-red-500 text-red-300 text-xs">24h</span> | |
| </div> | |
| <div id="losers-list" class="space-y-3"> | |
| <div class="flex items-center justify-between p-3 rounded-lg bg-gray-800 bg-opacity-50 animate-pulse"> | |
| <div class="flex items-center"> | |
| <div class="w-8 h-8 rounded-full bg-gray-700 mr-3"></div> | |
| <div class="w-20 h-4 bg-gray-700 rounded"></div> | |
| </div> | |
| <div class="w-16 h-4 bg-gray-700 rounded"></div> | |
| </div> | |
| <div class="flex items-center justify-between p-3 rounded-lg bg-gray-800 bg-opacity-50 animate-pulse"> | |
| <div class="flex items-center"> | |
| <div class="w-8 h-8 rounded-full bg-gray-700 mr-3"></div> | |
| <div class="w-20 h-4 bg-gray-700 rounded"></div> | |
| </div> | |
| <div class="w-16 h-4 bg-gray-700 rounded"></div> | |
| </div> | |
| <div class="flex items-center justify-between p-3 rounded-lg bg-gray-800 bg-opacity-50 animate-pulse"> | |
| <div class="flex items-center"> | |
| <div class="w-8 h-8 rounded-full bg-gray-700 mr-3"></div> | |
| <div class="w-20 h-4 bg-gray-700 rounded"></div> | |
| </div> | |
| <div class="w-16 h-4 bg-gray-700 rounded"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Funding Rates & Open Interest --> | |
| <div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8"> | |
| <!-- Funding Rates --> | |
| <div class="glass-card p-6 rounded-xl"> | |
| <h2 class="text-xl font-semibold mb-4">Exchange Funding Rates</h2> | |
| <div class="h-64"> | |
| <canvas id="funding-chart"></canvas> | |
| </div> | |
| </div> | |
| <!-- Open Interest --> | |
| <div class="glass-card p-6 rounded-xl"> | |
| <h2 class="text-xl font-semibold mb-4">Open Interest</h2> | |
| <div class="h-64"> | |
| <canvas id="oi-chart"></canvas> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Liquidation Heatmap --> | |
| <div class="glass-card p-6 rounded-xl mb-8"> | |
| <h2 class="text-xl font-semibold mb-4">Liquidation Heatmap</h2> | |
| <div class="h-80"> | |
| <canvas id="liquidation-chart"></canvas> | |
| </div> | |
| </div> | |
| <!-- Footer --> | |
| <footer class="text-center text-gray-500 text-sm py-6"> | |
| <div class="flex justify-center space-x-4 mb-2"> | |
| <a href="#" class="hover:text-primary transition"><i data-feather="github"></i></a> | |
| <a href="#" class="hover:text-primary transition"><i data-feather="twitter"></i></a> | |
| <a href="#" class="hover:text-primary transition"><i data-feather="discord"></i></a> | |
| </div> | |
| <p>CryptoPulse Navigator - Real-time Crypto Market Intelligence</p> | |
| <p class="text-xs mt-1">Data sourced from CoinGlass | Updates every 5 minutes</p> | |
| </footer> | |
| </div> | |
| <script> | |
| // Global config with direct API endpoints | |
| const CONFIG = { | |
| refreshInterval: 60 * 1000, // 1 minute | |
| apiEndpoints: { | |
| binance: { | |
| price: 'https://api.binance.com/api/v3/ticker/24hr', | |
| klines: 'https://api.binance.com/api/v3/klines', | |
| funding: 'https://fapi.binance.com/fapi/v1/premiumIndex' | |
| }, | |
| coinGlass: { | |
| openInterest: 'https://open-api.coinglass.com/api/pro/v1/futures/openInterest', | |
| liquidation: 'https://open-api.coinglass.com/api/pro/v1/futures/liquidation', | |
| fundingRates: 'https://open-api.coinglass.com/api/pro/v1/funding_rate', | |
| longShort: 'https://open-api.coinglass.com/api/pro/v1/futures/longShort', | |
| fearGreed: 'https://open-api.coinglass.com/api/pro/v1/fear_greed' | |
| } | |
| }, | |
| coinGlassKey: 'YOUR_COINGLASS_API_KEY' // Replace with actual key | |
| }; | |
| // Initialize Vanta.js background | |
| VANTA.NET({ | |
| el: "#vanta-bg", | |
| mouseControls: true, | |
| touchControls: true, | |
| gyroControls: false, | |
| minHeight: 200.00, | |
| minWidth: 200.00, | |
| scale: 1.00, | |
| scaleMobile: 1.00, | |
| color: 0x6366f1, | |
| backgroundColor: 0x0f172a, | |
| points: 12.00, | |
| maxDistance: 22.00, | |
| spacing: 18.00 | |
| }); | |
| // Initialize charts | |
| const phiCtx = document.getElementById('phi-gauge').getContext('2d'); | |
| const phiGauge = new Chart(phiCtx, { | |
| type: 'doughnut', | |
| data: { | |
| datasets: [{ | |
| data: [0, 100], | |
| backgroundColor: ['#6366f1', 'rgba(30, 41, 59, 0.5)'], | |
| borderWidth: 0 | |
| }] | |
| }, | |
| options: { | |
| cutout: '85%', | |
| rotation: -90, | |
| circumference: 180, | |
| responsive: false, | |
| plugins: { | |
| legend: { display: false }, | |
| tooltip: { enabled: false } | |
| } | |
| } | |
| }); | |
| // Initialize other charts | |
| const btcChart = new Chart(document.getElementById('btc-chart'), { | |
| type: 'line', | |
| data: { | |
| labels: Array(24).fill(''), | |
| datasets: [{ | |
| data: Array(24).fill(0), | |
| borderColor: '#f59e0b', | |
| borderWidth: 2, | |
| tension: 0.3, | |
| fill: true, | |
| backgroundColor: 'rgba(245, 158, 11, 0.1)', | |
| pointRadius: 0 | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| plugins: { legend: { display: false } }, | |
| scales: { | |
| x: { display: false }, | |
| y: { display: false } | |
| } | |
| } | |
| }); | |
| const ethChart = new Chart(document.getElementById('eth-chart'), { | |
| type: 'line', | |
| data: { | |
| labels: Array(24).fill(''), | |
| datasets: [{ | |
| data: Array(24).fill(0), | |
| borderColor: '#8b5cf6', | |
| borderWidth: 2, | |
| tension: 0.3, | |
| fill: true, | |
| backgroundColor: 'rgba(139, 92, 246, 0.1)', | |
| pointRadius: 0 | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| plugins: { legend: { display: false } }, | |
| scales: { | |
| x: { display: false }, | |
| y: { display: false } | |
| } | |
| } | |
| }); | |
| const fundingChart = new Chart(document.getElementById('funding-chart'), { | |
| type: 'bar', | |
| data: { | |
| labels: ['Binance', 'OKX', 'Bybit', 'Deribit', 'Bitget'], | |
| datasets: [{ | |
| label: 'Funding Rate', | |
| data: [0.01, 0.005, 0.007, -0.002, 0.003], | |
| backgroundColor: [ | |
| 'rgba(99, 102, 241, 0.7)', | |
| 'rgba(99, 102, 241, 0.7)', | |
| 'rgba(99, 102, 241, 0.7)', | |
| 'rgba(99, 102, 241, 0.7)', | |
| 'rgba(99, 102, 241, 0.7)' | |
| ], | |
| borderColor: [ | |
| 'rgba(99, 102, 241, 1)', | |
| 'rgba(99, 102, 241, 1)', | |
| 'rgba(99, 102, 241, 1)', | |
| 'rgba(99, 102, 241, 1)', | |
| 'rgba(99, 102, 241, 1)' | |
| ], | |
| borderWidth: 1 | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| plugins: { | |
| legend: { display: false }, | |
| tooltip: { | |
| callbacks: { | |
| label: function(context) { | |
| return (context.raw * 100).toFixed(4) + '%'; | |
| } | |
| } | |
| } | |
| }, | |
| scales: { | |
| y: { | |
| beginAtZero: true, | |
| ticks: { | |
| callback: function(value) { | |
| return (value * 100).toFixed(2) + '%'; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| const oiChart = new Chart(document.getElementById('oi-chart'), { | |
| type: 'line', | |
| data: { | |
| labels: ['6h ago', '5h ago', '4h ago', '3h ago', '2h ago', '1h ago', 'Now'], | |
| datasets: [ | |
| { | |
| label: 'BTC', | |
| data: [12000, 12500, 12300, 12800, 12700, 13000, 13200], | |
| borderColor: '#f59e0b', | |
| backgroundColor: 'rgba(245, 158, 11, 0.1)', | |
| tension: 0.3, | |
| fill: true | |
| }, | |
| { | |
| label: 'ETH', | |
| data: [8000, 8200, 8100, 8300, 8250, 8400, 8500], | |
| borderColor: '#8b5cf6', | |
| backgroundColor: 'rgba(139, 92, 246, 0.1)', | |
| tension: 0.3, | |
| fill: true | |
| } | |
| ] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| plugins: { | |
| tooltip: { | |
| callbacks: { | |
| label: function(context) { | |
| return context.dataset.label + ': $' + context.raw.toLocaleString(); | |
| } | |
| } | |
| } | |
| }, | |
| scales: { | |
| y: { | |
| ticks: { | |
| callback: function(value) { | |
| return '$' + (value / 1000) + 'B'; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| const liquidationChart = new Chart(document.getElementById('liquidation-chart'), { | |
| type: 'bar', | |
| data: { | |
| labels: ['BTC', 'ETH', 'SOL', 'XRP', 'ADA', 'DOT', 'DOGE', 'MATIC'], | |
| datasets: [ | |
| { | |
| label: 'Long', | |
| data: [12000000, 8500000, 3200000, 1800000, 1500000, 1200000, 900000, 800000], | |
| backgroundColor: 'rgba(16, 185, 129, 0.7)', | |
| borderColor: 'rgba(16, 185, 129, 1)', | |
| borderWidth: 1 | |
| }, | |
| { | |
| label: 'Short', | |
| data: [9500000, 7200000, 2800000, 1500000, 1200000, 900000, 700000, 600000], | |
| backgroundColor: 'rgba(239, 68, 68, 0.7)', | |
| borderColor: 'rgba(239, 68, 68, 1)', | |
| borderWidth: 1 | |
| } | |
| ] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| plugins: { | |
| tooltip: { | |
| callbacks: { | |
| label: function(context) { | |
| return context.dataset.label + ': $' + (context.raw / 1000000).toFixed(2) + 'M'; | |
| } | |
| } | |
| } | |
| }, | |
| scales: { | |
| x: { stacked: true }, | |
| y: { | |
| stacked: true, | |
| ticks: { | |
| callback: function(value) { | |
| return '$' + (value / 1000000) + 'M'; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| // Fetch live data from Binance and CoinGlass APIs | |
| async function fetchData() { | |
| try { | |
| document.getElementById('status-badge').className = 'px-3 py-1 rounded-full bg-opacity-20 bg-yellow-500 text-yellow-300 flex items-center'; | |
| document.querySelector('#status-badge span:last-child').textContent = 'Updating'; | |
| // Binance API requests | |
| const [binancePrices, btcFunding, ethFunding] = await Promise.all([ | |
| axios.get(`${CONFIG.apiEndpoints.binance.price}?symbols=["BTCUSDT","ETHUSDT"]`), | |
| axios.get(`${CONFIG.apiEndpoints.binance.funding}?symbol=BTCUSDT`), | |
| axios.get(`${CONFIG.apiEndpoints.binance.funding}?symbol=ETHUSDT`) | |
| ]); | |
| // CoinGlass API requests with headers | |
| const coinGlassHeaders = { | |
| 'coinglassSecret': CONFIG.coinGlassKey | |
| }; | |
| const [openInterest, liquidations, fundingRates, longShort, fearGreed] = await Promise.all([ | |
| axios.get(CONFIG.apiEndpoints.coinGlass.openInterest, { headers: coinGlassHeaders }), | |
| axios.get(CONFIG.apiEndpoints.coinGlass.liquidation, { headers: coinGlassHeaders }), | |
| axios.get(CONFIG.apiEndpoints.coinGlass.fundingRates, { headers: coinGlassHeaders }), | |
| axios.get(CONFIG.apiEndpoints.coinGlass.longShort, { headers: coinGlassHeaders }), | |
| axios.get(CONFIG.apiEndpoints.coinGlass.fearGreed, { headers: coinGlassHeaders }) | |
| ]); | |
| // Process Binance data | |
| const btcData = binancePrices.data.find(p => p.symbol === 'BTCUSDT'); | |
| const ethData = binancePrices.data.find(p => p.symbol === 'ETHUSDT'); | |
| // Transform data into our format | |
| const transformedData = { | |
| btc: { | |
| price: parseFloat(btcData.lastPrice), | |
| change_24h: parseFloat(btcData.priceChangePercent), | |
| funding_rate: parseFloat(btcFunding.data.lastFundingRate) * 100, | |
| open_interest: openInterest.data.data.btc.sumOpenInterest, | |
| liquidations: liquidations.data.data.btc.sumLiquidation | |
| }, | |
| eth: { | |
| price: parseFloat(ethData.lastPrice), | |
| change_24h: parseFloat(ethData.priceChangePercent), | |
| funding_rate: parseFloat(ethFunding.data.lastFundingRate) * 100, | |
| open_interest: openInterest.data.data.eth.sumOpenInterest, | |
| liquidations: liquidations.data.data.eth.sumLiquidation | |
| }, | |
| phi_score: calculatePHIScore(longShort.data.data), // Calculated score | |
| volx: parseFloat(fearGreed.data.data.volatility), | |
| momx: parseFloat(fearGreed.data.data.momentum), | |
| fbs: parseFloat(fundingRates.data.data.averageRate), | |
| lpi: parseFloat(longShort.data.data.longShortRate), | |
| long_short_ratio: parseFloat(longShort.data.data.longShortRate), | |
| fear_greed: { | |
| value: parseFloat(fearGreed.data.data.value), | |
| label: fearGreed.data.data.valueClass | |
| }, | |
| funding_rates: fundingRates.data.data.rateList, | |
| open_interest_history: openInterest.data.data.historyList, | |
| liquidations_history: liquidations.data.data.historyList | |
| }; | |
| // Helper function to calculate PHI score | |
| function calculatePHIScore(longShortData) { | |
| // Weighted average of multiple factors | |
| const volScore = (parseFloat(longShortData.volatility) / 100) * 30; | |
| const momScore = (parseFloat(longShortData.momentum) + 1) * 25; | |
| const lsScore = (parseFloat(longShortData.longShortRate) - 1) * 15; | |
| const fgScore = (parseFloat(fearGreed.data.data.value) / 100) * 30; | |
| return Math.min(100, Math.max(0, | |
| volScore + momScore + lsScore + fgScore | |
| )).toFixed(1); | |
| } | |
| updateDashboard(transformedData); | |
| document.getElementById('status-badge').className = 'px-3 py-1 rounded-full bg-opacity-20 bg-green-500 text-green-300 flex items-center'; | |
| document.querySelector('#status-badge span:last-child').textContent = 'Live'; | |
| document.getElementById('last-updated').innerHTML = `<i data-feather="clock" class="w-4 h-4 inline mr-1"></i> ${new Date().toLocaleTimeString()}`; | |
| } catch (error) { | |
| console.error('Error fetching data:', error); | |
| document.getElementById('status-badge').className = 'px-3 py-1 rounded-full bg-opacity-20 bg-red-500 text-red-300 flex items-center'; | |
| document.querySelector('#status-badge span:last-child').textContent = 'Offline'; | |
| // Try again in 30 seconds if failed | |
| setTimeout(fetchData, 30000); | |
| } | |
| } | |
| // Update dashboard with real data | |
| function updateDashboard(data) { | |
| // Update timestamp first | |
| document.getElementById('last-updated').innerHTML = | |
| `<i data-feather="clock" class="w-4 h-4 inline mr-1"></i> ${new Date().toLocaleTimeString()}`; | |
| // PHI Score and Metrics | |
| const phiScore = data.phi_score || 50; | |
| document.getElementById('phi-score').textContent = phiScore.toFixed(1); | |
| // Update gauge chart | |
| phiGauge.data.datasets[0].data = [phiScore, 100 - phiScore]; | |
| phiGauge.update(); | |
| // Update metric bars | |
| document.getElementById('volx-value').textContent = data.volx ? data.volx.toFixed(1) : '--'; | |
| document.getElementById('momx-value').textContent = data.momx ? (data.momx * 100).toFixed(2) + '%' : '--'; | |
| document.getElementById('fbs-value').textContent = data.fbs ? (data.fbs * 100).toFixed(4) + '%' : '--'; | |
| document.getElementById('lpi-value').textContent = data.lpi ? data.lpi.toFixed(1) : '--'; | |
| document.getElementById('volx-bar').style.width = `${data.volx || 0}%`; | |
| document.getElementById('momx-bar').style.width = `${(data.momx || 0) * 100}%`; | |
| document.getElementById('fbs-bar').style.width = `${(data.fbs || 0) * 100}%`; | |
| document.getElementById('lpi-bar').style.width = `${data.lpi || 0}%`; | |
| // Update market phase | |
| let phase = 'Neutral'; | |
| let phaseColor = 'gray'; | |
| if (phiScore < 30) { | |
| phase = 'Compression'; | |
| phaseColor = 'purple'; | |
| } else if (phiScore < 50) { | |
| phase = 'Recovery'; | |
| phaseColor = 'blue'; | |
| } else if (phiScore < 70) { | |
| phase = 'Expansion'; | |
| phaseColor = 'green'; | |
| } else { | |
| phase = 'Exhaustion'; | |
| phaseColor = 'red'; | |
| } | |
| const phaseBadge = document.getElementById('phase-badge'); | |
| phaseBadge.textContent = phase; | |
| phaseBadge.className = `px-3 py-1 rounded-full bg-opacity-20 bg-${phaseColor}-500 text-${phaseColor}-300 phase-badge`; | |
| // Update phase description | |
| const descriptions = { | |
| 'Compression': 'Market is in a compression phase with low volatility. Traders are cautious, awaiting a breakout.', | |
| 'Recovery': 'Market is recovering from recent moves. Volatility is increasing as traders reposition.', | |
| 'Expansion': 'Market is in expansion with strong momentum. Trending conditions likely to continue.', | |
| 'Exhaustion': 'Market shows signs of exhaustion after strong moves. Potential reversal or consolidation ahead.', | |
| 'Neutral': 'Market is in neutral territory without clear direction. Watch for breakout signals.' | |
| }; | |
| document.getElementById('phase-description').textContent = descriptions[phase] || descriptions['Neutral']; | |
| // Update risk level | |
| let riskLevel = 'Medium'; | |
| let riskColor = 'yellow'; | |
| if (phiScore < 20 || phiScore > 80) { | |
| riskLevel = 'Extreme'; | |
| riskColor = 'red'; | |
| } else if (phiScore < 40 || phiScore > 60) { | |
| riskLevel = 'High'; | |
| riskColor = 'orange'; | |
| } else { | |
| riskLevel = 'Medium'; | |
| riskColor = 'yellow'; | |
| } | |
| document.getElementById('risk-level').innerHTML = `<span class="px-2 py-1 rounded bg-opacity-20 bg-${riskColor}-500 text-${riskColor}-300">${riskLevel} Risk</span>`; | |
| // Update BTC/ETH data | |
| if (data.btc) { | |
| document.getElementById('btc-price').textContent = `$${data.btc.price.toLocaleString()}`; | |
| const btcChange = data.btc.change_24h; | |
| const btcChangeEl = document.getElementById('btc-change'); | |
| btcChangeEl.textContent = `${btcChange > 0 ? '+' : ''}${btcChange.toFixed(2)}%`; | |
| btcChangeEl.className = `ml-2 px-2 py-1 rounded text-xs ${btcChange >= 0 ? 'bg-green-500 bg-opacity-20 text-green-300' : 'bg-red-500 bg-opacity-20 text-red-300'}`; | |
| document.getElementById('btc-dominance').textContent = data.btc.dominance.toFixed(1) + '%'; | |
| document.getElementById('btc-funding').textContent = (data.btc.funding_rate * 100).toFixed(4) + '%'; | |
| document.getElementById('btc-oi').textContent = `$${(data.btc.open_interest / 1000000000).toFixed(2)}B`; | |
| document.getElementById('btc-liquidations').textContent = `$${(data.btc.liquidations / 1000000).toFixed(2)}M`; | |
| // Update BTC chart | |
| btcChart.data.datasets[0].data = data.btc.price_history || Array(24).fill(0); | |
| btcChart.update(); | |
| } | |
| if (data.eth) { | |
| document.getElementById('eth-price').textContent = `$${data.eth.price.toLocaleString()}`; | |
| const ethChange = data.eth.change_24h; | |
| const ethChangeEl = document.getElementById('eth-change'); | |
| ethChangeEl.textContent = `${ethChange > 0 ? '+' : ''}${ethChange.toFixed(2)}%`; | |
| ethChangeEl.className = `ml-2 px-2 py-1 rounded text-xs ${ethChange >= 0 ? 'bg-green-500 bg-opacity-20 text-green-300' : 'bg-red-500 bg-opacity-20 text-red-300'}`; | |
| document.getElementById('eth-dominance').textContent = data.eth.dominance.toFixed(1) + '%'; | |
| document.getElementById('eth-funding').textContent = (data.eth.funding_rate * 100).toFixed(4) + '%'; | |
| document.getElementById('eth-oi').textContent = `$${(data.eth.open_interest / 1000000000).toFixed(2)}B`; | |
| document.getElementById('eth-liquidations').textContent = `$${(data.eth.liquidations / 1000000).toFixed(2)}M`; | |
| // Update ETH chart | |
| ethChart.data.datasets[0].data = data.eth.price_history || Array(24).fill(0); | |
| ethChart.update(); | |
| } | |
| // Update long/short ratio | |
| if (data.long_short_ratio) { | |
| const ratio = data.long_short_ratio; | |
| document.getElementById('ls-ratio-value').textContent = ratio.toFixed(2); | |
| document.getElementById('long-bar').style.width = `${(ratio / (ratio + 1)) * 100}%`; | |
| document.getElementById('short-bar').style.width = `${(1 / (ratio + 1)) * 100}%`; | |
| } | |
| // Update fear & greed index | |
| if (data.fear_greed) { | |
| const fg = data.fear_greed; | |
| document.getElementById('fear-greed-value').textContent = `${fg.value} (${fg.label})`; | |
| document.getElementById('fear-greed-bar').style.width = `${fg.value}%`; | |
| } | |
| // Update top gainers/losers | |
| if (data.top_gainers) { | |
| const gainersList = document.getElementById('gainers-list'); | |
| gainersList.innerHTML = ''; | |
| data.top_gainers.slice(0, 5).forEach(gainer => { | |
| const gainerEl = document.createElement('div'); | |
| gainerEl.className = 'flex items-center justify-between p-3 rounded-lg hover:bg-gray-800 transition'; | |
| gainerEl.innerHTML = ` | |
| <div class="flex items-center"> | |
| <div class="w-8 h-8 rounded-full bg-gray-700 mr-3 flex items-center justify-center text-xs font-bold"> | |
| ${gainer.symbol.substring(0, 3)} | |
| </div> | |
| <div> | |
| <div class="font-medium">${gainer.symbol}</div> | |
| <div class="text-xs text-gray-400">$${(gainer.price / 1000).toFixed(3)}K</div> | |
| </div> | |
| </div> | |
| <div class="px-3 py-1 rounded-full bg-opacity-20 bg-green-500 text-green-300 text-sm"> | |
| +${gainer.change.toFixed(2)}% | |
| </div> | |
| `; | |
| gainersList.appendChild(gainerEl); | |
| }); | |
| } | |
| if (data.top_losers) { | |
| const losersList = document.getElementById('losers-list'); | |
| losersList.innerHTML = ''; | |
| data.top_losers.slice(0, 5).forEach(loser => { | |
| const loserEl = document.createElement('div'); | |
| loserEl.className = 'flex items-center justify-between p-3 rounded-lg hover:bg-gray-800 transition'; | |
| loserEl.innerHTML = ` | |
| <div class="flex items-center"> | |
| <div class="w-8 h-8 rounded-full bg-gray-700 mr-3 flex items-center justify-center text-xs font-bold"> | |
| ${loser.symbol.substring(0, 3)} | |
| </div> | |
| <div> | |
| <div class="font-medium">${loser.symbol}</div> | |
| <div class="text-xs text-gray-400">$${(loser.price / 1000).toFixed(3)}K</div> | |
| </div> | |
| </div> | |
| <div class="px-3 py-1 rounded-full bg-opacity-20 bg-red-500 text-red-300 text-sm"> | |
| ${loser.change.toFixed(2)}% | |
| </div> | |
| `; | |
| losersList.appendChild(loserEl); | |
| }); | |
| } | |
| // Update funding rates chart | |
| if (data.funding_rates) { | |
| fundingChart.data.datasets[0].data = Object.values(data.funding_rates); | |
| fundingChart.update(); | |
| } | |
| // Update open interest chart | |
| if (data.open_interest) { | |
| oiChart.data.datasets[0].data = data.open_interest.btc_history; | |
| oiChart.data.datasets[1].data = data.open_interest.eth_history; | |
| oiChart.update(); | |
| } | |
| // Update liquidation chart | |
| if (data.liquidations) { | |
| liquidationChart.data.datasets[0].data = data.liquidations.longs; | |
| liquidationChart.data.datasets[1].data = data.liquidations.shorts; | |
| liquidationChart.update(); | |
| } | |
| } | |
| // Refresh button | |
| document.getElementById('refresh-btn').addEventListener('click', fetchData); | |
| // Initial load with error handling | |
| document.addEventListener('DOMContentLoaded', () => { | |
| feather.replace(); | |
| // Add CORS proxy header if needed | |
| axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; | |
| // First try with proxy | |
| fetchData(); | |
| // Auto-refresh every minute | |
| setInterval(fetchData, CONFIG.refreshInterval); | |
| // Fallback: if CORS proxy fails, try direct with JSONP | |
| window.jsonpCallback = function(data) { | |
| console.log('JSONP fallback data:', data); | |
| // Transform and use data as needed | |
| }; | |
| }); | |
| // Fallback JSONP function | |
| function loadJSONP(url) { | |
| const script = document.createElement('script'); | |
| script.src = url; | |
| document.head.appendChild(script); | |
| } | |
| </script> | |
| </body> | |
| </html> | |