File size: 5,568 Bytes
097168d
6340f89
097168d
 
 
 
6340f89
9c7fae0
097168d
9c7fae0
 
 
d8c7fa5
9c7fae0
 
 
d8c7fa5
9c7fae0
d8c7fa5
9c7fae0
 
 
 
d8c7fa5
 
 
097168d
 
9c7fae0
097168d
9c7fae0
efd7324
9c7fae0
097168d
9c7fae0
097168d
 
 
 
 
6340f89
097168d
6340f89
 
097168d
 
efd7324
9c7fae0
097168d
 
 
 
efd7324
d0a6c56
9c7fae0
 
 
 
 
 
 
 
 
 
efd7324
 
9c7fae0
 
efd7324
 
 
9c7fae0
 
 
 
 
 
 
 
 
 
 
 
efd7324
 
9c7fae0
efd7324
 
9c7fae0
 
 
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
90
91
92
93
94
95
96
97
98
99
100
101
<!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; padding: 1rem; }
        .container { max-width: 1280px; margin: 0 auto; }
        header { text-align: center; margin-bottom: 1.5rem; }
        h1 { color: #38BDF8; margin-bottom: 0; }
        .status-bar { font-size: 12px; color: #9CA3AF; text-align: right; margin-bottom: 1rem; }
        .status-online { color: #34D399; } .status-offline { color: #F87171; }
        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; }
        tbody tr { animation: fadeIn 0.5s ease-out; }
        @keyframes fadeIn { from { background-color: rgba(52, 211, 153, 0.2); } to { background-color: transparent; } }
        .asset-cell { display: grid; grid-template-columns: auto 1fr; gap: 12px; align-items: center; }
        .asset-logo { width: 24px; height: 24px; }
        .asset-cell a { color: inherit; text-decoration: none; font-weight: bold; }
    </style>
</head>
<body>
    <main class="container">
        <header><h1>Sentinel Arbitrage Engine</h1></header>
        <div class="status-bar">
            Engine Status: <span id="status-light" class="status-offline">OFFLINE</span> | Last Signal: <span id="last-update-time">--:--:--</span>
        </div>
        <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;">Connecting to engine...</td></tr>
                </tbody>
            </table>
        </article>
    </main>
    <script>
        const ASSET_CONFIG = {
            'BTC': { logo: 'https://s2.coinmarketcap.com/static/img/coins/64x64/1.png' },
            'ETH': { logo: 'https://s2.coinmarketcap.com/static/img/coins/64x64/1027.png' },
            'SOL': { logo: 'https://s2.coinmarketcap.com/static/img/coins/64x64/5426.png' },
            'XRP': { logo: 'https://s2.coinmarketcap.com/static/img/coins/64x64/52.png' },
            'DOGE': { logo: 'https://s2.coinmarketcap.com/static/img/coins/64x64/74.png' },
            'ADA': { logo: 'https://s2.coinmarketcap.com/static/img/coins/64x64/2010.png' },
            'AVAX': { logo: 'https://s2.coinmarketcap.com/static/img/coins/64x64/5805.png' },
            'LINK': { logo: 'https://s2.coinmarketcap.com/static/img/coins/64x64/1975.png' },
            'DOT': { logo: 'https://s2.coinmarketcap.com/static/img/coins/64x64/6636.png' },
            'MATIC': { logo: 'https://s2.coinmarketcap.com/static/img/coins/64x64/3890.png' }
        };

        const socket = io();
        const statusLight = document.getElementById('status-light');
        const opportunitiesTable = document.getElementById('opportunities-table');
        const lastUpdateTime = document.getElementById('last-update-time');

        socket.on('connect', () => {
            statusLight.textContent = 'ONLINE';
            statusLight.className = 'status-online';
            document.getElementById('placeholder-row').cells[0].textContent = 'Monitoring for oracle dislocations...';
        });

        socket.on('disconnect', () => {
            statusLight.textContent = 'OFFLINE';
            statusLight.className = 'status-offline';
        });

        socket.on('new_signal', (signal) => {
            document.getElementById('placeholder-row')?.remove();
            const newRow = opportunitiesTable.insertRow(0);
            const assetInfo = ASSET_CONFIG[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>
            `;
            
            lastUpdateTime.textContent = new Date(signal.timestamp).toLocaleTimeString('en-US');
        });
    </script>
</body>
</html>