Spaces:
Running
Running
Update static/index.html
Browse files- static/index.html +125 -23
static/index.html
CHANGED
@@ -4,24 +4,105 @@
|
|
4 |
<meta charset="UTF-8">
|
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 {
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
</style>
|
26 |
</head>
|
27 |
<body>
|
@@ -29,9 +110,11 @@
|
|
29 |
<header>
|
30 |
<h1>Sentinel Arbitrage Engine</h1>
|
31 |
</header>
|
|
|
32 |
<div class="status-bar">
|
33 |
Engine Status: <span id="status-light" class="status-offline">OFFLINE</span> | Last Signal: <span id="last-update-time">--:--:--</span>
|
34 |
</div>
|
|
|
35 |
<article>
|
36 |
<table>
|
37 |
<thead>
|
@@ -50,11 +133,21 @@
|
|
50 |
</table>
|
51 |
</article>
|
52 |
</main>
|
|
|
53 |
<script>
|
54 |
-
const
|
55 |
-
'BTC':
|
56 |
-
|
57 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
};
|
59 |
|
60 |
const socket = io();
|
@@ -63,28 +156,37 @@
|
|
63 |
const lastUpdateTime = document.getElementById('last-update-time');
|
64 |
|
65 |
socket.on('connect', () => {
|
|
|
66 |
statusLight.textContent = 'ONLINE';
|
67 |
statusLight.className = 'status-online';
|
68 |
document.getElementById('placeholder-row').cells[0].textContent = 'Monitoring for oracle dislocations...';
|
69 |
});
|
70 |
|
71 |
socket.on('disconnect', () => {
|
|
|
72 |
statusLight.textContent = 'OFFLINE';
|
73 |
statusLight.className = 'status-offline';
|
74 |
});
|
75 |
|
76 |
socket.on('new_signal', (signal) => {
|
|
|
77 |
document.getElementById('placeholder-row')?.remove();
|
78 |
|
79 |
const isPythCheaper = signal.pyth_price < signal.chainlink_price;
|
80 |
const newRow = opportunitiesTable.insertRow(0);
|
81 |
|
82 |
-
const
|
83 |
|
|
|
84 |
newRow.innerHTML = `
|
85 |
-
<td
|
86 |
-
|
87 |
-
|
|
|
|
|
|
|
|
|
|
|
88 |
<td><strong>${signal.spread_pct.toFixed(3)}%</strong></td>
|
89 |
<td><span class="risk-${signal.risk.toLowerCase()}">${signal.risk}</span></td>
|
90 |
<td>${signal.strategy}</td>
|
|
|
4 |
<meta charset="UTF-8">
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
<title>Sentinel Arbitrage Engine</title>
|
7 |
+
|
8 |
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css">
|
9 |
<script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script>
|
10 |
+
|
11 |
<style>
|
12 |
+
:root {
|
13 |
+
--pico-font-family: 'SF Mono', 'Consolas', 'Menlo', monospace;
|
14 |
+
--pico-font-size: 14px;
|
15 |
+
--pico-color-green-400: #34D399;
|
16 |
+
--pico-color-red-400: #F87171;
|
17 |
+
--pico-color-amber-400: #FBBF24;
|
18 |
+
}
|
19 |
+
|
20 |
+
body {
|
21 |
+
background-color: #111927;
|
22 |
+
color: #E5E7EB;
|
23 |
+
}
|
24 |
+
|
25 |
+
.container {
|
26 |
+
max-width: 1280px;
|
27 |
+
margin: 1.5rem auto;
|
28 |
+
padding: 0 1rem;
|
29 |
+
}
|
30 |
+
|
31 |
+
header {
|
32 |
+
text-align: center;
|
33 |
+
margin-bottom: 1.5rem;
|
34 |
+
}
|
35 |
+
|
36 |
+
h1 {
|
37 |
+
color: #38BDF8;
|
38 |
+
margin-bottom: 0;
|
39 |
+
font-weight: 600;
|
40 |
+
}
|
41 |
+
|
42 |
+
table {
|
43 |
+
width: 100%;
|
44 |
+
border-collapse: collapse;
|
45 |
+
}
|
46 |
+
|
47 |
+
th {
|
48 |
+
background-color: #374151;
|
49 |
+
text-align: left;
|
50 |
+
position: sticky;
|
51 |
+
top: 0;
|
52 |
+
z-index: 10;
|
53 |
+
}
|
54 |
+
|
55 |
+
td, th {
|
56 |
+
padding: 0.75rem 1rem;
|
57 |
+
border-bottom: 1px solid #374151;
|
58 |
+
vertical-align: middle;
|
59 |
+
}
|
60 |
+
|
61 |
+
tbody tr {
|
62 |
+
animation: fadeIn 0.7s ease-out forwards;
|
63 |
+
}
|
64 |
+
|
65 |
+
.buy { color: var(--pico-color-green-400); }
|
66 |
+
.sell { color: var(--pico-color-red-400); }
|
67 |
+
|
68 |
+
.risk-low { color: var(--pico-color-green-400); }
|
69 |
+
.risk-medium { color: var(--pico-color-amber-400); }
|
70 |
+
.risk-high { color: var(--pico-color-red-400); }
|
71 |
+
|
72 |
+
.status-bar {
|
73 |
+
font-size: 12px;
|
74 |
+
color: #9CA3AF;
|
75 |
+
text-align: right;
|
76 |
+
margin-bottom: 1rem;
|
77 |
+
}
|
78 |
+
.status-online { color: #34D399; }
|
79 |
+
.status-offline { color: #F87171; }
|
80 |
+
|
81 |
+
/* --- NEW STYLES FOR THE FIX --- */
|
82 |
+
.asset-cell {
|
83 |
+
display: grid;
|
84 |
+
grid-template-columns: auto 1fr;
|
85 |
+
gap: 12px;
|
86 |
+
align-items: center;
|
87 |
+
}
|
88 |
+
.asset-logo {
|
89 |
+
width: 24px;
|
90 |
+
height: 24px;
|
91 |
+
}
|
92 |
+
.asset-cell a {
|
93 |
+
color: inherit;
|
94 |
+
text-decoration: none;
|
95 |
+
font-weight: bold;
|
96 |
+
}
|
97 |
+
.asset-cell a:hover {
|
98 |
+
text-decoration: underline;
|
99 |
+
}
|
100 |
+
/* --- END NEW STYLES --- */
|
101 |
+
|
102 |
+
@keyframes fadeIn {
|
103 |
+
from { background-color: rgba(52, 211, 153, 0.2); opacity: 0; }
|
104 |
+
to { background-color: transparent; opacity: 1; }
|
105 |
+
}
|
106 |
</style>
|
107 |
</head>
|
108 |
<body>
|
|
|
110 |
<header>
|
111 |
<h1>Sentinel Arbitrage Engine</h1>
|
112 |
</header>
|
113 |
+
|
114 |
<div class="status-bar">
|
115 |
Engine Status: <span id="status-light" class="status-offline">OFFLINE</span> | Last Signal: <span id="last-update-time">--:--:--</span>
|
116 |
</div>
|
117 |
+
|
118 |
<article>
|
119 |
<table>
|
120 |
<thead>
|
|
|
133 |
</table>
|
134 |
</article>
|
135 |
</main>
|
136 |
+
|
137 |
<script>
|
138 |
+
const ASSET_CONFIG = {
|
139 |
+
'BTC': {
|
140 |
+
logo: 'https://s2.coinmarketcap.com/static/img/coins/64x64/1.png',
|
141 |
+
link: 'https://www.coingecko.com/en/coins/bitcoin'
|
142 |
+
},
|
143 |
+
'ETH': {
|
144 |
+
logo: 'https://s2.coinmarketcap.com/static/img/coins/64x64/1027.png',
|
145 |
+
link: 'https://www.coingecko.com/en/coins/ethereum'
|
146 |
+
},
|
147 |
+
'SOL': {
|
148 |
+
logo: 'https://s2.coinmarketcap.com/static/img/coins/64x64/5426.png',
|
149 |
+
link: 'https://www.coingecko.com/en/coins/solana'
|
150 |
+
}
|
151 |
};
|
152 |
|
153 |
const socket = io();
|
|
|
156 |
const lastUpdateTime = document.getElementById('last-update-time');
|
157 |
|
158 |
socket.on('connect', () => {
|
159 |
+
console.log('✅ Connected to Sentinel Engine.');
|
160 |
statusLight.textContent = 'ONLINE';
|
161 |
statusLight.className = 'status-online';
|
162 |
document.getElementById('placeholder-row').cells[0].textContent = 'Monitoring for oracle dislocations...';
|
163 |
});
|
164 |
|
165 |
socket.on('disconnect', () => {
|
166 |
+
console.log('🔥 Disconnected from Sentinel Engine.');
|
167 |
statusLight.textContent = 'OFFLINE';
|
168 |
statusLight.className = 'status-offline';
|
169 |
});
|
170 |
|
171 |
socket.on('new_signal', (signal) => {
|
172 |
+
console.log('⚡️ New Signal Received:', signal);
|
173 |
document.getElementById('placeholder-row')?.remove();
|
174 |
|
175 |
const isPythCheaper = signal.pyth_price < signal.chainlink_price;
|
176 |
const newRow = opportunitiesTable.insertRow(0);
|
177 |
|
178 |
+
const assetInfo = ASSET_CONFIG[signal.asset] || { logo: '', link: '#' };
|
179 |
|
180 |
+
// --- THE CRITICAL FIX IS HERE ---
|
181 |
newRow.innerHTML = `
|
182 |
+
<td>
|
183 |
+
<div class="asset-cell">
|
184 |
+
<img src="${assetInfo.logo}" class="asset-logo" alt="${signal.asset} logo">
|
185 |
+
<a href="${assetInfo.link}" target="_blank">${signal.asset}/USD</a>
|
186 |
+
</div>
|
187 |
+
</td>
|
188 |
+
<td><span class="${isPythCheaper ? 'buy' : 'sell'}">${signal.pyth_price.toLocaleString('en-US', { style: 'currency', currency: 'USD' })}</span></td>
|
189 |
+
<td><span class="${!isPythCheaper ? 'buy' : 'sell'}">${signal.chainlink_price.toLocaleString('en-US', { style: 'currency', currency: 'USD' })}</span></td>
|
190 |
<td><strong>${signal.spread_pct.toFixed(3)}%</strong></td>
|
191 |
<td><span class="risk-${signal.risk.toLowerCase()}">${signal.risk}</span></td>
|
192 |
<td>${signal.strategy}</td>
|