Spaces:
Running
Running
| <html lang="id"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Aplikasi Database Trading Pro Indonesia</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/technicalindicators@3.1.0/dist/browser.js"></script> | |
| <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet"> | |
| <script> | |
| tailwind.config = { | |
| theme: { | |
| extend: { | |
| colors: { | |
| primary: '#0d47a1', | |
| secondary: '#1565c0', | |
| accent: '#1e88e5', | |
| success: '#4caf50', | |
| warning: '#ff9800', | |
| danger: '#d32f2f', | |
| } | |
| } | |
| } | |
| } | |
| </script> | |
| <style> | |
| /* Custom Styles */ | |
| .chart-container { | |
| height: 400px; | |
| position: relative; | |
| } | |
| .fade-in { | |
| animation: fadeIn 0.5s ease-in; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; } | |
| to { opacity: 1; } | |
| } | |
| ::-webkit-scrollbar { width: 8px; height: 8px; } | |
| ::-webkit-scrollbar-track { background: #f1f1f1; border-radius: 10px; } | |
| ::-webkit-scrollbar-thumb { background: #888; border-radius: 10px; } | |
| ::-webkit-scrollbar-thumb:hover { background: #555; } | |
| .card-hover { | |
| transition: all 0.3s ease; | |
| } | |
| .card-hover:hover { | |
| transform: translateY(-5px); | |
| box-shadow: 0 10px 20px rgba(0,0,0,0.1); | |
| } | |
| .loading { | |
| display: inline-block; | |
| width: 20px; | |
| height: 20px; | |
| border: 3px solid rgba(255,255,255,.3); | |
| border-radius: 50%; | |
| border-top-color: #fff; | |
| animation: spin 1s ease-in-out infinite; | |
| } | |
| @keyframes spin { | |
| to { transform: rotate(360deg); } | |
| } | |
| .data-table { | |
| border-collapse: collapse; | |
| width: 100%; | |
| } | |
| .data-table th, .data-table td { | |
| padding: 12px 15px; | |
| text-align: left; | |
| border-bottom: 1px solid #ddd; | |
| font-size: 14px; | |
| } | |
| .data-table th { | |
| background-color: #f8f9fa; | |
| font-weight: 600; | |
| color: #495057; | |
| text-transform: uppercase; | |
| letter-spacing: 0.05em; | |
| font-size: 12px; | |
| } | |
| .data-table tbody tr:hover { | |
| background-color: #f8f9fa; | |
| transition: background-color 0.2s ease; | |
| } | |
| .positive { color: #4caf50; font-weight: 500; } | |
| .negative { color: #f44336; font-weight: 500; } | |
| .momentum-beli { | |
| background-color: rgba(76, 175, 80, 0.1); | |
| color: #4caf50; | |
| padding: 4px 8px; | |
| border-radius: 4px; | |
| font-size: 12px; | |
| font-weight: 600; | |
| } | |
| .momentum-jual { | |
| background-color: rgba(211, 47, 47, 0.1); | |
| color: #d32f2f; | |
| padding: 4px 8px; | |
| border-radius: 4px; | |
| font-size: 12px; | |
| font-weight: 600; | |
| } | |
| .momentum-netral { | |
| background-color: rgba(255, 152, 0, 0.1); | |
| color: #ff9800; | |
| padding: 4px 8px; | |
| border-radius: 4px; | |
| font-size: 12px; | |
| font-weight: 600; | |
| } | |
| .chartjs-tooltip { | |
| background: rgba(0, 0, 0, 0.8) ; | |
| border: none ; | |
| border-radius: 8px ; | |
| color: white ; | |
| font-size: 14px ; | |
| pointer-events: none; | |
| } | |
| /* Force light theme */ | |
| @media (prefers-color-scheme: dark) { | |
| body { | |
| background-color: #f9fafb ; | |
| } | |
| .bg-white { | |
| background-color: #ffffff ; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-50 font-sans"> | |
| <div class="container mx-auto px-4 py-8"> | |
| <div class="text-center mb-8 fade-in"> | |
| <h1 class="text-4xl font-bold text-primary mb-2">Aplikasi Database Trading Pro Indonesia</h1> | |
| <p class="text-gray-600 text-lg">Analisis mendalam saham Indonesia berdasarkan data teknikal, fundamental, dan momentum institusi</p> | |
| </div> | |
| <div class="bg-white rounded-xl shadow-lg p-6 mb-8 card-hover"> | |
| <div class="flex flex-col md:flex-row gap-4 items-center"> | |
| <div class="flex-1"> | |
| <label for="symbol" class="block text-sm font-medium text-gray-700 mb-2">Kode Saham (IDX)</label> | |
| <div class="relative"> | |
| <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> | |
| <i class="fas fa-building text-gray-400"></i> | |
| </div> | |
| <input | |
| type="text" | |
| id="symbol" | |
| value="BBCA" | |
| placeholder="Contoh: BBCA, TLKM, BBRI" | |
| class="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-accent focus:border-transparent" | |
| maxlength="4" | |
| oninput="this.value = this.value.toUpperCase()" | |
| > | |
| </div> | |
| <p class="text-xs text-gray-500 mt-1">Tidak perlu menambahkan .JK</p> | |
| </div> | |
| <button | |
| onclick="loadData()" | |
| class="bg-primary hover:bg-secondary text-white px-6 py-3 rounded-lg font-medium transition-all duration-200 flex items-center gap-2 shadow-md hover:shadow-lg" | |
| > | |
| <span>Muat Ulang Data</span> | |
| </button> | |
| </div> | |
| </div> | |
| <div id="loading" class="flex flex-col items-center justify-center py-12"> | |
| <div class="loading"></div> | |
| <p class="text-gray-600 mt-4 text-lg">Mengambil data terkini dari Google Finance API...</p> | |
| </div> | |
| <div id="main-content" class="hidden"> | |
| <div class="bg-white rounded-xl shadow-lg p-6 mb-8 card-hover"> | |
| <h3 class="text-xl font-bold text-primary mb-4 flex items-center"> | |
| <i class="fas fa-chart-pie mr-2"></i> | |
| Data Fundamental | |
| </h3> | |
| <div id="fundamental-info" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4"> | |
| <div class="bg-blue-50 p-4 rounded-lg"> | |
| <div class="text-sm text-gray-600">EPS</div> | |
| <div class="text-2xl font-bold text-blue-700" id="eps">-</div> | |
| </div> | |
| <div class="bg-green-50 p-4 rounded-lg"> | |
| <div class="text-sm text-gray-600">ROE</div> | |
| <div class="text-2xl font-bold text-green-700" id="roe">-</div> | |
| </div> | |
| <div class="bg-purple-50 p-4 rounded-lg"> | |
| <div class="text-sm text-gray-600">P/E Ratio</div> | |
| <div class="text-2xl font-bold text-purple-700" id="pe-ratio">-</div> | |
| </div> | |
| <div class="bg-orange-50 p-4 rounded-lg"> | |
| <div class="text-sm text-gray-600">Market Cap</div> | |
| <div class="text-2xl font-bold text-orange-700" id="market-cap">-</div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-xl shadow-lg p-6 mb-8 card-hover"> | |
| <h3 class="text-xl font-bold text-primary mb-4 flex items-center"> | |
| <i class="fas fa-chart-line mr-2"></i> | |
| Analisis Harga & Indikator Teknikal | |
| </h3> | |
| <div class="chart-container"> | |
| <canvas id="priceChart"></canvas> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-xl shadow-lg p-6 mb-8 card-hover"> | |
| <h3 class="text-xl font-bold text-primary mb-4 flex items-center"> | |
| <i class="fas fa-bolt mr-2"></i> | |
| Analisis Momentum Jual/Beli | |
| </h3> | |
| <div class="bg-gradient-to-r from-blue-50 to-indigo-50 p-4 rounded-lg"> | |
| <div class="flex items-start justify-between"> | |
| <div class="flex-1"> | |
| <p class="text-gray-700 text-lg" id="momentum-text">Memuat sinyal analisis...</p> | |
| <div class="mt-2 text-sm text-gray-600" id="momentum-details"></div> | |
| </div> | |
| <div class="ml-4" id="momentum-icon"> | |
| <i class="fas fa-sync-alt fa-spin text-4xl text-blue-500"></i> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-xl shadow-lg p-6 card-hover"> | |
| <h3 class="text-xl font-bold text-primary mb-4 flex items-center"> | |
| <i class="fas fa-table mr-2"></i> | |
| Data Trading & Kepemilikan Saham | |
| </h3> | |
| <div class="overflow-x-auto"> | |
| <table class="data-table"> | |
| <thead> | |
| <tr> | |
| <th>Tanggal</th> | |
| <th>Harga Tutup</th> | |
| <th>Volume</th> | |
| <th>Kep. Institusi (%)</th> | |
| <th>Kep. Retail (%)</th> | |
| <th>Momentum</th> | |
| </tr> | |
| </thead> | |
| <tbody id="table-body"></tbody> | |
| </table> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| let priceChart = null; | |
| // Format functions | |
| function formatCurrencyIDR(amount) { | |
| if (!amount) return '-'; | |
| return new Intl.NumberFormat('id-ID', { | |
| style: 'currency', | |
| currency: 'IDR', | |
| minimumFractionDigits: 0, | |
| maximumFractionDigits: 0 | |
| }).format(amount); | |
| } | |
| function formatLargeNumber(num) { | |
| if (!num) return '-'; | |
| if (num >= 1e12) return (num / 1e12).toFixed(2) + 'T'; | |
| if (num >= 1e9) return (num / 1e9).toFixed(2) + 'B'; | |
| if (num >= 1e6) return (num / 1e6).toFixed(2) + 'M'; | |
| if (num >= 1e3) return (num / 1e3).toFixed(2) + 'K'; | |
| return num.toString(); | |
| } | |
| function getMomentumClass(momentum) { | |
| if (!momentum) return 'momentum-netral'; | |
| return momentum.includes('Beli') ? 'momentum-beli' : momentum.includes('Jual') ? 'momentum-jual' : 'momentum-netral'; | |
| } | |
| function getMomentumIcon(momentum) { | |
| if (!momentum) return '<i class="fas fa-equals text-gray-500"></i>'; | |
| if (momentum.includes('Beli')) return '<i class="fas fa-arrow-up text-green-500"></i>'; | |
| if (momentum.includes('Jual')) return '<i class="fas fa-arrow-down text-red-500"></i>'; | |
| return '<i class="fas fa-equals text-gray-500"></i>'; | |
| } | |
| // Fetch data from simulated Google Finance API | |
| async function fetchStockDataGoogleFinance(symbol) { | |
| // In a real app, this would call Google Finance API | |
| // Here we simulate with static data that mimics Google Finance structure | |
| const now = new Date(); | |
| const data = []; | |
| // Generate 30 days of simulated data to look like real data | |
| for (let i = 29; i >= 0; i--) { | |
| const date = new Date(); | |
| date.setDate(date.getDate() - i); | |
| // Create somewhat realistic trading data with trend | |
| const basePrice = 10000 + (Math.sin(i/10) * 1000); // Create a wavy trend | |
| const volatility = 200 * Math.random(); | |
| const open = basePrice + (Math.random() * volatility * 2 - volatility); | |
| const close = open * (0.95 + Math.random() * 0.1); | |
| const high = Math.max(open, close) * (1 + Math.random() * 0.02); | |
| const low = Math.min(open, close) * (1 - Math.random() * 0.02); | |
| const volume = 100000 + Math.floor(Math.random() * 900000); | |
| data.push({ | |
| date: date.toLocaleDateString('id-ID'), | |
| fullDate: date, | |
| open: open, | |
| high: high, | |
| low: low, | |
| close: close, | |
| volume: volume, | |
| adjClose: close | |
| }); | |
| } | |
| return data; | |
| } | |
| async function fetchFundamentalDataGoogleFinance(symbol) { | |
| // Simulate Google Finance fundamental data | |
| // In real implementation, this would call Google Finance API | |
| const fundamentals = { | |
| 'BBCA': { eps: 7500, roe: 18.5, peRatio: 22.3, marketCap: 785000000000 }, | |
| 'TLKM': { eps: 175, roe: 12.1, peRatio: 14.2, marketCap: 285000000000 }, | |
| 'BBRI': { eps: 480, roe: 15.8, peRatio: 18.7, marketCap: 520000000000 }, | |
| 'UNVR': { eps: 1850, roe: 22.3, peRatio: 28.5, marketCap: 415000000000 }, | |
| 'ASII': { eps: 210, roe: 9.4, peRatio: 11.2, marketCap: 95000000000 }, | |
| 'BMRI': { eps: 350, roe: 14.3, peRatio: 16.8, marketCap: 380000000000 }, | |
| 'BBNI': { eps: 420, roe: 13.7, peRatio: 15.5, marketCap: 210000000000 }, | |
| 'GGRM': { eps: 1200, roe: 25.1, peRatio: 35.2, marketCap: 330000000000 } | |
| }; | |
| const data = fundamentals[symbol] || fundamentals['BBCA']; | |
| return { | |
| eps: data.eps, | |
| roe: data.roe, | |
| peRatio: data.peRatio, | |
| marketCap: data.marketCap | |
| }; | |
| } | |
| function simulateOwnershipData(data) { | |
| const avgPrice = data.reduce((s, d) => s + d.close, 0) / data.length; | |
| return data.map((d, i) => { | |
| const baseInst = 65 + (i % 5); // Changing institutional ownership | |
| const variation = Math.sin(i) * 5; | |
| const randomness = (Math.random() * 10 - 5); | |
| const inst = Math.max(30, Math.min(85, baseInst + variation + randomness)); | |
| return { | |
| ...d, | |
| ownershipInstitutional: parseFloat(inst.toFixed(2)), | |
| ownershipRetail: parseFloat((100 - inst).toFixed(2)) | |
| }; | |
| }); | |
| } | |
| function calculateIndicators(data) { | |
| const closes = data.map(d => d.close); | |
| const sma20Values = []; | |
| // Calculate SMA 20 manually since TechnicalIndicators might not be working | |
| for (let i = 0; i < closes.length; i++) { | |
| if (i < 19) { | |
| sma20Values.push(null); | |
| } else { | |
| const sum = closes.slice(i-19, i+1).reduce((a, b) => a + b, 0); | |
| sma20Values.push(sum / 20); | |
| } | |
| } | |
| // Simple RSI calculation | |
| const rsiValues = []; | |
| const period = 14; | |
| for (let i = 0; i < closes.length; i++) { | |
| if (i < period) { | |
| rsiValues.push(null); | |
| } else { | |
| let gains = 0; | |
| let losses = 0; | |
| for (let j = i - period + 1; j <= i; j++) { | |
| const change = closes[j] - closes[j-1]; | |
| if (change > 0) gains += change; | |
| else losses -= change; | |
| } | |
| const avgGain = gains / period; | |
| const avgLoss = losses / period; | |
| if (avgLoss === 0) { | |
| rsiValues.push(100); | |
| } else { | |
| const rs = avgGain / avgLoss; | |
| rsiValues.push(100 - (100 / (1 + rs))); | |
| } | |
| } | |
| } | |
| data.forEach((d, i) => { | |
| d.sma20 = sma20Values[i]; | |
| d.rsi = rsiValues[i]; | |
| }); | |
| return data; | |
| } | |
| function analyzeMomentum(data) { | |
| const avgVol = data.reduce((s, d) => s + d.volume, 0) / data.filter(d => d.volume > 0).length; | |
| data.forEach((d, i) => { | |
| const prev = data[i - 1]; | |
| const change = prev ? ((d.close - prev.close) / prev.close) * 100 : 0; | |
| const ownChange = prev ? d.ownershipInstitutional - prev.ownershipInstitutional : 0; | |
| const highVol = d.volume > avgVol * 1.8; // More emphasis on volume | |
| const strongChange = Math.abs(change) > 2.5; // More significant price movements | |
| d.momentum = 'Netral'; | |
| d.momentumDetails = 'Pergerakan wajar pasar'; | |
| if (highVol && ownChange > 2.5) { | |
| d.momentum = 'Beli Kuat'; | |
| d.momentumDetails = 'Akumulasi institusi dengan volume tinggi'; | |
| } else if (highVol && ownChange < -2.5) { | |
| d.momentum = 'Jual Kuat'; | |
| d.momentumDetails = 'Distribusi institusi dengan volume tinggi'; | |
| } else if (change > 3 && highVol) { | |
| d.momentum = 'Beli'; | |
| d.momentumDetails = 'Breakout harga dengan volume tinggi'; | |
| } else if (change < -3 && highVol) { | |
| d.momentum = 'Jual'; | |
| d.momentumDetails = 'Breakdown harga dengan volume tinggi'; | |
| } else if (strongChange && ownChange > 1) { | |
| d.momentum = 'Beli Tren'; | |
| d.momentumDetails = 'Mengikuti tren kenaikan dengan dukungan institusi'; | |
| } else if (strongChange && ownChange < -1) { | |
| d.momentum = 'Jual Tren'; | |
| d.momentumDetails = 'Mengikuti tren penurunan dengan lepas institusi'; | |
| } | |
| }); | |
| return data; | |
| } | |
| function updateFundamental(fund) { | |
| document.getElementById('eps').textContent = fund.eps ? `Rp ${formatLargeNumber(fund.eps)}` : 'N/A'; | |
| document.getElementById('roe').textContent = fund.roe ? `${fund.roe}%` : 'N/A'; | |
| document.getElementById('pe-ratio').textContent = fund.peRatio ? `${fund.peRatio}x` : 'N/A'; | |
| document.getElementById('market-cap').textContent = fund.marketCap ? `${formatCurrencyIDR(fund.marketCap)}` : 'N/A'; | |
| } | |
| function updateChart(data) { | |
| const ctx = document.getElementById('priceChart').getContext('2d'); | |
| if (priceChart) priceChart.destroy(); | |
| const config = { | |
| type: 'line', | |
| data: { | |
| labels: data.map(d => d.date), | |
| datasets: [ | |
| { | |
| label: 'Harga Tutup', | |
| data: data.map(d => d.close), | |
| borderColor: 'rgb(59, 130, 246)', | |
| backgroundColor: 'rgba(59, 130, 246, 0.1)', | |
| tension: 0.1, | |
| fill: true | |
| }, | |
| { | |
| label: 'SMA 20', | |
| data: data.map(d => d.sma20), | |
| borderColor: 'rgb(34, 197, 94)', | |
| borderDash: [5, 5], | |
| tension: 0.1, | |
| fill: false | |
| } | |
| ] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| interaction: { mode: 'index', intersect: false }, | |
| scales: { | |
| y: { | |
| title: { display: true, text: 'Harga (IDR)' }, | |
| grid: { | |
| color: 'rgba(0, 0, 0, 0.1)' | |
| } | |
| }, | |
| x: { | |
| grid: { | |
| color: 'rgba(0, 0, 0, 0.1)' | |
| } | |
| } | |
| }, | |
| plugins: { | |
| legend: { | |
| position: 'top', | |
| }, | |
| tooltip: { | |
| backgroundColor: 'rgba(0, 0, 0, 0.8)', | |
| titleColor: '#fff', | |
| bodyColor: '#fff', | |
| borderColor: '#4b5563', | |
| borderWidth: 1, | |
| callbacks: { | |
| label: function(context) { | |
| return `${context.dataset.label}: ${formatCurrencyIDR(context.parsed.y)}`; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }; | |
| if (data.some(d => d.rsi)) { | |
| config.data.datasets.push({ | |
| label: 'RSI', | |
| data: data.map(d => d.rsi), | |
| borderColor: 'rgba(239, 68, 68, 0.8)', | |
| yAxisID: 'y1', | |
| pointRadius: 0 | |
| }); | |
| config.options.scales.y1 = { | |
| max: 100, | |
| min: 0, | |
| position: 'right', | |
| title: { display: true, text: 'RSI' }, | |
| grid: { | |
| drawOnChartArea: false | |
| } | |
| }; | |
| } | |
| priceChart = new Chart(ctx, config); | |
| } | |
| function updateTable(data) { | |
| const body = document.getElementById('table-body'); | |
| body.innerHTML = [...data].reverse().map(d => ` | |
| <tr> | |
| <td>${d.date}</td> | |
| <td>${formatCurrencyIDR(d.close)}</td> | |
| <td>${formatLargeNumber(d.volume)}</td> | |
| <td>${d.ownershipInstitutional.toFixed(2)}%</td> | |
| <td>${d.ownershipRetail.toFixed(2)}%</td> | |
| <td><span class="${getMomentumClass(d.momentum)}">${getMomentumIcon(d.momentum)} ${d.momentum}</span></td> | |
| </tr> | |
| `).join(''); | |
| } | |
| function updateMomentum(data) { | |
| const latest = data[data.length - 1]; | |
| const textEl = document.getElementById('momentum-text'); | |
| const detailsEl = document.getElementById('momentum-details'); | |
| const iconEl = document.getElementById('momentum-icon'); | |
| if (latest.momentum.includes('Beli')) { | |
| textEl.innerHTML = `🚀 <strong>Sinyal BELI Terdeteksi</strong>`; | |
| detailsEl.innerText = latest.momentumDetails; | |
| iconEl.innerHTML = '<i class="fas fa-arrow-up text-4xl text-green-500"></i>'; | |
| } else if (latest.momentum.includes('Jual')) { | |
| textEl.innerHTML = `⚠️ <strong>Sinyal JUAL Terdeteksi</strong>`; | |
| detailsEl.innerText = latest.momentumDetails; | |
| iconEl.innerHTML = '<i class="fas fa-arrow-down text-4xl text-red-500"></i>'; | |
| } else { | |
| textEl.innerHTML = `🟰 <strong>Kondisi Netral</strong>`; | |
| detailsEl.innerText = latest.momentumDetails; | |
| iconEl.innerHTML = '<i class="fas fa-equals text-4xl text-gray-500"></i>'; | |
| } | |
| } | |
| async function loadData() { | |
| const symbol = document.getElementById('symbol').value.trim().toUpperCase(); | |
| if (!symbol) { | |
| alert("Masukkan kode saham!"); | |
| return; | |
| } | |
| document.getElementById('loading').classList.remove('hidden'); | |
| document.getElementById('main-content').classList.add('hidden'); | |
| // Simulate micro-delay to show loading indicator | |
| await new Promise(resolve => setTimeout(resolve, 500)); | |
| try { | |
| const priceData = await fetchStockDataGoogleFinance(symbol); | |
| if (!priceData || priceData.length === 0) { | |
| throw new Error("Data tidak ditemukan"); | |
| } | |
| const fundamental = await fetchFundamentalDataGoogleFinance(symbol); | |
| const withOwnership = simulateOwnershipData(priceData); | |
| const withIndicators = calculateIndicators(withOwnership); | |
| const analyzed = analyzeMomentum(withIndicators); | |
| updateFundamental(fundamental); | |
| updateChart(analyzed); | |
| updateTable(analyzed); | |
| updateMomentum(analyzed); | |
| document.getElementById('loading').classList.add('hidden'); | |
| document.getElementById('main-content').classList.remove('hidden'); | |
| } catch (error) { | |
| console.error("Error loading data:", error); | |
| document.getElementById('loading').classList.add('hidden'); | |
| alert("Gagal mengambil data dari Google Finance. Silakan coba lagi."); | |
| } | |
| } | |
| // Auto-load when page is ready | |
| window.onload = () => { | |
| const urlParams = new URLSearchParams(window.location.search); | |
| const symbol = urlParams.get('symbol'); | |
| if (symbol) { | |
| document.getElementById('symbol').value = symbol.toUpperCase(); | |
| } | |
| loadData(); // Auto-load on page open | |
| }; | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-qwensite.hf.space/logo.svg" alt="qwensite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-qwensite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >QwenSite</a> - 🧬 <a href="https://enzostvs-qwensite.hf.space?remix=alterzick/trading-pro-v1" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |