feat: Dashboard-Tab Trump (Events, Positionen, Trades)

This commit is contained in:
2026-06-12 08:56:35 +00:00
parent 89b041eb6e
commit ed2fdf6c0a

View File

@@ -53,13 +53,14 @@
</head>
<body>
<header>
<h1>trade-kuns <small>Paper · Trend (BTC ETH SOL XRP) + Grid (XRP)</small></h1>
<h1>trade-kuns <small>Paper · Trend (BTC ETH SOL XRP) + Grid (XRP) + Trump</small></h1>
<div id="status"><span class="dot" style="background:var(--muted)"></span>lade…</div>
</header>
<nav class="tabs">
<button class="tab active" data-tab="trading">Trading</button>
<button class="tab" data-tab="grid">GridBot</button>
<button class="tab" data-tab="trump">Trump</button>
</nav>
<section id="tab-trading">
@@ -106,6 +107,16 @@
<div class="panel"><h2>Grid-Trades</h2><div id="grid-trades"></div></div>
</section>
<section id="tab-trump" hidden>
<div class="kpis" id="trump-cards"></div>
<div class="panel"><h2>Offene Positionen</h2><div id="trump-positions"></div></div>
<div class="panel"><h2>Events</h2><div id="trump-events"></div></div>
<div class="panel"><h2>Trades</h2><div id="trump-trades"></div></div>
</section>
<script>
const fmt = (n, d = 2) => n == null || Number.isNaN(n) ? '' : n.toLocaleString('de-DE', { minimumFractionDigits: d, maximumFractionDigits: d });
const fmtTs = (ts) => ts == null ? '' : new Date(ts).toLocaleString('de-DE', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' });
@@ -348,11 +359,13 @@ function tradeMarkers(trades, { withR = false, label = '' } = {}) {
const charts = {
trading: [], // wird unten befüllt
grid: [],
trump: [],
};
function showTab(name) {
document.querySelectorAll('.tab').forEach(b => b.classList.toggle('active', b.dataset.tab === name));
document.getElementById('tab-trading').hidden = name !== 'trading';
document.getElementById('tab-grid').hidden = name !== 'grid';
document.getElementById('tab-trump').hidden = name !== 'trump';
history.replaceState(null, '', '#' + name);
requestAnimationFrame(() => (charts[name] || []).forEach(c => c.redraw()));
}
@@ -399,13 +412,15 @@ async function renderTrendPrice() {
async function refresh() {
try {
const [pf, stats, trades, decisions, grid, gridTradesAll] = await Promise.all([
const [pf, stats, trades, decisions, grid, gridTradesAll, trump, trumpTradesAll] = await Promise.all([
fetch('/api/portfolio').then(r => r.json()),
fetch('/api/stats').then(r => r.json()),
fetch('/api/trades?limit=200').then(r => r.json()),
fetch('/api/decisions?limit=12').then(r => r.json()),
fetch('/api/grid').then(r => r.json()),
fetch('/api/trades?bot=grid&limit=200').then(r => r.json()),
fetch('/api/trump').then(r => r.json()),
fetch('/api/trades?bot=trump&limit=200').then(r => r.json()),
]);
lastTrades = trades;
lastPositions = pf.positions;
@@ -494,6 +509,42 @@ async function refresh() {
grid.trades.map(t => `<tr><td>${fmtTs(new Date(t.entryTs).getTime())}</td><td>${fmtTs(new Date(t.exitTs).getTime())}</td><td>${fmt(t.entryPrice, 4)}</td><td>${fmt(t.exitPrice, 4)}</td><td class="${cls(t.pnl)}">${sign(t.pnl)}</td><td>${t.exitReason}</td></tr>`),
'Noch keine Grid-Trades.');
// ── Trump-Tab ──
// Equity ≈ cash + Σ qty×entryPrice (Näherung; kein Marktpreis verfügbar im API)
const trumpPositions = trump.positions || [];
const trumpEvents = trump.events || [];
const trumpEquityApprox = (trump.cash || 0) + trumpPositions.reduce((s, p) => s + p.qty * p.entryPrice, 0);
const trumpPnl = trumpEquityApprox - (trump.startCapital || 0);
const evCount = trumpEvents.length;
document.getElementById('trump-cards').innerHTML =
kpi('Equity (ca.)', fmt(trumpEquityApprox) + ' $') +
kpi('PnL', sign(trumpPnl) + ' $', cls(trumpPnl)) +
kpi('Cash', fmt(trump.cash) + ' $') +
kpi('Offene Pos.', trumpPositions.length) +
kpi('Events', evCount >= 50 ? '50+' : evCount);
document.getElementById('trump-positions').innerHTML = table(
['Pair', 'Entry-Zeit', 'Entry-Preis', 'Qty', 'Exit fällig'],
trumpPositions.map(p => `<tr><td><span class="tag long">${p.pair}</span></td><td>${fmtTs(p.entryTs)}</td><td>${fmt(p.entryPrice, priceDec(p.entryPrice))}</td><td>${fmt(p.qty, 4)}</td><td>${fmtTs(p.exitDueTs)}</td></tr>`),
'Keine offenen Positionen.');
document.getElementById('trump-events').innerHTML = table(
['Zeit', 'Quelle', 'Coin', 'Instrument', 'Notional $', 'Ref'],
trumpEvents.map(e => {
const ref = e.ref
? e.source === 'onchain'
? `<a href="https://etherscan.io/tx/${e.ref}" target="_blank" style="color:var(--accent)">${e.ref.slice(0, 12)}…</a>`
: `<a href="${e.ref}" target="_blank" style="color:var(--accent)">${e.ref.slice(0, 24)}${e.ref.length > 24 ? '…' : ''}</a>`
: '';
return `<tr><td>${fmtTs(e.eventTs)}</td><td>${e.source ?? ''}</td><td>${e.token ?? ''}</td><td>${e.instrument ?? ''}</td><td>${e.notionalUsd != null ? fmt(e.notionalUsd) + ' $' : ''}</td><td style="text-align:left">${ref}</td></tr>`;
}),
'Keine Events vorhanden.');
document.getElementById('trump-trades').innerHTML = table(
['Entry', 'Exit', 'Entry-Preis', 'Exit-Preis', 'PnL $', 'Grund'],
trumpTradesAll.map(t => `<tr><td>${fmtTs(new Date(t.entryTs).getTime())}</td><td>${fmtTs(new Date(t.exitTs).getTime())}</td><td>${fmt(t.entryPrice, 4)}</td><td>${fmt(t.exitPrice, 4)}</td><td class="${cls(t.pnl)}">${sign(t.pnl)}</td><td>${t.exitReason}</td></tr>`),
'Noch keine Trump-Trades.');
const eng = pf.engine || {};
const ok = eng.lastCycleOk !== false;
document.getElementById('status').innerHTML =
@@ -505,6 +556,7 @@ async function refresh() {
}
if (location.hash === '#grid') showTab('grid');
else if (location.hash === '#trump') showTab('trump');
refresh();
setInterval(refresh, 30000);
let resizeT;