Spaces:
Running
Running
File size: 5,509 Bytes
097168d 6340f89 097168d 6340f89 8c8b0ba 097168d 9c7fae0 8c8b0ba d8c7fa5 9c7fae0 d8c7fa5 9c7fae0 8c8b0ba 9c7fae0 097168d 9c7fae0 097168d 9c7fae0 8c8b0ba 097168d 3e3365d efd7324 8c8b0ba efd7324 8c8b0ba efd7324 8c8b0ba 3e3365d 8c8b0ba 9c7fae0 8c8b0ba efd7324 3e3365d efd7324 9c7fae0 8c8b0ba efd7324 8c8b0ba 3e3365d 8c8b0ba efd7324 097168d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sentinel Arbitrage Engine</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css">
<script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script>
<style>
:root { font-family: 'SF Mono', 'Consolas', 'Menlo', monospace; }
body { background-color: #111927; color: #E5E7EB; font-size: 14px; margin: 0; }
.container { max-width: 1400px; margin: 1rem auto; padding: 0 1rem; }
header h1 { color: #38BDF8; margin-bottom: 0; text-align: center; }
.grid-container { display: grid; grid-template-columns: 2fr 1fr; gap: 1.5rem; }
table { width: 100%; border-collapse: collapse; }
th { background-color: #374151; text-align: left; position: sticky; top: 0; }
td, th { padding: 0.75rem 1rem; border-bottom: 1px solid #374151; vertical-align: middle; }
.buy { color: #34D399; } .sell { color: #F87171; }
.risk-low { color: #34D399; } .risk-medium { color: #FBBF24; } .risk-high { color: #F87171; }
.log-panel { background-color: #1F2937; border: 1px solid #374151; border-radius: 0.5rem; height: 60vh; overflow-y: scroll; font-size: 12px; padding: 1rem; }
.log-panel p { margin: 0; padding: 0.25rem 0; border-bottom: 1px solid #2b3544; }
.log-panel p:first-child { color: #38BDF8; font-weight: bold; }
.asset-cell { display: flex; align-items: center; gap: 10px; }
.asset-logo { width: 24px; height: 24px; }
tbody tr { animation: fadeIn 0.5s ease-out; }
@keyframes fadeIn { from { background-color: rgba(52, 211, 153, 0.2); } to { background-color: transparent; } }
</style>
</head>
<body>
<main class="container">
<header><h1>Sentinel Arbitrage Engine</h1></header>
<div class="grid-container">
<section id="signal-section">
<article>
<table>
<thead><tr><th>Pair</th><th>Oracle 1 (Pyth)</th><th>Oracle 2 (Agg.)</th><th>Discrepancy</th><th>AI Risk</th><th>AI Strategy</th></tr></thead>
<tbody id="opportunities-table">
<tr id="placeholder-row"><td colspan="6" style="text-align:center; padding: 2rem;">Awaiting first signal...</td></tr>
</tbody>
</table>
</article>
</section>
<section id="log-section">
<article>
<header>Live Engine Logs</header>
<div class="log-panel" id="log-container">
<p>Connecting to engine...</p>
</div>
</article>
</section>
</div>
</main>
<script>
const ASSET_LOGOS = {'BTC': 'https://s2.coinmarketcap.com/static/img/coins/64x64/1.png','ETH': 'https://s2.coinmarketcap.com/static/img/coins/64x64/1027.png','SOL': 'https://s2.coinmarketcap.com/static/img/coins/64x64/5426.png','XRP': 'https://s2.coinmarketcap.com/static/img/coins/64x64/52.png','DOGE': 'https://s2.coinmarketcap.com/static/img/coins/64x64/74.png','ADA': 'https://s2.coinmarketcap.com/static/img/coins/64x64/2010.png','AVAX': 'https://s2.coinmarketcap.com/static/img/coins/64x64/5805.png','LINK': 'https://s2.coinmarketcap.com/static/img/coins/64x64/1975.png','DOT': 'https://s2.coinmarketcap.com/static/img/coins/64x64/6636.png','MATIC': 'https://s2.coinmarketcap.com/static/img/coins/64x64/3890.png'};
const socket = io();
const opportunitiesTable = document.getElementById('opportunities-table');
const logContainer = document.getElementById('log-container');
socket.on('connect', () => { logContainer.innerHTML = '<p>β
Connection Established. Engine is starting...</p>'; });
socket.on('disconnect', () => { addLog('π₯ Engine Disconnected.'); });
socket.on('log_message', (msg) => { addLog(msg); });
socket.on('new_signal', (signal) => {
document.getElementById('placeholder-row')?.remove();
const newRow = opportunitiesTable.insertRow(0);
const assetInfo = ASSET_LOGOS[signal.asset] || { logo: '' };
newRow.innerHTML = `
<td><div class="asset-cell"><img src="${assetInfo.logo}" class="asset-logo"><strong>${signal.asset}/USD</strong></div></td>
<td><span class="${signal.pyth_price < signal.chainlink_price ? 'buy' : 'sell'}">${signal.pyth_price.toLocaleString('en-US',{style:'currency',currency:'USD'})}</span></td>
<td><span class="${signal.pyth_price > signal.chainlink_price ? 'buy' : 'sell'}">${signal.chainlink_price.toLocaleString('en-US',{style:'currency',currency:'USD'})}</span></td>
<td><strong>${signal.spread_pct.toFixed(3)}%</strong></td>
<td><span class="risk-${signal.risk.toLowerCase()}">${signal.risk}</span></td>
<td>${signal.strategy}</td>
`;
});
function addLog(message) {
const logEntry = document.createElement('p');
logEntry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
logContainer.prepend(logEntry);
if (logContainer.children.length > 100) {
logContainer.lastChild.remove();
}
}
</script>
</body>
</html> |