Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Scalp Trading Dashboard | CryptoSignal Sleuth Pro</title> | |
| <link rel="stylesheet" href="style.css"> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://unpkg.com/feather-icons"></script> | |
| </head> | |
| <body class="bg-gray-900 text-gray-100"> | |
| <custom-navbar></custom-navbar> | |
| <div class="container mx-auto px-4 py-6"> | |
| <!-- Header --> | |
| <div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4 mb-6"> | |
| <div> | |
| <h1 class="text-2xl font-bold">Scalp Trading Dashboard</h1> | |
| <p class="text-gray-400">Live multi-pair signals for crypto & forex</p> | |
| </div> | |
| <div class="flex flex-wrap gap-2 items-center"> | |
| <!-- Timeframe tabs --> | |
| <div class="flex bg-gray-800 rounded-lg p-1"> | |
| <button class="timeframe-tab active" data-timeframe="1m">1m</button> | |
| <button class="timeframe-tab" data-timeframe="5m">5m</button> | |
| <button class="timeframe-tab" data-timeframe="15m">15m</button> | |
| <button class="timeframe-tab" data-timeframe="1h">1h</button> | |
| </div> | |
| <!-- Asset type --> | |
| <select id="asset-type" class="bg-gray-800 text-sm rounded-lg px-3 py-1.5 border border-gray-700"> | |
| <option value="forex">Forex</option> | |
| <option value="crypto">Crypto</option> | |
| <option value="mixed">Mixed</option> | |
| </select> | |
| <!-- Search --> | |
| <input type="text" id="pair-search" placeholder="Search pair" | |
| class="bg-gray-800 text-sm rounded-lg px-3 py-1.5 border border-gray-700 w-40"> | |
| <button id="refresh-btn" class="px-4 py-1.5 rounded-lg text-sm bg-indigo-600 hover:bg-indigo-500"> | |
| <i data-feather="refresh-cw" class="w-4 h-4"></i> Refresh | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Signals Table --> | |
| <div class="rounded-xl overflow-hidden border border-gray-800"> | |
| <table class="w-full text-sm"> | |
| <thead class="bg-gray-800"> | |
| <tr class="text-gray-400 text-xs uppercase"> | |
| <th class="px-4 py-3 text-left">Pair</th> | |
| <th class="px-4 py-3 text-left">Type</th> | |
| <th class="px-4 py-3 text-left">TF</th> | |
| <th class="px-4 py-3 text-left">Bias</th> | |
| <th class="px-4 py-3 text-left">Entry Zone</th> | |
| <th class="px-4 py-3 text-left">SL</th> | |
| <th class="px-4 py-3 text-left">TP1 / TP2</th> | |
| <th class="px-4 py-3 text-left">Confidence</th> | |
| <th class="px-4 py-3 text-left">Updated</th> | |
| <th class="px-4 py-3 text-right">Action</th> | |
| </tr> | |
| </thead> | |
| <tbody id="signals-body" class="divide-y divide-gray-800"> | |
| <!-- Signals will be loaded here --> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| <script src="components/navbar.js"></script> | |
| <script src="script.js"></script> | |
| <script> | |
| feather.replace(); | |
| // Timeframe tabs | |
| document.querySelectorAll('.timeframe-tab').forEach(tab => { | |
| tab.addEventListener('click', () => { | |
| document.querySelectorAll('.timeframe-tab').forEach(t => t.classList.remove('active')); | |
| tab.classList.add('active'); | |
| loadSignals(); | |
| }); | |
| }); | |
| // Asset type and search | |
| document.getElementById('asset-type').addEventListener('change', loadSignals); | |
| document.getElementById('pair-search').addEventListener('input', filterSignals); | |
| document.getElementById('refresh-btn').addEventListener('click', loadSignals); | |
| async function loadSignals() { | |
| const timeframe = document.querySelector('.timeframe-tab.active').dataset.timeframe; | |
| const assetType = document.getElementById('asset-type').value; | |
| try { | |
| const response = await fetch('/api/scalp/signals', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ timeframe, asset_type: assetType }) | |
| }); | |
| const data = await response.json(); | |
| renderSignals(data.signals); | |
| } catch (error) { | |
| console.error('Error loading signals:', error); | |
| } | |
| } | |
| function renderSignals(signals) { | |
| const tbody = document.getElementById('signals-body'); | |
| tbody.innerHTML = ''; | |
| signals.forEach(signal => { | |
| const row = document.createElement('tr'); | |
| row.className = 'hover:bg-gray-800/50'; | |
| const directionClass = signal.direction === 'long' ? | |
| 'bg-emerald-500/20 text-emerald-300 border-emerald-500/40' : | |
| signal.direction === 'short' ? | |
| 'bg-rose-500/20 text-rose-300 border-rose-500/40' : | |
| 'bg-gray-500/20 text-gray-300 border-gray-500/40'; | |
| row.innerHTML = ` | |
| <td class="px-4 py-3 font-medium">${signal.symbol}</td> | |
| <td class="px-4 py-3 text-xs">${signal.asset_type.toUpperCase()}</td> | |
| <td class="px-4 py-3 text-xs">${signal.timeframe}</td> | |
| <td class="px-4 py-3"> | |
| <span class="px-2 py-1 text-xs rounded-full font-semibold uppercase border ${directionClass}"> | |
| ${signal.direction.toUpperCase()} | |
| </span> | |
| </td> | |
| <td class="px-4 py-3 text-xs"> | |
| ${signal.entry_zone[0].toFixed(5)} - ${signal.entry_zone[1].toFixed(5)} | |
| </td> | |
| <td class="px-4 py-3 text-xs">${signal.stop_loss.toFixed(5)}</td> | |
| <td class="px-4 py-3 text-xs"> | |
| ${signal.take_profit_levels[0].toFixed(5)} / ${signal.take_profit_levels[1].toFixed(5)} | |
| </td> | |
| <td class="px-4 py-3"> | |
| <div class="flex items-center gap-2"> | |
| <div class="h-1.5 w-16 bg-gray-700 rounded-full overflow-hidden"> | |
| <div class="h-full bg-emerald-500" style="width: ${signal.confidence}%"></div> | |
| </div> | |
| <span class="text-xs">${signal.confidence}%</span> | |
| </div> | |
| </td> | |
| <td class="px-4 py-3 text-xs text-gray-400"> | |
| ${new Date(signal.updated_at).toLocaleTimeString()} | |
| </td> | |
| <td class="px-4 py-3 text-right"> | |
| <button class="text-xs px-3 py-1 rounded-lg bg-gray-700 hover:bg-gray-600"> | |
| View Plan | |
| </button> | |
| </td> | |
| `; | |
| tbody.appendChild(row); | |
| }); | |
| } | |
| function filterSignals() { | |
| const search = document.getElementById('pair-search').value.toLowerCase(); | |
| const rows = document.querySelectorAll('#signals-body tr'); | |
| rows.forEach(row => { | |
| const pair = row.querySelector('td:first-child').textContent.toLowerCase(); | |
| row.style.display = pair.includes(search) ? '' : 'none'; | |
| }); | |
| } | |
| // Load initial signals | |
| loadSignals(); | |
| </script> | |
| </body> | |
| </html> |