<!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Dashboard de Monitoreo de Criptomonedas</title> <script src="https://c...content-available-to-author-only...e.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script> <style> body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 0; background-color: #f5f7f9; color: #333; } .container { max-width: 1200px; margin: 0 auto; padding: 20px; } header { background-color: #1e293b; color: white; padding: 15px 20px; border-radius: 8px 8px 0 0; } .dashboard-title { margin: 0; font-size: 24px; display: flex; align-items: center; justify-content: space-between; } .dropdown-container { display: flex; align-items: center; } #pair-dropdown { margin-left: 10px; padding: 8px; border-radius: 4px; border: 1px solid #ccc; background: #fff; font-size: 14px; } .tabs { margin-top: 20px; display: flex; border-bottom: 1px solid #ddd; background-color: #fff; border-radius: 8px 8px 0 0; } .tab { padding: 12px 20px; cursor: pointer; background-color: #f5f7f9; border: none; outline: none; font-size: 16px; transition: background-color 0.3s; border-radius: 8px 8px 0 0; margin-right: 2px; } .tab:hover { background-color: #e9ecef; } .active-tab { background-color: #fff; border-bottom: 3px solid #3b82f6; font-weight: 600; } .tab-content { display: none; padding: 20px; background-color: #fff; border-radius: 0 0 8px 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.05); } .active { display: block; } .section-title { font-size: 20px; margin-top: 0; margin-bottom: 20px; color: #1e293b; border-bottom: 1px solid #eee; padding-bottom: 10px; } .rates-grid, .prices-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; margin-bottom: 30px; } .rate-card, .price-card { background-color: #fff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); padding: 20px; transition: transform 0.2s; } .rate-card:hover, .price-card:hover { transform: translateY(-5px); } .card-title { font-size: 16px; margin-top: 0; color: #64748b; } .value { font-size: 24px; font-weight: 600; color: #0f172a; } .estado { display: inline-block; padding: 4px 8px; border-radius: 4px; font-size: 12px; font-weight: 600; margin-top: 10px; } .LONG { background-color: #dcfce7; color: #166534; } .SHORT { background-color: #fee2e2; color: #b91c1c; } .bid-ask { display: flex; justify-content: space-between; margin-top: 10px; } .bid, .ask { text-align: center; flex: 1; } .bid .label, .ask .label { font-size: 14px; color: #64748b; margin-bottom: 5px; } .bid .value { color: #16a34a; } .ask .value { color: #dc2626; } .log-section { margin-top: 30px; } .log-title { font-size: 18px; margin-bottom: 10px; color: #1e293b; } background-color: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 15px; max-height: 200px; overflow-y: auto; } padding-left: 20px; margin: 0; } margin-bottom: 8px; color: #334155; font-size: 14px; } .charts-container { margin-top: 30px; } .chart-wrapper { background-color: #fff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); padding: 20px; margin-bottom: 20px; } .chart-title { font-size: 18px; margin-top: 0; margin-bottom: 15px; color: #1e293b; } canvas { width: 100% !important; max-height: 300px; } @media (max-width: 768px) { .rates-grid, .prices-grid { grid-template-columns: 1fr; } .tabs { flex-direction: column; } .tab { border-radius: 0; margin-right: 0; margin-bottom: 2px; } } </style> </head> <body> <div class="container"> <header> <div class="dashboard-title"> <span>Dashboard de Criptomonedas</span> <div class="dropdown-container"> <label for="pair-dropdown">Par:</label> <select id="pair-dropdown"> <option value="BTC/USD">BTC/USD</option> <option value="ETH/USD">ETH/USD</option> <option value="SOL/USD">SOL/USD</option> <option value="XRP/USD">XRP/USD</option> </select> </div> </div> </header> <div class="tabs"> <button class="tab active-tab" data-tab="funding-tab">Tasas de Funding</button> <button class="tab" data-tab="prices-tab">Precios</button> <button class="tab" data-tab="charts-tab">Gráficos</button> </div> <div id="funding-tab" class="tab-content active"> <h2 class="section-title">Tasas de Funding: <span id="pair-title-funding">BTC/USD</span></h2> <div class="rates-grid"> <div class="rate-card"> <h3 class="card-title">Exch(1) Funding Rate</h3> <div class="value" id="exch1-funding-rate">0.00%</div> <div class="estado LONG" id="exch1-funding-estado">LONG</div> </div> <div class="rate-card"> <h3 class="card-title">Exch(2) Funding Rate</h3> <div class="value" id="exch2-funding-rate">0.00%</div> <div class="estado LONG" id="exch2-funding-estado">LONG</div> </div> <div class="rate-card"> <h3 class="card-title">Delta Rate</h3> <div class="value" id="delta-rate">0.00%</div> </div> </div> </div> <div id="prices-tab" class="tab-content"> <h2 class="section-title">Precios: <span id="pair-title-prices">BTC/USD</span></h2> <div class="prices-grid"> <div class="price-card"> <h3 class="card-title">Exch(1)</h3> <div class="bid-ask"> <div class="bid"> <div class="label">Bid (Compra)</div> <div class="value" id="exch1-bid">0.0000</div> </div> <div class="ask"> <div class="label">Ask (Venta)</div> <div class="value" id="exch1-ask">0.0000</div> </div> </div> </div> <div class="price-card"> <h3 class="card-title">Exch(2)</h3> <div class="bid-ask"> <div class="bid"> <div class="label">Bid (Compra)</div> <div class="value" id="exch2-bid">0.0000</div> </div> <div class="ask"> <div class="label">Ask (Venta)</div> <div class="value" id="exch2-ask">0.0000</div> </div> </div> </div> </div> </div> <div id="charts-tab" class="tab-content"> <h2 class="section-title">Gráficos: <span id="pair-title-charts">BTC/USD</span></h2> <div class="charts-container"> <div class="chart-wrapper"> <h3 class="chart-title">Funding Rates por Intercambio</h3> <canvas id="funding-rates-chart"></canvas> </div> <div class="chart-wrapper"> <h3 class="chart-title">Delta Rate con Media Móvil</h3> <canvas id="delta-rate-chart"></canvas> </div> </div> </div> <div class="log-section"> <h3 class="log-title">Registro de Eventos</h3> <div class="event-log"> <ul id="event-log-list"> <!-- Los eventos se añadirán aquí dinámicamente --> </ul> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', () => { const tabButtons = document.querySelectorAll('.tab'); const tabContents = document.querySelectorAll('.tab-content'); const pairDropdown = document.getElementById('pair-dropdown'); const pairTitleFunding = document.getElementById('pair-title-funding'); const pairTitlePrices = document.getElementById('pair-title-prices'); const pairTitleCharts = document.getElementById('pair-title-charts'); const exch1FundingRateSpan = document.getElementById('exch1-funding-rate'); const exch2FundingRateSpan = document.getElementById('exch2-funding-rate'); const deltaRateSpan = document.getElementById('delta-rate'); const exch1FundingEstadoSpan = document.getElementById('exch1-funding-estado'); const exch2FundingEstadoSpan = document.getElementById('exch2-funding-estado'); const exch1BidSpan = document.getElementById('exch1-bid'); const exch1AskSpan = document.getElementById('exch1-ask'); const exch2BidSpan = document.getElementById('exch2-bid'); const exch2AskSpan = document.getElementById('exch2-ask'); const eventLogList = document.getElementById('event-log-list'); // Datos para los gráficos const maxDataPoints = 20; const fundingRatesData = { labels: [], datasets: [ { label: 'Exch(1)', data: [], borderColor: 'rgb(59, 130, 246)', backgroundColor: 'rgba(59, 130, 246, 0.1)', fill: false, tension: 0.4 }, { label: 'Exch(2)', data: [], borderColor: 'rgb(249, 115, 22)', backgroundColor: 'rgba(249, 115, 22, 0.1)', fill: false, tension: 0.4 } ] }; const deltaRateData = { labels: [], datasets: [ { label: 'Delta Rate', data: [], borderColor: 'rgb(16, 185, 129)', backgroundColor: 'rgba(16, 185, 129, 0.1)', fill: false, tension: 0.4 }, { label: 'Media Móvil (5 períodos)', data: [], borderColor: 'rgb(168, 85, 247)', backgroundColor: 'rgba(168, 85, 247, 0.1)', borderDash: [5, 5], fill: false, tension: 0.4 } ] }; // Inicializar gráficos const fundingRatesCtx = document.getElementById('funding-rates-chart').getContext('2d'); const fundingRatesChart = new Chart(fundingRatesCtx, { type: 'line', data: fundingRatesData, options: { responsive: true, maintainAspectRatio: false, interaction: { mode: 'index', intersect: false, }, scales: { y: { title: { display: true, text: 'Funding Rate (%)' }, ticks: { callback: function(value) { return value.toFixed(2) + '%'; } } }, x: { title: { display: true, text: 'Tiempo' } } }, plugins: { tooltip: { callbacks: { label: function(context) { return context.dataset.label + ': ' + context.parsed.y.toFixed(2) + '%'; } } } } } }); const deltaRateCtx = document.getElementById('delta-rate-chart').getContext('2d'); const deltaRateChart = new Chart(deltaRateCtx, { type: 'line', data: deltaRateData, options: { responsive: true, maintainAspectRatio: false, interaction: { mode: 'index', intersect: false, }, scales: { y: { title: { display: true, text: 'Rate (%)' }, ticks: { callback: function(value) { return value.toFixed(2) + '%'; } } }, x: { title: { display: true, text: 'Tiempo' } } }, plugins: { tooltip: { callbacks: { label: function(context) { return context.dataset.label + ': ' + context.parsed.y.toFixed(2) + '%'; } } } } } }); // Funcionalidad de pestañas tabButtons.forEach(button => { button.addEventListener('click', () => { const tabId = button.dataset.tab; tabButtons.forEach(btn => btn.classList.remove('active-tab')); tabContents.forEach(content => content.classList.remove('active')); button.classList.add('active-tab'); document.getElementById(tabId).classList.add('active'); }); }); // Funcionalidad del selector de pares pairDropdown.addEventListener('change', (event) => { const selectedPair = event.target.value; pairTitleFunding.textContent = selectedPair; pairTitlePrices.textContent = selectedPair; pairTitleCharts.textContent = selectedPair; // En un dashboard real, aquí se actualizarían todos los datos para el nuevo par }); // Función para calcular la media móvil function calculateMovingAverage(data, windowSize) { if (data.length < windowSize) { } const result = []; for (let i = 0; i < data.length; i++) { if (i < windowSize - 1) { result.push(null); } else { const windowSlice = data.slice(i - windowSize + 1, i + 1); const sum = windowSlice.reduce((acc, val) => acc + val, 0); result.push(sum / windowSize); } } return result; } // Función para generar datos aleatorios simulados function generarDatoAleatorio() { const fundingRate = parseFloat(randomInRange(-0.005, 0.005).toFixed(4)); // Rango típico de funding rate const precioBase = 0.17; // Precio base arbitrario const spreadPorcentaje = randomInRange(0.001, 0.005); // Spread pequeño const ask = precioBase * (1 + spreadPorcentaje); const bid = precioBase * (1 - spreadPorcentaje); const deltaRate = parseFloat(randomInRange(0.03, 0.05).toFixed(2)); return { exch1_funding_rate: fundingRate * 100, // En porcentaje exch2_funding_rate: (fundingRate + randomInRange(-0.001, 0.001)) * 100, // Ligeramente diferente delta_rate: deltaRate, exch1_bid: bid.toFixed(4), exch1_ask: ask.toFixed(4), exch2_bid: (bid * (1 + randomInRange(-0.0005, 0.0005))).toFixed(4), // Ligeras diferencias exch2_ask: (ask * (1 + randomInRange(-0.0005, 0.0005))).toFixed(4), }; } } function actualizarDashboard() { const datos = generarDatoAleatorio(); exch1FundingRateSpan.textContent = datos.exch1_funding_rate.toFixed(2) + '%'; exch2FundingRateSpan.textContent = datos.exch2_funding_rate.toFixed(2) + '%'; deltaRateSpan.textContent = datos.delta_rate + '%'; exch1BidSpan.textContent = datos.exch1_bid;
Standard input is empty
<!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Dashboard de Monitoreo de Criptomonedas</title> <script src="https://c...content-available-to-author-only...e.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script> <style> body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 0; background-color: #f5f7f9; color: #333; } .container { max-width: 1200px; margin: 0 auto; padding: 20px; } header { background-color: #1e293b; color: white; padding: 15px 20px; border-radius: 8px 8px 0 0; } .dashboard-title { margin: 0; font-size: 24px; display: flex; align-items: center; justify-content: space-between; } .dropdown-container { display: flex; align-items: center; } #pair-dropdown { margin-left: 10px; padding: 8px; border-radius: 4px; border: 1px solid #ccc; background: #fff; font-size: 14px; } .tabs { margin-top: 20px; display: flex; border-bottom: 1px solid #ddd; background-color: #fff; border-radius: 8px 8px 0 0; } .tab { padding: 12px 20px; cursor: pointer; background-color: #f5f7f9; border: none; outline: none; font-size: 16px; transition: background-color 0.3s; border-radius: 8px 8px 0 0; margin-right: 2px; } .tab:hover { background-color: #e9ecef; } .active-tab { background-color: #fff; border-bottom: 3px solid #3b82f6; font-weight: 600; } .tab-content { display: none; padding: 20px; background-color: #fff; border-radius: 0 0 8px 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.05); } .active { display: block; } .section-title { font-size: 20px; margin-top: 0; margin-bottom: 20px; color: #1e293b; border-bottom: 1px solid #eee; padding-bottom: 10px; } .rates-grid, .prices-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; margin-bottom: 30px; } .rate-card, .price-card { background-color: #fff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); padding: 20px; transition: transform 0.2s; } .rate-card:hover, .price-card:hover { transform: translateY(-5px); } .card-title { font-size: 16px; margin-top: 0; color: #64748b; } .value { font-size: 24px; font-weight: 600; color: #0f172a; } .estado { display: inline-block; padding: 4px 8px; border-radius: 4px; font-size: 12px; font-weight: 600; margin-top: 10px; } .LONG { background-color: #dcfce7; color: #166534; } .SHORT { background-color: #fee2e2; color: #b91c1c; } .bid-ask { display: flex; justify-content: space-between; margin-top: 10px; } .bid, .ask { text-align: center; flex: 1; } .bid .label, .ask .label { font-size: 14px; color: #64748b; margin-bottom: 5px; } .bid .value { color: #16a34a; } .ask .value { color: #dc2626; } .log-section { margin-top: 30px; } .log-title { font-size: 18px; margin-bottom: 10px; color: #1e293b; } .event-log { background-color: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 15px; max-height: 200px; overflow-y: auto; } .event-log ul { padding-left: 20px; margin: 0; } .event-log li { margin-bottom: 8px; color: #334155; font-size: 14px; } .charts-container { margin-top: 30px; } .chart-wrapper { background-color: #fff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); padding: 20px; margin-bottom: 20px; } .chart-title { font-size: 18px; margin-top: 0; margin-bottom: 15px; color: #1e293b; } canvas { width: 100% !important; max-height: 300px; } @media (max-width: 768px) { .rates-grid, .prices-grid { grid-template-columns: 1fr; } .tabs { flex-direction: column; } .tab { border-radius: 0; margin-right: 0; margin-bottom: 2px; } } </style> </head> <body> <div class="container"> <header> <div class="dashboard-title"> <span>Dashboard de Criptomonedas</span> <div class="dropdown-container"> <label for="pair-dropdown">Par:</label> <select id="pair-dropdown"> <option value="BTC/USD">BTC/USD</option> <option value="ETH/USD">ETH/USD</option> <option value="SOL/USD">SOL/USD</option> <option value="XRP/USD">XRP/USD</option> </select> </div> </div> </header> <div class="tabs"> <button class="tab active-tab" data-tab="funding-tab">Tasas de Funding</button> <button class="tab" data-tab="prices-tab">Precios</button> <button class="tab" data-tab="charts-tab">Gráficos</button> </div> <div id="funding-tab" class="tab-content active"> <h2 class="section-title">Tasas de Funding: <span id="pair-title-funding">BTC/USD</span></h2> <div class="rates-grid"> <div class="rate-card"> <h3 class="card-title">Exch(1) Funding Rate</h3> <div class="value" id="exch1-funding-rate">0.00%</div> <div class="estado LONG" id="exch1-funding-estado">LONG</div> </div> <div class="rate-card"> <h3 class="card-title">Exch(2) Funding Rate</h3> <div class="value" id="exch2-funding-rate">0.00%</div> <div class="estado LONG" id="exch2-funding-estado">LONG</div> </div> <div class="rate-card"> <h3 class="card-title">Delta Rate</h3> <div class="value" id="delta-rate">0.00%</div> </div> </div> </div> <div id="prices-tab" class="tab-content"> <h2 class="section-title">Precios: <span id="pair-title-prices">BTC/USD</span></h2> <div class="prices-grid"> <div class="price-card"> <h3 class="card-title">Exch(1)</h3> <div class="bid-ask"> <div class="bid"> <div class="label">Bid (Compra)</div> <div class="value" id="exch1-bid">0.0000</div> </div> <div class="ask"> <div class="label">Ask (Venta)</div> <div class="value" id="exch1-ask">0.0000</div> </div> </div> </div> <div class="price-card"> <h3 class="card-title">Exch(2)</h3> <div class="bid-ask"> <div class="bid"> <div class="label">Bid (Compra)</div> <div class="value" id="exch2-bid">0.0000</div> </div> <div class="ask"> <div class="label">Ask (Venta)</div> <div class="value" id="exch2-ask">0.0000</div> </div> </div> </div> </div> </div> <div id="charts-tab" class="tab-content"> <h2 class="section-title">Gráficos: <span id="pair-title-charts">BTC/USD</span></h2> <div class="charts-container"> <div class="chart-wrapper"> <h3 class="chart-title">Funding Rates por Intercambio</h3> <canvas id="funding-rates-chart"></canvas> </div> <div class="chart-wrapper"> <h3 class="chart-title">Delta Rate con Media Móvil</h3> <canvas id="delta-rate-chart"></canvas> </div> </div> </div> <div class="log-section"> <h3 class="log-title">Registro de Eventos</h3> <div class="event-log"> <ul id="event-log-list"> <!-- Los eventos se añadirán aquí dinámicamente --> </ul> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', () => { const tabButtons = document.querySelectorAll('.tab'); const tabContents = document.querySelectorAll('.tab-content'); const pairDropdown = document.getElementById('pair-dropdown'); const pairTitleFunding = document.getElementById('pair-title-funding'); const pairTitlePrices = document.getElementById('pair-title-prices'); const pairTitleCharts = document.getElementById('pair-title-charts'); const exch1FundingRateSpan = document.getElementById('exch1-funding-rate'); const exch2FundingRateSpan = document.getElementById('exch2-funding-rate'); const deltaRateSpan = document.getElementById('delta-rate'); const exch1FundingEstadoSpan = document.getElementById('exch1-funding-estado'); const exch2FundingEstadoSpan = document.getElementById('exch2-funding-estado'); const exch1BidSpan = document.getElementById('exch1-bid'); const exch1AskSpan = document.getElementById('exch1-ask'); const exch2BidSpan = document.getElementById('exch2-bid'); const exch2AskSpan = document.getElementById('exch2-ask'); const eventLogList = document.getElementById('event-log-list'); // Datos para los gráficos const maxDataPoints = 20; const fundingRatesData = { labels: [], datasets: [ { label: 'Exch(1)', data: [], borderColor: 'rgb(59, 130, 246)', backgroundColor: 'rgba(59, 130, 246, 0.1)', fill: false, tension: 0.4 }, { label: 'Exch(2)', data: [], borderColor: 'rgb(249, 115, 22)', backgroundColor: 'rgba(249, 115, 22, 0.1)', fill: false, tension: 0.4 } ] }; const deltaRateData = { labels: [], datasets: [ { label: 'Delta Rate', data: [], borderColor: 'rgb(16, 185, 129)', backgroundColor: 'rgba(16, 185, 129, 0.1)', fill: false, tension: 0.4 }, { label: 'Media Móvil (5 períodos)', data: [], borderColor: 'rgb(168, 85, 247)', backgroundColor: 'rgba(168, 85, 247, 0.1)', borderDash: [5, 5], fill: false, tension: 0.4 } ] }; // Inicializar gráficos const fundingRatesCtx = document.getElementById('funding-rates-chart').getContext('2d'); const fundingRatesChart = new Chart(fundingRatesCtx, { type: 'line', data: fundingRatesData, options: { responsive: true, maintainAspectRatio: false, interaction: { mode: 'index', intersect: false, }, scales: { y: { title: { display: true, text: 'Funding Rate (%)' }, ticks: { callback: function(value) { return value.toFixed(2) + '%'; } } }, x: { title: { display: true, text: 'Tiempo' } } }, plugins: { tooltip: { callbacks: { label: function(context) { return context.dataset.label + ': ' + context.parsed.y.toFixed(2) + '%'; } } } } } }); const deltaRateCtx = document.getElementById('delta-rate-chart').getContext('2d'); const deltaRateChart = new Chart(deltaRateCtx, { type: 'line', data: deltaRateData, options: { responsive: true, maintainAspectRatio: false, interaction: { mode: 'index', intersect: false, }, scales: { y: { title: { display: true, text: 'Rate (%)' }, ticks: { callback: function(value) { return value.toFixed(2) + '%'; } } }, x: { title: { display: true, text: 'Tiempo' } } }, plugins: { tooltip: { callbacks: { label: function(context) { return context.dataset.label + ': ' + context.parsed.y.toFixed(2) + '%'; } } } } } }); // Funcionalidad de pestañas tabButtons.forEach(button => { button.addEventListener('click', () => { const tabId = button.dataset.tab; tabButtons.forEach(btn => btn.classList.remove('active-tab')); tabContents.forEach(content => content.classList.remove('active')); button.classList.add('active-tab'); document.getElementById(tabId).classList.add('active'); }); }); // Funcionalidad del selector de pares pairDropdown.addEventListener('change', (event) => { const selectedPair = event.target.value; pairTitleFunding.textContent = selectedPair; pairTitlePrices.textContent = selectedPair; pairTitleCharts.textContent = selectedPair; // En un dashboard real, aquí se actualizarían todos los datos para el nuevo par }); // Función para calcular la media móvil function calculateMovingAverage(data, windowSize) { if (data.length < windowSize) { return Array(data.length).fill(null); } const result = []; for (let i = 0; i < data.length; i++) { if (i < windowSize - 1) { result.push(null); } else { const windowSlice = data.slice(i - windowSize + 1, i + 1); const sum = windowSlice.reduce((acc, val) => acc + val, 0); result.push(sum / windowSize); } } return result; } // Función para generar datos aleatorios simulados function generarDatoAleatorio() { const fundingRate = parseFloat(randomInRange(-0.005, 0.005).toFixed(4)); // Rango típico de funding rate const precioBase = 0.17; // Precio base arbitrario const spreadPorcentaje = randomInRange(0.001, 0.005); // Spread pequeño const ask = precioBase * (1 + spreadPorcentaje); const bid = precioBase * (1 - spreadPorcentaje); const deltaRate = parseFloat(randomInRange(0.03, 0.05).toFixed(2)); return { exch1_funding_rate: fundingRate * 100, // En porcentaje exch2_funding_rate: (fundingRate + randomInRange(-0.001, 0.001)) * 100, // Ligeramente diferente delta_rate: deltaRate, exch1_bid: bid.toFixed(4), exch1_ask: ask.toFixed(4), exch2_bid: (bid * (1 + randomInRange(-0.0005, 0.0005))).toFixed(4), // Ligeras diferencias exch2_ask: (ask * (1 + randomInRange(-0.0005, 0.0005))).toFixed(4), timestamp: Date.now() }; } function randomInRange(min, max) { return Math.random() * (max - min) + min; } function actualizarDashboard() { const datos = generarDatoAleatorio(); exch1FundingRateSpan.textContent = datos.exch1_funding_rate.toFixed(2) + '%'; exch2FundingRateSpan.textContent = datos.exch2_funding_rate.toFixed(2) + '%'; deltaRateSpan.textContent = datos.delta_rate + '%'; exch1BidSpan.textContent = datos.exch1_bid;