mgbam commited on
Commit
8c8b0ba
·
verified ·
1 Parent(s): 9b0536f

Update static/index.html

Browse files
Files changed (1) hide show
  1. static/index.html +48 -82
static/index.html CHANGED
@@ -5,119 +5,85 @@
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Sentinel Arbitrage Engine</title>
7
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css">
 
8
  <style>
9
  :root { font-family: 'SF Mono', 'Consolas', 'Menlo', monospace; }
10
- body { background-color: #111927; color: #E5E7EB; font-size: 14px; margin: 0; padding: 1rem; }
11
- .container { max-width: 1280px; margin: 0 auto; }
12
- header { text-align: center; margin-bottom: 1.5rem; }
13
- h1 { color: #38BDF8; margin-bottom: 0; }
14
- .status-bar { font-size: 12px; color: #9CA3AF; text-align: right; margin-bottom: 1rem; }
15
- .status-online { color: #34D399; } .status-offline { color: #F87171; }
16
  table { width: 100%; border-collapse: collapse; }
17
  th { background-color: #374151; text-align: left; position: sticky; top: 0; }
18
  td, th { padding: 0.75rem 1rem; border-bottom: 1px solid #374151; vertical-align: middle; }
19
  .buy { color: #34D399; } .sell { color: #F87171; }
20
  .risk-low { color: #34D399; } .risk-medium { color: #FBBF24; } .risk-high { color: #F87171; }
 
 
 
 
 
21
  tbody tr { animation: fadeIn 0.5s ease-out; }
22
  @keyframes fadeIn { from { background-color: rgba(52, 211, 153, 0.2); } to { background-color: transparent; } }
23
- .asset-cell { display: grid; grid-template-columns: auto 1fr; gap: 12px; align-items: center; }
24
- .asset-logo { width: 24px; height: 24px; }
25
- .asset-cell strong { color: inherit; text-decoration: none; font-weight: bold; }
26
  </style>
27
  </head>
28
  <body>
29
  <main class="container">
30
  <header><h1>Sentinel Arbitrage Engine</h1></header>
31
- <div class="status-bar">
32
- Engine Status: <span id="status-light" class="status-offline">CONNECTING...</span> | Last Signal: <span id="last-update-time">--:--:--</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  </div>
34
- <article>
35
- <table>
36
- <thead>
37
- <tr>
38
- <th>Pair</th>
39
- <th>Oracle 1 (Pyth)</th>
40
- <th>Oracle 2 (Agg.)</th>
41
- <th>Discrepancy</th>
42
- <th>AI Risk</th>
43
- <th>AI Strategy</th>
44
- </tr>
45
- </thead>
46
- <tbody id="opportunities-table">
47
- <tr id="placeholder-row"><td colspan="6" style="text-align:center; padding: 2rem;">Initializing signal stream...</td></tr>
48
- </tbody>
49
- </table>
50
- </article>
51
  </main>
52
 
53
  <script>
54
- const ASSET_LOGOS = {
55
- 'BTC': 'https://s2.coinmarketcap.com/static/img/coins/64x64/1.png',
56
- 'ETH': 'https://s2.coinmarketcap.com/static/img/coins/64x64/1027.png',
57
- 'SOL': 'https://s2.coinmarketcap.com/static/img/coins/64x64/5426.png',
58
- 'XRP': 'https://s2.coinmarketcap.com/static/img/coins/64x64/52.png',
59
- 'DOGE': { logo: 'https://s2.coinmarketcap.com/static/img/coins/64x64/74.png' },
60
- 'ADA': { logo: 'https://s2.coinmarketcap.com/static/img/coins/64x64/2010.png' },
61
- 'AVAX': { logo: 'https://s2.coinmarketcap.com/static/img/coins/64x64/5805.png' },
62
- 'LINK': { logo: 'https://s2.coinmarketcap.com/static/img/coins/64x64/1975.png' },
63
- 'DOT': { logo: 'https://s2.coinmarketcap.com/static/img/coins/64x64/6636.png' },
64
- 'MATIC': { logo: 'https://s2.coinmarketcap.com/static/img/coins/64x64/3890.png' }
65
- };
66
-
67
- const statusLight = document.getElementById('status-light');
68
  const opportunitiesTable = document.getElementById('opportunities-table');
69
- const lastUpdateTime = document.getElementById('last-update-time');
70
 
71
- async function connectToStream() {
72
- try {
73
- const response = await fetch('/api/signals/stream');
74
- statusLight.textContent = 'ONLINE';
75
- statusLight.className = 'status-online';
76
- document.getElementById('placeholder-row')?.remove();
77
 
78
- const reader = response.body.getReader();
79
- const decoder = new TextDecoder();
80
 
81
- while (true) {
82
- const { value, done } = await reader.read();
83
- if (done) break;
84
-
85
- const chunk = decoder.decode(value, { stream: true });
86
- const lines = chunk.split('\n').filter(line => line.trim() !== '');
87
-
88
- for (const line of lines) {
89
- try {
90
- const signal = JSON.parse(line);
91
- renderSignal(signal);
92
- } catch (e) {
93
- console.error("Failed to parse signal line:", line, e);
94
- }
95
- }
96
- }
97
- } catch (error) {
98
- console.error("Stream connection failed:", error);
99
- statusLight.textContent = 'OFFLINE';
100
- statusLight.className = 'status-offline';
101
- setTimeout(connectToStream, 5000); // Retry after 5 seconds
102
- }
103
- }
104
-
105
- function renderSignal(signal) {
106
  const newRow = opportunitiesTable.insertRow(0);
107
  const assetInfo = ASSET_LOGOS[signal.asset] || { logo: '' };
108
-
109
  newRow.innerHTML = `
110
  <td><div class="asset-cell"><img src="${assetInfo.logo}" class="asset-logo"><strong>${signal.asset}/USD</strong></div></td>
111
- <td><span class="${signal.pyth_price < signal.chainlink_price ? 'buy' : 'sell'}">${signal.pyth_price.toLocaleString('en-US', { style: 'currency', currency: 'USD' })}</span></td>
112
- <td><span class="${signal.pyth_price > signal.chainlink_price ? 'buy' : 'sell'}">${signal.chainlink_price.toLocaleString('en-US', { style: 'currency', currency: 'USD' })}</span></td>
113
  <td><strong>${signal.spread_pct.toFixed(3)}%</strong></td>
114
  <td><span class="risk-${signal.risk.toLowerCase()}">${signal.risk}</span></td>
115
  <td>${signal.strategy}</td>
116
  `;
117
- lastUpdateTime.textContent = new Date(signal.timestamp).toLocaleTimeString('en-US');
118
- }
119
 
120
- connectToStream();
 
 
 
 
 
 
 
121
  </script>
122
  </body>
123
  </html>
 
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Sentinel Arbitrage Engine</title>
7
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css">
8
+ <script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script>
9
  <style>
10
  :root { font-family: 'SF Mono', 'Consolas', 'Menlo', monospace; }
11
+ body { background-color: #111927; color: #E5E7EB; font-size: 14px; margin: 0; }
12
+ .container { max-width: 1400px; margin: 1rem auto; padding: 0 1rem; }
13
+ header h1 { color: #38BDF8; margin-bottom: 0; text-align: center; }
14
+ .grid-container { display: grid; grid-template-columns: 2fr 1fr; gap: 1.5rem; }
 
 
15
  table { width: 100%; border-collapse: collapse; }
16
  th { background-color: #374151; text-align: left; position: sticky; top: 0; }
17
  td, th { padding: 0.75rem 1rem; border-bottom: 1px solid #374151; vertical-align: middle; }
18
  .buy { color: #34D399; } .sell { color: #F87171; }
19
  .risk-low { color: #34D399; } .risk-medium { color: #FBBF24; } .risk-high { color: #F87171; }
20
+ .log-panel { background-color: #1F2937; border: 1px solid #374151; border-radius: 0.5rem; height: 60vh; overflow-y: scroll; font-size: 12px; padding: 1rem; }
21
+ .log-panel p { margin: 0; padding: 0.25rem 0; border-bottom: 1px solid #2b3544; }
22
+ .log-panel p:first-child { color: #38BDF8; font-weight: bold; }
23
+ .asset-cell { display: flex; align-items: center; gap: 10px; }
24
+ .asset-logo { width: 24px; height: 24px; }
25
  tbody tr { animation: fadeIn 0.5s ease-out; }
26
  @keyframes fadeIn { from { background-color: rgba(52, 211, 153, 0.2); } to { background-color: transparent; } }
 
 
 
27
  </style>
28
  </head>
29
  <body>
30
  <main class="container">
31
  <header><h1>Sentinel Arbitrage Engine</h1></header>
32
+ <div class="grid-container">
33
+ <section id="signal-section">
34
+ <article>
35
+ <table>
36
+ <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>
37
+ <tbody id="opportunities-table">
38
+ <tr id="placeholder-row"><td colspan="6" style="text-align:center; padding: 2rem;">Awaiting first signal...</td></tr>
39
+ </tbody>
40
+ </table>
41
+ </article>
42
+ </section>
43
+ <section id="log-section">
44
+ <article>
45
+ <header>Live Engine Logs</header>
46
+ <div class="log-panel" id="log-container">
47
+ <p>Connecting to engine...</p>
48
+ </div>
49
+ </article>
50
+ </section>
51
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  </main>
53
 
54
  <script>
55
+ 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'};
56
+ const socket = io();
 
 
 
 
 
 
 
 
 
 
 
 
57
  const opportunitiesTable = document.getElementById('opportunities-table');
58
+ const logContainer = document.getElementById('log-container');
59
 
60
+ socket.on('connect', () => { logContainer.innerHTML = '<p>✅ Connection Established. Engine is starting...</p>'; });
61
+ socket.on('disconnect', () => { addLog('🔥 Engine Disconnected.'); });
 
 
 
 
62
 
63
+ socket.on('log_message', (msg) => { addLog(msg); });
 
64
 
65
+ socket.on('new_signal', (signal) => {
66
+ document.getElementById('placeholder-row')?.remove();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  const newRow = opportunitiesTable.insertRow(0);
68
  const assetInfo = ASSET_LOGOS[signal.asset] || { logo: '' };
 
69
  newRow.innerHTML = `
70
  <td><div class="asset-cell"><img src="${assetInfo.logo}" class="asset-logo"><strong>${signal.asset}/USD</strong></div></td>
71
+ <td><span class="${signal.pyth_price < signal.chainlink_price ? 'buy' : 'sell'}">${signal.pyth_price.toLocaleString('en-US',{style:'currency',currency:'USD'})}</span></td>
72
+ <td><span class="${signal.pyth_price > signal.chainlink_price ? 'buy' : 'sell'}">${signal.chainlink_price.toLocaleString('en-US',{style:'currency',currency:'USD'})}</span></td>
73
  <td><strong>${signal.spread_pct.toFixed(3)}%</strong></td>
74
  <td><span class="risk-${signal.risk.toLowerCase()}">${signal.risk}</span></td>
75
  <td>${signal.strategy}</td>
76
  `;
77
+ });
 
78
 
79
+ function addLog(message) {
80
+ const logEntry = document.createElement('p');
81
+ logEntry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
82
+ logContainer.prepend(logEntry);
83
+ if (logContainer.children.length > 100) {
84
+ logContainer.lastChild.remove();
85
+ }
86
+ }
87
  </script>
88
  </body>
89
  </html>