Das WebGUI konnte bisher Dashboard, Konten, Jobs, Logs und Einstellungen.
Die vier Strategie- und Analysemodule waren nur in der Avalonia-Oberflaeche
erreichbar - wer den Server aus der Ferne bediente, sah sie nicht.
Fuenf neue Endpunktgruppen holen sie herein:
/api/analytics KPIs, Equity-Kurve, PnL je Modul und Tag,
durchsuchbare Trade-Historie mit Seitenlauf
/api/modules/copytrading Master-Trader (CRUD), offene und
geschlossene Trades, Risikolimits je Konto
/api/modules/resolutionfarming Scanner-Kandidaten, Positionen, Historie,
Farming-Parameter je Konto
/api/modules/supervisor Profile, Agentenfragen, Berichtsarchiv,
Signal-Dossiers, Counterfactuals
/api/modules/accounting BWA-Periodenabrechnung, Ledger-Journal,
PDF- und CSV-Export, Ingest-Laeufe
Dazu im Bestand:
- Dashboard bekommt /overview-widgets: Modul-KPIs (heute/7T/30T), auffaellige
Trades der letzten 24 Stunden, Warnungen und Fehler des Tages, den letzten
Supervisor-Bericht.
- Die Kontenliste zeigt 3-Tage-PnL, Winrate, Gesamtergebnis und die
beteiligten Module statt nur Salden.
- Jobs lassen sich ueber /toggle und /state ein- und ausschalten, nicht nur
ausloesen.
Die Oberflaeche bleibt ohne Fremdbibliotheken: alle Diagramme sind Inline-SVG,
kein CDN, kein npm. Alle neuen Pfade liegen unter /api/ und damit hinter der
bestehenden Token-Pruefung.
Zwei Fehler nebenbei behoben:
- AccountingReportService.ResolveCurrency lief in eine NullReferenceException,
wenn der FX-Dienst nicht gesetzt war. Betrifft jeden EUR-Aufruf ohne
geladene EZB-Kurse.
- Ein Master-Trader, dessen Name ein Apostroph enthaelt, hatte einen toten
Loeschen-Knopf: escapeHtml laesst ' unberuehrt, und im onclick-Attribut
beendete das Zeichen das JavaScript-Literal vorzeitig. Laengerer Text mit
Anfuehrungszeichen konnte darueber eigenen Code einschleusen. Neu setzt
jsArg() den Wert als JSON-Literal ein; geprueft mit
O'Brien "quote" <b>bold</b> \ backslash.
McpLightServerTests weicht jetzt aus, wenn HttpListener mangels URL-ACL nicht
binden darf, statt den Lauf scheitern zu lassen.
Geprueft auf der Linux-Test-VM (Ubuntu 26.04, .NET 10): Build ohne Fehler,
533 von 533 Tests bestanden, alle 11 Ansichten und 15 Unteransichten geladen,
alle Endpunkte mit 200 beantwortet, Schreibwege bis in die Datenbank
nachverfolgt, PDF- und CSV-Export gueltig, SSE-Logstrom live.
Offene Befunde aus der Abnahme liegen als #532 (Kopfleiste laeuft unter
1623 px ueber), #533 (EUR-PDF ohne EZB-Kurse liefert Nullbetraege) und #534
(Einstellungen melden Erfolg trotz gescheitertem Speichern) im Bugtracker.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1237 lines
74 KiB
HTML
1237 lines
74 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>PolyTrader Web</title>
|
||
<link rel="stylesheet" href="/css/app.css">
|
||
</head>
|
||
<body>
|
||
<header class="app-header">
|
||
<div class="header-brand">
|
||
<span>📈</span>
|
||
<span>PolyTrader</span>
|
||
<span style="font-size: 11px; padding: 2px 6px; background: var(--accent-soft); color: var(--accent); border-radius: 4px; font-weight: normal;">WebGUI</span>
|
||
</div>
|
||
|
||
<nav class="header-nav">
|
||
<button class="nav-link active" onclick="switchView('dashboard')">Dashboard</button>
|
||
<button class="nav-link" onclick="switchView('analytics')">Analytics</button>
|
||
<button class="nav-link" onclick="switchView('copytrading')">CopyTrading</button>
|
||
<button class="nav-link" onclick="switchView('resolutionfarming')">Resolution Farming</button>
|
||
<button class="nav-link" onclick="switchView('supervisor')">Supervisor</button>
|
||
<button class="nav-link" onclick="switchView('accounting')">Accounting</button>
|
||
<button class="nav-link" onclick="switchView('accounts')">Konten</button>
|
||
<button class="nav-link" onclick="switchView('jobs')">Jobs</button>
|
||
<button class="nav-link" onclick="switchView('logs')">Terminal / Logs</button>
|
||
<button class="nav-link" onclick="switchView('modules')">Module</button>
|
||
<button class="nav-link" onclick="switchView('settings')">Einstellungen</button>
|
||
</nav>
|
||
|
||
<div class="header-actions">
|
||
<div class="status-indicator" title="Polymarket / Alchemy Connection">
|
||
<span class="dot" id="dotAlchemy"></span>
|
||
<span>WSS</span>
|
||
</div>
|
||
<div class="status-indicator" title="Mullvad VPN Status">
|
||
<span class="dot" id="dotVpn"></span>
|
||
<span>VPN</span>
|
||
</div>
|
||
<div class="status-indicator" title="Watchdog Heartbeat">
|
||
<span class="dot" id="dotWatchdog"></span>
|
||
<span>Watchdog</span>
|
||
</div>
|
||
<button class="btn btn-secondary" style="padding: 4px 10px; font-size: 12px;" onclick="logout()">Abmelden</button>
|
||
</div>
|
||
</header>
|
||
|
||
<main class="app-main">
|
||
<!-- VIEW: DASHBOARD -->
|
||
<section id="view-dashboard" class="view-panel active">
|
||
<div class="grid-4">
|
||
<div class="card">
|
||
<div class="card-title">Gesamt PnL</div>
|
||
<div class="card-value" id="valGlobalPnl">0.00 $</div>
|
||
<div class="card-sub">Über alle aktiven Module</div>
|
||
</div>
|
||
<div class="card">
|
||
<div class="card-title">USDC Guthaben</div>
|
||
<div class="card-value" id="valTotalUsdc">0.00 $</div>
|
||
<div class="card-sub" id="valAccountCount">0 Konten aktiv</div>
|
||
</div>
|
||
<div class="card">
|
||
<div class="card-title">Portfolio-Gesamtwert</div>
|
||
<div class="card-value" id="valPortfolioValue">0.00 $</div>
|
||
<div class="card-sub">Guthaben + Positionen</div>
|
||
</div>
|
||
<div class="card">
|
||
<div class="card-title">Notfall-Pause</div>
|
||
<button class="btn btn-danger" id="btnPause" style="width: 100%; margin-top: 6px;" onclick="togglePause()">
|
||
Trading pausieren
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="grid-2">
|
||
<div class="card">
|
||
<div class="card-title">Live Trading Modus</div>
|
||
<div style="font-size: 13px; color: var(--muted);">Echtgeld-Ausführung auf Polymarket</div>
|
||
<div class="toggle-group" id="groupLiveTrading">
|
||
<button class="btn-toggle" onclick="setTradingMode('live', 'Inactive')">Inaktiv</button>
|
||
<button class="btn-toggle" onclick="setTradingMode('live', 'SellOnly')">Nur Verkauf</button>
|
||
<button class="btn-toggle" onclick="setTradingMode('live', 'Active')">Aktiv</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-title">Demo Trading Modus</div>
|
||
<div style="font-size: 13px; color: var(--muted);">Papertrading und Simulation</div>
|
||
<div class="toggle-group" id="groupDemoTrading">
|
||
<button class="btn-toggle" onclick="setTradingMode('demo', 'Inactive')">Inaktiv</button>
|
||
<button class="btn-toggle" onclick="setTradingMode('demo', 'SellOnly')">Nur Verkauf</button>
|
||
<button class="btn-toggle" onclick="setTradingMode('demo', 'Active')">Aktiv</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Modul-KPIs -->
|
||
<div class="dashboard-section-title">Modul-KPIs</div>
|
||
<div class="kpi-tiles-grid" id="dashModuleKpis">
|
||
<div class="card" style="padding: 12px; color: var(--muted); font-size: 13px;">Lade Modul-KPIs …</div>
|
||
</div>
|
||
|
||
<!-- Account-Übersicht -->
|
||
<div class="dashboard-section-title">Account-Übersicht</div>
|
||
<div class="table-container">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Account</th>
|
||
<th>Module</th>
|
||
<th>Polymarket</th>
|
||
<th>Wallet (USDC)</th>
|
||
<th>3T PnL</th>
|
||
<th>3T Winrate %</th>
|
||
<th>Overall P/L</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="tblDashAccounts">
|
||
<tr><td colspan="7" style="text-align: center; color: var(--muted);">Lade Konten-Übersicht …</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- Live-Überblick Widgets (3 Spalten) -->
|
||
<div class="dashboard-section-title">Live-Überblick</div>
|
||
<div class="grid-3">
|
||
<!-- Auffällige Trades (24h) -->
|
||
<div class="card widget-card">
|
||
<div class="card-title">
|
||
<span>Auffällige Trades (24h)</span>
|
||
<span style="font-size: 11px; color: var(--muted);" id="badgeNotableCount">0</span>
|
||
</div>
|
||
<div class="widget-table-container">
|
||
<table class="compact-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Modul</th>
|
||
<th>Markt</th>
|
||
<th>PnL</th>
|
||
<th>PnL %</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="tblNotableTrades">
|
||
<tr><td colspan="4" style="text-align: center; color: var(--muted);">Lade Trades …</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Warnungen & Fehler (heute) -->
|
||
<div class="card widget-card">
|
||
<div class="card-title">
|
||
<span id="titleAlerts">Warnungen & Fehler (heute)</span>
|
||
<span style="font-size: 11px; color: var(--muted);" id="badgeAlertsCount">0</span>
|
||
</div>
|
||
<div class="widget-logs-container" id="containerAlerts">
|
||
<div style="color: var(--muted); padding: 8px 0; text-align: center;">Keine Warnungen heute.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Supervisor-KI (letzter Bericht) -->
|
||
<div class="card widget-card">
|
||
<div class="card-title">
|
||
<span id="titleSupervisor">Supervisor-KI (letzter Bericht)</span>
|
||
<span style="font-size: 11px; color: var(--muted);" id="badgeSupervisorTime">—</span>
|
||
</div>
|
||
<div class="supervisor-snippet" id="snippetSupervisor">
|
||
Lade Supervisor-Bericht …
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- VIEW: ANALYTICS -->
|
||
<section id="view-analytics" class="view-panel">
|
||
<!-- Filter Toolbar -->
|
||
<div class="analytics-toolbar">
|
||
<div class="toolbar-group">
|
||
<button class="btn btn-primary btn-sm" onclick="loadAnalytics()">Aktualisieren</button>
|
||
<div class="toolbar-item">
|
||
<label for="selAnalyticsAccount">Konto:</label>
|
||
<select id="selAnalyticsAccount" class="form-input form-select" onchange="onAnalyticsFilterChanged()">
|
||
<option value="-1">Alle Konten</option>
|
||
</select>
|
||
</div>
|
||
<div class="toolbar-item">
|
||
<label for="selAnalyticsModule">Modul:</label>
|
||
<select id="selAnalyticsModule" class="form-input form-select" onchange="onAnalyticsFilterChanged()">
|
||
<option value="Alle Module">Alle Module</option>
|
||
</select>
|
||
</div>
|
||
<div class="toolbar-item">
|
||
<label for="selAnalyticsMode">Modus:</label>
|
||
<select id="selAnalyticsMode" class="form-input form-select" onchange="onAnalyticsFilterChanged()">
|
||
<option value="Alle">Alle</option>
|
||
<option value="Live">Live</option>
|
||
<option value="Demo">Demo</option>
|
||
</select>
|
||
</div>
|
||
<div class="toolbar-item">
|
||
<label for="selAnalyticsRange">Zeitraum:</label>
|
||
<select id="selAnalyticsRange" class="form-input form-select" onchange="onAnalyticsFilterChanged()">
|
||
<option value="7">7 Tage</option>
|
||
<option value="30" selected>30 Tage</option>
|
||
<option value="90">90 Tage</option>
|
||
<option value="0">Alle</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="analytics-subnav">
|
||
<button class="subnav-tab active" id="tabBtnAnalyticsCharts" onclick="switchAnalyticsSubTab('charts')">Auswertung & Diagramme</button>
|
||
<button class="subnav-tab" id="tabBtnAnalyticsHistory" onclick="switchAnalyticsSubTab('history')">Tradehistorie</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- SUB-TAB 1: CHARTS & KPIS -->
|
||
<div id="analyticsSubTabCharts" class="analytics-subtab active">
|
||
<!-- 5 KPI Cards -->
|
||
<div class="grid-5" style="margin-bottom: 20px;">
|
||
<div class="card kpi-card">
|
||
<div class="card-title">Netto-PnL</div>
|
||
<div class="card-value" id="kpiNetPnl">0.00 $</div>
|
||
<div class="card-sub">Realisierter Gewinn/Verlust</div>
|
||
</div>
|
||
<div class="card kpi-card">
|
||
<div class="card-title">Winrate</div>
|
||
<div class="card-value" id="kpiWinRate">0.0 %</div>
|
||
<div class="card-sub">Anteil profitabler Trades</div>
|
||
</div>
|
||
<div class="card kpi-card">
|
||
<div class="card-title">Trades</div>
|
||
<div class="card-value" id="kpiTradeCount">0</div>
|
||
<div class="card-sub">Ausgeführte Abschlüsse</div>
|
||
</div>
|
||
<div class="card kpi-card">
|
||
<div class="card-title">Ø PnL / Trade</div>
|
||
<div class="card-value" id="kpiAvgPnl">0.00 $</div>
|
||
<div class="card-sub">Durchschnittliches Ergebnis</div>
|
||
</div>
|
||
<div class="card kpi-card">
|
||
<div class="card-title">Profit-Faktor</div>
|
||
<div class="card-value" id="kpiProfitFactor">0.00</div>
|
||
<div class="card-sub">Bruttogewinn / -verlust</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 3 Charts Grid -->
|
||
<!-- Top Chart: Equity Curve (Full Width) -->
|
||
<div class="card chart-card" style="margin-bottom: 20px;">
|
||
<div class="card-title">
|
||
<span>Equity-Kurve (kumulierter PnL)</span>
|
||
<span style="font-size: 11px; color: var(--muted);" id="lblEquityTradesCount">0 Datenpunkte</span>
|
||
</div>
|
||
<div class="chart-container" id="containerEquityChart">
|
||
<svg id="svgEquityChart" class="chart-svg"></svg>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Bottom 2 Charts: PnL by Module & PnL by Day -->
|
||
<div class="grid-2">
|
||
<div class="card chart-card">
|
||
<div class="card-title">PnL je Modul</div>
|
||
<div class="chart-container" id="containerModuleChart">
|
||
<svg id="svgModuleChart" class="chart-svg"></svg>
|
||
</div>
|
||
</div>
|
||
<div class="card chart-card">
|
||
<div class="card-title">PnL je Tag</div>
|
||
<div class="chart-container" id="containerDayChart">
|
||
<svg id="svgDayChart" class="chart-svg"></svg>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- SUB-TAB 2: TRADEHISTORIE -->
|
||
<div id="analyticsSubTabHistory" class="analytics-subtab" style="display: none;">
|
||
<!-- Filter Bar -->
|
||
<div class="history-toolbar">
|
||
<div style="display: flex; gap: 12px; align-items: center; flex-wrap: wrap;">
|
||
<div class="toolbar-item" style="flex: 1; min-width: 250px;">
|
||
<label for="tbHistorySearch">Suche:</label>
|
||
<input type="text" id="tbHistorySearch" class="form-input" placeholder="Markt oder Outcome suchen …" oninput="onHistorySearchInput()">
|
||
</div>
|
||
<div class="toolbar-item">
|
||
<label for="selHistoryWinLoss">Ergebnis:</label>
|
||
<select id="selHistoryWinLoss" class="form-input form-select" onchange="onHistoryWinLossChanged()">
|
||
<option value="Alle">Alle</option>
|
||
<option value="Gewinner">Nur Gewinner</option>
|
||
<option value="Verlierer">Nur Verlierer</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Trades Table -->
|
||
<div class="table-container" style="margin-top: 14px;">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Zeitpunkt</th>
|
||
<th>Modul</th>
|
||
<th>Account</th>
|
||
<th>Modus</th>
|
||
<th>Markt</th>
|
||
<th>Outcome</th>
|
||
<th>Side</th>
|
||
<th>Entry</th>
|
||
<th>Exit</th>
|
||
<th>Size</th>
|
||
<th>PnL</th>
|
||
<th>PnL %</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="tblAnalyticsTrades">
|
||
<tr><td colspan="12" style="text-align: center; color: var(--muted);">Lade Trades …</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- Pagination -->
|
||
<div class="pagination-bar" id="historyPagination">
|
||
<span id="lblPaginationInfo" style="color: var(--muted); font-size: 13px;">Zeige 0 von 0 Trades</span>
|
||
<div style="display: flex; gap: 6px;">
|
||
<button class="btn btn-secondary btn-sm" id="btnPrevPage" onclick="changeAnalyticsPage(-1)">◀ Vorherige</button>
|
||
<span id="lblCurrentPage" style="padding: 4px 10px; font-weight: 600; font-size: 13px;">1</span>
|
||
<button class="btn btn-secondary btn-sm" id="btnNextPage" onclick="changeAnalyticsPage(1)">Nächste ▶</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- VIEW: COPYTRADING -->
|
||
<section id="view-copytrading" class="view-panel">
|
||
<div class="module-toolbar">
|
||
<div style="display: flex; gap: 8px; align-items: center;">
|
||
<span style="font-size: 16px; font-weight: 700; color: var(--text);">CopyTrading Modul</span>
|
||
<span class="badge" style="background: rgba(34, 197, 94, 0.15); color: var(--positive); border: 1px solid var(--positive);">Aktiv</span>
|
||
</div>
|
||
<div class="module-tabs">
|
||
<button class="module-tab-btn active" id="ctTabBtn-traders" onclick="switchCtTab('traders')">Master-Trader</button>
|
||
<button class="module-tab-btn" id="ctTabBtn-open" onclick="switchCtTab('open')">Offene Positionen</button>
|
||
<button class="module-tab-btn" id="ctTabBtn-closed" onclick="switchCtTab('closed')">Geschlossene Trades</button>
|
||
<button class="module-tab-btn" id="ctTabBtn-settings" onclick="switchCtTab('settings')">Account-Einstellungen</button>
|
||
</div>
|
||
<div style="margin-left: auto; display: flex; gap: 8px;">
|
||
<button class="btn btn-secondary" onclick="refreshCurrentCtTab()">Aktualisieren</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- CT SUBTAB: TRADERS -->
|
||
<div id="ctTab-traders" class="ct-tab-content active">
|
||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 14px;">
|
||
<div style="font-size: 14px; color: var(--muted);" id="ctTradersSummary">Lade Master-Trader …</div>
|
||
<button class="btn btn-primary" onclick="openTraderModal(null)">+ Neuer Master-Trader</button>
|
||
</div>
|
||
<div class="table-container">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th style="width: 50px;">ID</th>
|
||
<th>Name</th>
|
||
<th>Wallet</th>
|
||
<th>Kategorie</th>
|
||
<th>Status</th>
|
||
<th>Auto-Pause</th>
|
||
<th>Maker</th>
|
||
<th style="text-align: right;">Winrate (30T)</th>
|
||
<th style="text-align: right;">Copy-PnL (30T)</th>
|
||
<th style="text-align: right;">Profit-Faktor</th>
|
||
<th>Konten</th>
|
||
<th style="text-align: center; width: 140px;">Aktionen</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="ctTradersTbody">
|
||
<tr><td colspan="12" style="text-align: center; color: var(--muted);">Lade Master-Trader …</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- CT SUBTAB: OPEN TRADES -->
|
||
<div id="ctTab-open" class="ct-tab-content" style="display: none;">
|
||
<div style="margin-bottom: 14px; font-size: 13px; color: var(--muted);" id="ctOpenSummary">Lade offene Positionen …</div>
|
||
<div class="table-container">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Konto</th>
|
||
<th>Master-Trader</th>
|
||
<th>Marktfrage</th>
|
||
<th>Outcome</th>
|
||
<th>Side</th>
|
||
<th style="text-align: right;">Einstieg</th>
|
||
<th style="text-align: right;">Aktuell</th>
|
||
<th style="text-align: right;">Shares</th>
|
||
<th style="text-align: right;">Einsatz</th>
|
||
<th style="text-align: right;">Buchgewinn</th>
|
||
<th>Status</th>
|
||
<th>Eröffnet</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="ctOpenTbody">
|
||
<tr><td colspan="12" style="text-align: center; color: var(--muted);">Lade offene Positionen …</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- CT SUBTAB: CLOSED TRADES -->
|
||
<div id="ctTab-closed" class="ct-tab-content" style="display: none;">
|
||
<div class="module-toolbar" style="margin-top: 0; padding: 10px 14px;">
|
||
<div style="display: flex; gap: 12px; align-items: center; flex-wrap: wrap; flex: 1;">
|
||
<div class="toolbar-item">
|
||
<label for="ctClosedFilterTrader">Master:</label>
|
||
<select id="ctClosedFilterTrader" class="form-input form-select" onchange="loadCtClosedTrades(1)">
|
||
<option value="0">Alle Master</option>
|
||
</select>
|
||
</div>
|
||
<div class="toolbar-item">
|
||
<label for="ctClosedFilterResult">Ergebnis:</label>
|
||
<select id="ctClosedFilterResult" class="form-input form-select" onchange="loadCtClosedTrades(1)">
|
||
<option value="Alle">Alle</option>
|
||
<option value="Gewinner">Nur Gewinner</option>
|
||
<option value="Verlierer">Nur Verlierer</option>
|
||
</select>
|
||
</div>
|
||
<div class="toolbar-item" style="flex: 1; min-width: 200px;">
|
||
<input type="text" id="ctClosedSearch" class="form-input" placeholder="Suche in Markt / Outcome …" oninput="debounceCtClosedSearch()">
|
||
</div>
|
||
</div>
|
||
<div style="font-size: 13px; color: var(--muted);" id="ctClosedSummary">0 Trades</div>
|
||
</div>
|
||
<div class="table-container">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>ID</th>
|
||
<th>Konto</th>
|
||
<th>Master-Trader</th>
|
||
<th>Marktfrage</th>
|
||
<th>Outcome</th>
|
||
<th>Side</th>
|
||
<th style="text-align: right;">Einstieg</th>
|
||
<th style="text-align: right;">Exit</th>
|
||
<th style="text-align: right;">Shares</th>
|
||
<th style="text-align: right;">Realisierter PnL</th>
|
||
<th style="text-align: right;">Rendite</th>
|
||
<th>Geschlossen</th>
|
||
<th>Grund</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="ctClosedTbody">
|
||
<tr><td colspan="13" style="text-align: center; color: var(--muted);">Lade Trades …</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="pagination-bar" id="ctClosedPagination">
|
||
<span id="ctClosedPageInfo" style="font-size: 13px; color: var(--muted);">Seite 1 von 1</span>
|
||
<div style="display: flex; gap: 6px;">
|
||
<button class="btn btn-secondary btn-sm" id="btnCtClosedPrev" onclick="changeCtClosedPage(-1)">◀ Vorherige</button>
|
||
<button class="btn btn-secondary btn-sm" id="btnCtClosedNext" onclick="changeCtClosedPage(1)">Nächste ▶</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- CT SUBTAB: SETTINGS -->
|
||
<div id="ctTab-settings" class="ct-tab-content" style="display: none;">
|
||
<div class="card settings-form" style="max-width: 900px; margin: 0 auto;">
|
||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 18px; border-bottom: 1px solid var(--border); padding-bottom: 12px;">
|
||
<div style="display: flex; gap: 10px; align-items: center;">
|
||
<label style="font-size: 13px; font-weight: 600;">Konto wählen:</label>
|
||
<select id="ctSettingsAccountSelect" class="form-input form-select" style="min-width: 220px;" onchange="loadCtSettingsForSelectedAccount()"></select>
|
||
</div>
|
||
<div id="ctSettingsStatus" style="font-size: 13px; color: var(--positive); display: none;">✓ Gespeichert</div>
|
||
</div>
|
||
<form id="ctSettingsForm" onsubmit="saveCtSettings(event)">
|
||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 18px;">
|
||
<div class="form-row">
|
||
<label for="ctPerMarketLimit">Limit pro Markt (%)</label>
|
||
<input type="number" step="0.1" id="ctPerMarketLimit" class="form-input" required>
|
||
<div class="form-desc">Max. Einsatz in einen einzelnen Markt (als % des Guthabens).</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<label for="ctPerMasterLimit">Limit pro Master (%)</label>
|
||
<input type="number" step="0.1" id="ctPerMasterLimit" class="form-input" required>
|
||
<div class="form-desc">Max. gleichzeitiger Gesamteinsatz für einen Master-Trader.</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<label for="ctMaxBuyPrice">Max. Kaufpreis (0–1)</label>
|
||
<input type="number" step="0.01" id="ctMaxBuyPrice" class="form-input" min="0" max="1" required>
|
||
<div class="form-desc">Preis-Obergrenze (z. B. 0.98 = 98 ¢).</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<label for="ctMaxPriceDiff">Max. Preisaufschlag BUY (%)</label>
|
||
<input type="number" step="0.1" id="ctMaxPriceDiff" class="form-input" required>
|
||
<div class="form-desc">Maximaler Limit-Aufschlag über dem Master-Einstiegspreis.</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<label for="ctTime6h">Limit < 6h Restlaufzeit (%)</label>
|
||
<input type="number" step="0.1" id="ctTime6h" class="form-input" required>
|
||
<div class="form-desc">Exposure-Deckel für kurzfristig auflösende Märkte.</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<label for="ctTime24h">Limit 6–24h Restlaufzeit (%)</label>
|
||
<input type="number" step="0.1" id="ctTime24h" class="form-input" required>
|
||
<div class="form-desc">Exposure-Deckel für Märkte mit 6 bis 24h Restlaufzeit.</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<label for="ctTime72h">Limit 24–72h Restlaufzeit (%)</label>
|
||
<input type="number" step="0.1" id="ctTime72h" class="form-input" required>
|
||
<div class="form-desc">Exposure-Deckel für Märkte mit 24 bis 72h Restlaufzeit.</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<label for="ctTimeNone">Limit > 72h / kein Datum (%)</label>
|
||
<input type="number" step="0.1" id="ctTimeNone" class="form-input" required>
|
||
<div class="form-desc">Exposure-Deckel für Märkte mit > 72h Laufzeit.</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<label for="ctProfitTarget">Take-Profit (% Gewinn)</label>
|
||
<input type="number" step="0.1" id="ctProfitTarget" class="form-input" required>
|
||
<div class="form-desc">Take-Profit-Schwelle in % Gewinn (9999 = deaktiviert).</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<label for="ctPreRedeemLimit">Pre-Redeem-Schwelle (0–1)</label>
|
||
<input type="number" step="0.001" id="ctPreRedeemLimit" class="form-input" min="0" max="1" required>
|
||
<div class="form-desc">Vorzeitige Glattstellung (z. B. 0.995 = 99,5 ¢, 0 = aus).</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<label for="ctSellFloorPct">SELL-Floor (%)</label>
|
||
<input type="number" step="0.1" id="ctSellFloorPct" class="form-input" required>
|
||
<div class="form-desc">Mindest-Verkaufspreis = Master-Exit minus diesen Prozentsatz.</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<label for="ctMaxSpreadPct">Max. Spread BUY (%)</label>
|
||
<input type="number" step="0.1" id="ctMaxSpreadPct" class="form-input" required>
|
||
<div class="form-desc">Orderbuch-Filter gegen überhöhten Spread.</div>
|
||
</div>
|
||
</div>
|
||
<div style="margin-top: 20px; display: flex; gap: 10px; align-items: center;">
|
||
<button type="submit" class="btn btn-primary">Einstellungen speichern</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- VIEW: RESOLUTION FARMING -->
|
||
<section id="view-resolutionfarming" class="view-panel">
|
||
<div class="module-toolbar">
|
||
<div style="display: flex; gap: 8px; align-items: center;">
|
||
<span style="font-size: 16px; font-weight: 700; color: var(--text);">Resolution Farming</span>
|
||
<span class="badge badge-accent">Favoriten-Arbitrage</span>
|
||
</div>
|
||
<div class="toolbar-item">
|
||
<label for="rfAccountSelect">Konto:</label>
|
||
<select id="rfAccountSelect" class="form-input form-select" style="min-width: 180px;" onchange="loadRfForSelectedAccount()"></select>
|
||
</div>
|
||
<div class="module-tabs">
|
||
<button class="module-tab-btn active" id="rfTabBtn-candidates" onclick="switchRfTab('candidates')">Kandidaten</button>
|
||
<button class="module-tab-btn" id="rfTabBtn-positions" onclick="switchRfTab('positions')">Offene Positionen</button>
|
||
<button class="module-tab-btn" id="rfTabBtn-history" onclick="switchRfTab('history')">Historie</button>
|
||
<button class="module-tab-btn" id="rfTabBtn-settings" onclick="switchRfTab('settings')">Einstellungen</button>
|
||
</div>
|
||
<div style="margin-left: auto; display: flex; gap: 8px;">
|
||
<button class="btn btn-secondary" onclick="refreshCurrentRfTab()">Aktualisieren</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- RF SUBTAB: CANDIDATES -->
|
||
<div id="rfTab-candidates" class="rf-tab-content active">
|
||
<div style="margin-bottom: 14px; font-size: 13px; color: var(--muted);" id="rfCandidatesSummary">Lade Marktkandidaten …</div>
|
||
<div class="table-container">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Zeitpunkt</th>
|
||
<th>Marktfrage</th>
|
||
<th>Outcome</th>
|
||
<th>Kategorie</th>
|
||
<th style="text-align: right;">Ask</th>
|
||
<th style="text-align: right;">Fee (bps)</th>
|
||
<th style="text-align: right;">Net Edge %</th>
|
||
<th style="text-align: right;">Score</th>
|
||
<th>Auflösung</th>
|
||
<th>Status</th>
|
||
<th>Ablehnungsgrund</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="rfCandidatesTbody">
|
||
<tr><td colspan="11" style="text-align: center; color: var(--muted);">Lade Kandidaten …</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- RF SUBTAB: POSITIONS -->
|
||
<div id="rfTab-positions" class="rf-tab-content" style="display: none;">
|
||
<div style="margin-bottom: 14px; font-size: 13px; color: var(--muted);" id="rfPositionsSummary">Lade offene Positionen …</div>
|
||
<div class="table-container">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Konto</th>
|
||
<th>Marktfrage</th>
|
||
<th>Outcome</th>
|
||
<th>Kategorie</th>
|
||
<th>Cluster</th>
|
||
<th style="text-align: right;">Einstieg</th>
|
||
<th style="text-align: right;">Shares</th>
|
||
<th style="text-align: right;">Einsatz (USDC)</th>
|
||
<th>Eröffnet</th>
|
||
<th>Enddatum</th>
|
||
<th>Status</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="rfPositionsTbody">
|
||
<tr><td colspan="11" style="text-align: center; color: var(--muted);">Lade Positionen …</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- RF SUBTAB: HISTORY -->
|
||
<div id="rfTab-history" class="rf-tab-content" style="display: none;">
|
||
<div class="module-toolbar" style="margin-top: 0; padding: 10px 14px;">
|
||
<div class="toolbar-item" style="flex: 1; min-width: 250px;">
|
||
<input type="text" id="rfHistorySearch" class="form-input" placeholder="Suche in Markt / Outcome / Kategorie …" oninput="debounceRfHistorySearch()">
|
||
</div>
|
||
<div style="font-size: 13px; color: var(--muted);" id="rfHistorySummary">0 Trades</div>
|
||
</div>
|
||
<div class="table-container">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>ID</th>
|
||
<th>Konto</th>
|
||
<th>Marktfrage</th>
|
||
<th>Outcome</th>
|
||
<th>Kategorie</th>
|
||
<th style="text-align: right;">Einstieg</th>
|
||
<th style="text-align: right;">Exit</th>
|
||
<th style="text-align: right;">Shares</th>
|
||
<th style="text-align: right;">Realisierter PnL</th>
|
||
<th style="text-align: right;">Rendite</th>
|
||
<th style="text-align: right;">Gebühren</th>
|
||
<th>Geschlossen</th>
|
||
<th>Redeem-Status</th>
|
||
<th>Grund</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="rfHistoryTbody">
|
||
<tr><td colspan="14" style="text-align: center; color: var(--muted);">Lade Historie …</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- RF SUBTAB: SETTINGS -->
|
||
<div id="rfTab-settings" class="rf-tab-content" style="display: none;">
|
||
<div class="card settings-form" style="max-width: 900px; margin: 0 auto;">
|
||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 18px; border-bottom: 1px solid var(--border); padding-bottom: 12px;">
|
||
<div style="font-size: 14px; font-weight: 600;" id="rfSettingsAccountTitle">Einstellungen für Konto</div>
|
||
<div id="rfSettingsStatus" style="font-size: 13px; color: var(--positive); display: none;">✓ Gespeichert</div>
|
||
</div>
|
||
<form id="rfSettingsForm" onsubmit="saveRfSettings(event)">
|
||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 18px;">
|
||
<div class="form-row" style="grid-column: span 2;">
|
||
<label class="checkbox-label">
|
||
<input type="checkbox" id="rfEnabled">
|
||
<strong>Modul aktiv</strong> (Schaltet das ResolutionFarming für diesen Account scharf)
|
||
</label>
|
||
<div class="form-desc">Bei deaktiviertem Schalter wird nur im Hintergrund gescannt (Read-Only).</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<label for="rfMinPrice">Min. Preis (0–1)</label>
|
||
<input type="number" step="0.01" id="rfMinPrice" class="form-input" min="0" max="1" required>
|
||
<div class="form-desc">Unteres Ende des Preisbands (Standard 0.90 = 90 ¢).</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<label for="rfMaxPrice">Max. Preis (0–1)</label>
|
||
<input type="number" step="0.01" id="rfMaxPrice" class="form-input" min="0" max="1" required>
|
||
<div class="form-desc">Oberes Ende des Preisbands (Standard 0.98 = 98 ¢).</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<label for="rfMaxHours">Max. Stunden bis Auflösung</label>
|
||
<input type="number" id="rfMaxHours" class="form-input" min="1" required>
|
||
<div class="form-desc">Nur Märkte scannen, die innerhalb dieses Fensters auflösen (Standard 48h).</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<label for="rfMinEdge">Min. Netto-Edge (%)</label>
|
||
<input type="number" step="0.1" id="rfMinEdge" class="form-input" required>
|
||
<div class="form-desc">Mindest-Netto-Edge nach Fees (Standard 1.5%).</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<label for="rfMaxPerMarket">Max. Einsatz je Markt (USDC)</label>
|
||
<input type="number" step="1" id="rfMaxPerMarket" class="form-input" required>
|
||
<div class="form-desc">Obergrenze des Einsatzes in einem einzelnen Markt (Standard 25).</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<label for="rfMaxCluster">Max. Anteil je Cluster (%)</label>
|
||
<input type="number" step="1" id="rfMaxCluster" class="form-input" required>
|
||
<div class="form-desc">Maximaler Anteil der Bankroll je Ereignis-Cluster (Standard 10%).</div>
|
||
</div>
|
||
<div class="form-row" style="grid-column: span 2;">
|
||
<label for="rfWhitelist">Kategorie-Whitelist (CSV)</label>
|
||
<input type="text" id="rfWhitelist" class="form-input" placeholder="Sports,Politics,Geopolitics">
|
||
<div class="form-desc">Kommagetrennte Liste der erlaubten Markt-Kategorien (z. B. Krypto ausschließen wegen Fees).</div>
|
||
</div>
|
||
<div class="form-row" style="grid-column: span 2;">
|
||
<label for="rfBlacklist">Blacklist Slugs/Tags (CSV)</label>
|
||
<input type="text" id="rfBlacklist" class="form-input" placeholder="z. B. dispute,controversy">
|
||
<div class="form-desc">Ausschluss von Märkten mit Dispute-Gefahr (Teil-Match).</div>
|
||
</div>
|
||
</div>
|
||
<div style="margin-top: 20px; display: flex; gap: 10px; align-items: center;">
|
||
<button type="submit" class="btn btn-primary">Einstellungen speichern</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- VIEW: SUPERVISOR -->
|
||
<section id="view-supervisor" class="view-panel">
|
||
<div class="module-toolbar">
|
||
<div style="display: flex; gap: 8px; align-items: center;">
|
||
<span style="font-size: 16px; font-weight: 700; color: var(--text);">AI Supervisor & Copilot</span>
|
||
<span class="badge" style="background: rgba(137, 180, 250, 0.15); color: var(--accent); border: 1px solid var(--accent);">LLM Agent</span>
|
||
</div>
|
||
<div class="module-tabs">
|
||
<button class="module-tab-btn active" id="supTabBtn-chat" onclick="switchSupTab('chat')">AI Copilot Chat</button>
|
||
<button class="module-tab-btn" id="supTabBtn-reports" onclick="switchSupTab('reports')">Berichte-Archiv</button>
|
||
<button class="module-tab-btn" id="supTabBtn-signals" onclick="switchSupTab('signals')">Signal-Dossiers</button>
|
||
<button class="module-tab-btn" id="supTabBtn-counterfactuals" onclick="switchSupTab('counterfactuals')">Counterfactuals</button>
|
||
</div>
|
||
<div style="margin-left: auto; display: flex; gap: 8px;">
|
||
<button class="btn btn-secondary" onclick="refreshCurrentSupTab()">Aktualisieren</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- SUP SUBTAB: CHAT -->
|
||
<div id="supTab-chat" class="sup-tab-content active">
|
||
<div class="supervisor-chat-box">
|
||
<div class="chat-presets-bar">
|
||
<span class="chat-preset-tag">Schnellabfragen:</span>
|
||
<button class="chat-preset-btn" onclick="applySupPreset('Erstelle einen kompakten Tagesbericht über alle Module, PnL und offene Positionen.')">📊 Tagesbericht</button>
|
||
<button class="chat-preset-btn" onclick="applySupPreset('Audit aller offenen Positionen: Gibt es Klumpenrisiken oder kritische Restlaufzeiten?')">🛡️ Risiko-Audit</button>
|
||
<button class="chat-preset-btn" onclick="applySupPreset('Analysiere die verlorenen Trades der letzten 24 Stunden. Was waren die Hauptursachen?')">🔍 Verlust-Analyse</button>
|
||
<button class="chat-preset-btn" onclick="applySupPreset('Bewerte die Performance der aktiven Master-Trader und markiere auffällige Drift.')">👥 Master-Trader Audit</button>
|
||
<button class="chat-preset-btn" onclick="applySupPreset('Prüfe die abgelehnten Signale: Hätten wir profitabel getradet (Counterfactuals)?')">💡 Counterfactuals</button>
|
||
</div>
|
||
<div class="chat-messages-area" id="supChatMessages">
|
||
<div class="chat-bubble assistant">
|
||
<div class="chat-bubble-header">
|
||
<span>🤖 Supervisor Copilot</span>
|
||
<span>Bereit</span>
|
||
</div>
|
||
<div class="chat-bubble-body">Hallo! Ich bin der autonome PolyTrader Supervisor. Ich überwache alle Handelsmodule, Kontosalden, Order-Ereignisse und Gegenwahrscheinlichkeiten.
|
||
|
||
Wähle ein Profil und stelle mir eine Frage zu deinen Positionen, Risiken oder deiner Trading-Performance.</div>
|
||
</div>
|
||
</div>
|
||
<form id="formSupChat" onsubmit="sendSupQuestion(event)" class="chat-input-row">
|
||
<select id="supProfileSelect" class="form-input form-select" style="min-width: 140px; max-width: 160px; font-size: 13px;" title="Supervisor Profil">
|
||
<option value="General">General</option>
|
||
<option value="Risk">Risk</option>
|
||
<option value="Research">Research</option>
|
||
</select>
|
||
<input type="text" id="supModelInput" class="form-input" style="max-width: 150px; font-size: 13px;" placeholder="Modell (leer = Standard)" title="Optionales KI-Modell (z. B. gpt-4o, claude-3-5-sonnet)">
|
||
<input type="text" id="supQuestionInput" class="form-input" style="flex: 1; font-size: 13.5px;" placeholder="Frage an den Supervisor stellen …" required autocomplete="off">
|
||
<button type="submit" id="btnSupSend" class="btn btn-primary" style="padding: 8px 18px;">Senden</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- SUP SUBTAB: REPORTS -->
|
||
<div id="supTab-reports" class="sup-tab-content" style="display: none;">
|
||
<div style="margin-bottom: 14px; font-size: 13px; color: var(--muted);" id="supReportsSummary">Lade Berichte-Archiv …</div>
|
||
<div class="table-container">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th style="width: 50px;">ID</th>
|
||
<th>Zeitpunkt</th>
|
||
<th>Profil</th>
|
||
<th>Modell</th>
|
||
<th>Frage / Auslöser</th>
|
||
<th style="text-align: center;">Tools</th>
|
||
<th style="text-align: right;">Tokens</th>
|
||
<th style="text-align: center; width: 120px;">Aktion</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="supReportsTbody">
|
||
<tr><td colspan="8" style="text-align: center; color: var(--muted);">Lade Berichte …</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- SUP SUBTAB: SIGNALS -->
|
||
<div id="supTab-signals" class="sup-tab-content" style="display: none;">
|
||
<div style="margin-bottom: 14px; font-size: 13px; color: var(--muted);" id="supSignalsSummary">Lade Signal-Dossiers …</div>
|
||
<div class="table-container">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Signal-ID</th>
|
||
<th>Erkannt am</th>
|
||
<th>Modul</th>
|
||
<th>Konto</th>
|
||
<th>Marktfrage</th>
|
||
<th>Side</th>
|
||
<th>Letzte Entscheidung</th>
|
||
<th>Grund</th>
|
||
<th style="text-align: center; width: 120px;">Aktion</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="supSignalsTbody">
|
||
<tr><td colspan="9" style="text-align: center; color: var(--muted);">Lade Signale …</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- SUP SUBTAB: COUNTERFACTUALS -->
|
||
<div id="supTab-counterfactuals" class="sup-tab-content" style="display: none;">
|
||
<div style="margin-bottom: 14px; font-size: 13px; color: var(--muted);" id="supCounterfactualsSummary">Lade Counterfactual-Analysen (abgelehnte Signale vs. Realität) …</div>
|
||
<div class="table-container">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th style="width: 50px;">ID</th>
|
||
<th>Geprüft am</th>
|
||
<th>Modul</th>
|
||
<th>Konto</th>
|
||
<th>Markt</th>
|
||
<th>Ablehnungsgrund</th>
|
||
<th style="text-align: right;">Signal-Preis</th>
|
||
<th style="text-align: center;">Ausgang</th>
|
||
<th style="text-align: right;">Hypoth. PnL / Share</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="supCounterfactualsTbody">
|
||
<tr><td colspan="9" style="text-align: center; color: var(--muted);">Lade Counterfactuals …</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- VIEW: ACCOUNTING -->
|
||
<section id="view-accounting" class="view-panel">
|
||
<div class="module-toolbar">
|
||
<div style="display: flex; gap: 8px; align-items: center;">
|
||
<span style="font-size: 16px; font-weight: 700; color: var(--text);">Accounting & BWA</span>
|
||
<span class="badge" style="background: rgba(166, 227, 161, 0.15); color: var(--positive); border: 1px solid var(--positive);">Finanzbuchhaltung</span>
|
||
</div>
|
||
<div class="module-tabs">
|
||
<button class="module-tab-btn active" id="accTabBtn-bwa" onclick="switchAccTab('bwa')">BWA & Periodenabrechnung</button>
|
||
<button class="module-tab-btn" id="accTabBtn-ledger" onclick="switchAccTab('ledger')">Ledger-Journal</button>
|
||
<button class="module-tab-btn" id="accTabBtn-runs" onclick="switchAccTab('runs')">Sync & Ingest Läufe</button>
|
||
</div>
|
||
<div style="margin-left: auto; display: flex; gap: 8px;">
|
||
<button class="btn btn-secondary" onclick="refreshCurrentAccTab()">Aktualisieren</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ACC SUBTAB: BWA -->
|
||
<div id="accTab-bwa" class="acc-tab-content active">
|
||
<!-- Filters & Currency -->
|
||
<div class="card" style="margin-bottom: 20px;">
|
||
<div style="display: flex; flex-wrap: wrap; gap: 16px; align-items: center; justify-content: space-between;">
|
||
<div style="display: flex; flex-wrap: wrap; gap: 12px; align-items: center;">
|
||
<div class="toolbar-item">
|
||
<label for="accFilterAccount" style="font-size: 12px; font-weight: 600;">Konto:</label>
|
||
<select id="accFilterAccount" class="form-input form-select" style="min-width: 170px;">
|
||
<option value="">Alle Konten</option>
|
||
</select>
|
||
</div>
|
||
<div class="toolbar-item">
|
||
<label for="accFilterFrom" style="font-size: 12px; font-weight: 600;">Von:</label>
|
||
<input type="date" id="accFilterFrom" class="form-input" style="font-size: 13px;">
|
||
</div>
|
||
<div class="toolbar-item">
|
||
<label for="accFilterTo" style="font-size: 12px; font-weight: 600;">Bis:</label>
|
||
<input type="date" id="accFilterTo" class="form-input" style="font-size: 13px;">
|
||
</div>
|
||
<button class="btn btn-primary" style="margin-top: 14px;" onclick="loadAccountingBwa()">Abrechnung berechnen</button>
|
||
</div>
|
||
|
||
<div style="display: flex; flex-wrap: wrap; gap: 12px; align-items: center;">
|
||
<div>
|
||
<label style="display: block; font-size: 11px; color: var(--muted); margin-bottom: 2px;">Währung:</label>
|
||
<div class="currency-pills">
|
||
<button type="button" class="currency-pill active" id="currPill-USDC" onclick="selectAccountingCurrency('USDC')">USDC</button>
|
||
<button type="button" class="currency-pill" id="currPill-USD" onclick="selectAccountingCurrency('USD')">USD</button>
|
||
<button type="button" class="currency-pill" id="currPill-EUR" onclick="selectAccountingCurrency('EUR')">EUR</button>
|
||
</div>
|
||
</div>
|
||
<div style="margin-top: 14px; display: flex; gap: 8px;">
|
||
<button class="btn btn-secondary" onclick="exportAccountingPdf()">📄 PDF Export</button>
|
||
<button class="btn btn-secondary" onclick="exportAccountingCsv()">📊 CSV Export</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div id="accCurrencyNote" style="margin-top: 10px; font-size: 11.5px; color: var(--muted); font-style: italic;"></div>
|
||
</div>
|
||
|
||
<!-- BWA KPI Cards -->
|
||
<div class="grid-4" style="margin-bottom: 20px;">
|
||
<div class="card">
|
||
<div class="card-title">Anfangsbestand</div>
|
||
<div class="card-value" id="accBwaOpening">0.00</div>
|
||
<div class="card-sub" id="accBwaPeriodLabel">Zu Beginn der Periode</div>
|
||
</div>
|
||
<div class="card">
|
||
<div class="card-title">Endbestand</div>
|
||
<div class="card-value" id="accBwaClosing">0.00</div>
|
||
<div class="card-sub" id="accBwaBalanceChange">Veränderung: 0.00</div>
|
||
</div>
|
||
<div class="card">
|
||
<div class="card-title">Netto Trading-Ergebnis</div>
|
||
<div class="card-value" id="accBwaNetResult">0.00</div>
|
||
<div class="card-sub" id="accBwaTradeStats">0 Trades | 0 Buchungen</div>
|
||
</div>
|
||
<div class="card">
|
||
<div class="card-title">Handelsvolumen & Gebühren</div>
|
||
<div class="card-value" id="accBwaVolume">0.00</div>
|
||
<div class="card-sub" id="accBwaFees">Gebühren: 0.00 | Rewards: 0.00</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Monthly Breakdown Table -->
|
||
<h3 style="margin-bottom: 12px; font-size: 15px; font-weight: 600;">Monatliche BWA-Aufschlüsselung</h3>
|
||
<div class="table-container">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Monat</th>
|
||
<th style="text-align: right;">Anfangsbestand</th>
|
||
<th style="text-align: right;">Endbestand</th>
|
||
<th style="text-align: right;">Ein-/Auszahlungen</th>
|
||
<th style="text-align: right;">Handelsvolumen</th>
|
||
<th style="text-align: right;">Gebühren</th>
|
||
<th style="text-align: right;">Netto-Ergebnis</th>
|
||
<th style="text-align: center;">Trades</th>
|
||
<th style="text-align: center;">Buchungen</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="accMonthlyTbody">
|
||
<tr><td colspan="9" style="text-align: center; color: var(--muted);">Lade Abrechnung …</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ACC SUBTAB: LEDGER -->
|
||
<div id="accTab-ledger" class="acc-tab-content" style="display: none;">
|
||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 14px; flex-wrap: wrap; gap: 10px;">
|
||
<div style="display: flex; gap: 10px; align-items: center;">
|
||
<input type="text" id="accLedgerSearch" class="form-input" style="min-width: 260px;" placeholder="Suchen nach Markt, TX-Hash, Event …" onkeydown="if(event.key==='Enter') searchAccLedger()">
|
||
<button class="btn btn-secondary" onclick="searchAccLedger()">Suchen</button>
|
||
</div>
|
||
<div id="accLedgerSummary" style="font-size: 13px; color: var(--muted);">Lade Journal …</div>
|
||
</div>
|
||
<div class="table-container">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Zeitpunkt</th>
|
||
<th>Konto</th>
|
||
<th>Ereignis</th>
|
||
<th>Side</th>
|
||
<th>Markt</th>
|
||
<th>Outcome</th>
|
||
<th style="text-align: right;">Size</th>
|
||
<th style="text-align: right;">Preis</th>
|
||
<th style="text-align: right;">Brutto</th>
|
||
<th style="text-align: right;">Fee</th>
|
||
<th style="text-align: right;">Netto</th>
|
||
<th>TX-Hash</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="accLedgerTbody">
|
||
<tr><td colspan="12" style="text-align: center; color: var(--muted);">Lade Journal …</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="pagination-bar" id="accLedgerPagination">
|
||
<span id="accLedgerPageInfo" style="font-size: 13px; color: var(--muted);">Seite 1 von 1</span>
|
||
<div style="display: flex; gap: 6px;">
|
||
<button class="btn btn-secondary btn-sm" id="btnAccLedgerPrev" onclick="changeAccLedgerPage(-1)">◀ Vorherige</button>
|
||
<button class="btn btn-secondary btn-sm" id="btnAccLedgerNext" onclick="changeAccLedgerPage(1)">Nächste ▶</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ACC SUBTAB: RUNS -->
|
||
<div id="accTab-runs" class="acc-tab-content" style="display: none;">
|
||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 14px;">
|
||
<div id="accRunsSummary" style="font-size: 13px; color: var(--muted);">Lade Ingestion-Historie …</div>
|
||
<button class="btn btn-primary" onclick="triggerManualIngest()">+ Blockchain-Sync manuell starten</button>
|
||
</div>
|
||
<div class="table-container">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th style="width: 50px;">ID</th>
|
||
<th>Konto</th>
|
||
<th>Startzeit</th>
|
||
<th>Fertiggestellt</th>
|
||
<th>Typ</th>
|
||
<th style="text-align: right;">Neue Buchungen</th>
|
||
<th style="text-align: right;">Duplikate</th>
|
||
<th style="text-align: right;">Saldo-Delta</th>
|
||
<th style="text-align: center;">Status</th>
|
||
<th>Fehlermeldung</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="accRunsTbody">
|
||
<tr><td colspan="10" style="text-align: center; color: var(--muted);">Lade Ingestion-Läufe …</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- VIEW: ACCOUNTS -->
|
||
<section id="view-accounts" class="view-panel">
|
||
<h2 style="margin-bottom: 16px; font-size: 18px;">Polymarket Konten</h2>
|
||
<div class="table-container">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>#</th>
|
||
<th>Name</th>
|
||
<th>Status</th>
|
||
<th>Modus</th>
|
||
<th>USDC Balance</th>
|
||
<th>3T PnL</th>
|
||
<th>3T Winrate %</th>
|
||
<th>Overall P/L</th>
|
||
<th>Proxy Wallet</th>
|
||
<th>Polymarket</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="tblAccounts">
|
||
<tr><td colspan="10" style="text-align: center; color: var(--muted);">Lade Konten …</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- VIEW: JOBS -->
|
||
<section id="view-jobs" class="view-panel">
|
||
<h2 style="margin-bottom: 16px; font-size: 18px;">Server Jobs & Hintergrund-Dienste</h2>
|
||
<div class="table-container">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Job Name</th>
|
||
<th>Beschreibung</th>
|
||
<th>Aktiv</th>
|
||
<th>Letzter Lauf</th>
|
||
<th>Nächster Lauf</th>
|
||
<th>Status</th>
|
||
<th>Aktion</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="tblJobs">
|
||
<tr><td colspan="7" style="text-align: center; color: var(--muted);">Lade Jobs …</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- VIEW: TERMINAL / LOGS -->
|
||
<section id="view-logs" class="view-panel">
|
||
<div class="terminal-window">
|
||
<div class="terminal-toolbar">
|
||
<div style="display: flex; gap: 10px; align-items: center;">
|
||
<span style="font-weight: 600;">Echtzeit-Log Stream</span>
|
||
<div class="status-indicator" style="padding: 2px 6px; font-size: 11px;">
|
||
<span class="dot online" id="sseDot"></span>
|
||
<span id="sseStatus">Verbunden</span>
|
||
</div>
|
||
</div>
|
||
<div style="display: flex; gap: 10px; align-items: center;">
|
||
<select id="logLevelFilter" class="form-input" style="padding: 4px 8px; font-size: 12px; width: auto;" onchange="applyLogFilter()">
|
||
<option value="ALL">Alle Level</option>
|
||
<option value="INFO">Info</option>
|
||
<option value="WARNING">Warning</option>
|
||
<option value="ERROR">Error</option>
|
||
<option value="TRADE">Trade</option>
|
||
</select>
|
||
<label class="checkbox-label" style="font-size: 12px; color: var(--muted);">
|
||
<input type="checkbox" id="chkAutoScroll" checked> Auto-Scroll
|
||
</label>
|
||
<button class="btn btn-secondary" style="padding: 4px 8px; font-size: 12px;" onclick="clearLogs()">Leeren</button>
|
||
</div>
|
||
</div>
|
||
<div class="terminal-logs" id="logContainer"></div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- VIEW: MODULES -->
|
||
<section id="view-modules" class="view-panel">
|
||
<h2 style="margin-bottom: 16px; font-size: 18px;">Strategie- & Analyse-Module</h2>
|
||
<div class="grid-2" id="modulesContainer">
|
||
<div class="card"><div class="card-title">Lade Module …</div></div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- VIEW: SETTINGS -->
|
||
<section id="view-settings" class="view-panel">
|
||
<h2 style="margin-bottom: 16px; font-size: 18px;">WebGUI Anwendungseinstellungen</h2>
|
||
<div class="card settings-form">
|
||
<form id="settingsForm" onsubmit="saveSettings(event)">
|
||
<div class="form-row">
|
||
<label class="checkbox-label">
|
||
<input type="checkbox" id="cfgEnabled">
|
||
WebGUI Server aktiv
|
||
</label>
|
||
<div class="form-desc">Steuert, ob Kestrel beim Programmstart hochfährt.</div>
|
||
</div>
|
||
|
||
<div class="form-row">
|
||
<label for="cfgPort">Server-Port</label>
|
||
<input type="number" id="cfgPort" class="form-input" min="1024" max="65535" required>
|
||
<div class="form-desc">Standard ist 6001. Änderung wird nach dem nächsten Neustart aktiv.</div>
|
||
</div>
|
||
|
||
<div class="form-row">
|
||
<label class="checkbox-label">
|
||
<input type="checkbox" id="cfgLocalOnly">
|
||
Nur lokaler Zugriff (127.0.0.1)
|
||
</label>
|
||
<div class="form-desc">Wenn deaktiviert, ist das WebUI über alle Netzwerkschnittstellen (LAN/VPN) erreichbar.</div>
|
||
</div>
|
||
|
||
<div class="form-row">
|
||
<label for="cfgToken">Zugangs-Token</label>
|
||
<div style="display: flex; gap: 8px;">
|
||
<input type="text" id="cfgToken" class="form-input" style="font-family: var(--font-mono); font-size: 12px;" readonly>
|
||
<button type="button" class="btn btn-secondary" onclick="copyToken()">Kopieren</button>
|
||
<button type="button" class="btn btn-secondary" onclick="generateNewToken()">Neu generieren</button>
|
||
</div>
|
||
<div class="form-desc">Wird in appsettings.Local.json gespeichert. Bei leerem Token ist das WebUI gesperrt.</div>
|
||
</div>
|
||
|
||
<div style="display: flex; gap: 10px; align-items: center; margin-top: 24px;">
|
||
<button type="submit" class="btn btn-primary" id="btnSaveSettings">Einstellungen speichern</button>
|
||
<span id="settingsStatusMsg" style="font-size: 13px; color: var(--positive); display: none;">✓ Gespeichert</span>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
|
||
<!-- MODAL: MASTER TRADER EDIT/ADD -->
|
||
<div id="modalTrader" class="modal-overlay" style="display: none;">
|
||
<div class="modal-dialog">
|
||
<div class="modal-header">
|
||
<h3 id="modalTraderTitle" style="margin: 0; font-size: 16px;">Master-Trader bearbeiten</h3>
|
||
<button class="modal-close" onclick="closeTraderModal()">×</button>
|
||
</div>
|
||
<form id="formTraderModal" onsubmit="saveTraderModal(event)">
|
||
<input type="hidden" id="traderModalId">
|
||
<div class="modal-body" style="display: grid; grid-template-columns: 1fr 1fr; gap: 14px;">
|
||
<div class="form-row" style="grid-column: span 2;">
|
||
<label for="traderModalName">Anzeigename</label>
|
||
<input type="text" id="traderModalName" class="form-input" required placeholder="z. B. Whale-Alpha">
|
||
</div>
|
||
<div class="form-row" style="grid-column: span 2;">
|
||
<label for="traderModalWallet">Wallet-Adresse (0x...)</label>
|
||
<input type="text" id="traderModalWallet" class="form-input" style="font-family: var(--font-mono); font-size: 12px;" required placeholder="0x1234567890abcdef...">
|
||
</div>
|
||
<div class="form-row">
|
||
<label for="traderModalCategory">Kategorie</label>
|
||
<select id="traderModalCategory" class="form-input form-select">
|
||
<option value="NEW_BIG_BET">NEW_BIG_BET</option>
|
||
<option value="HF">HF (High-Frequency)</option>
|
||
<option value="INSIDER">INSIDER</option>
|
||
<option value="SNIPER">SNIPER</option>
|
||
<option value="HOLDER">HOLDER</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-row" style="display: flex; flex-direction: column; justify-content: center; gap: 6px;">
|
||
<label class="checkbox-label"><input type="checkbox" id="traderModalActive" checked> <strong>Aktiv</strong> (Kopieren an)</label>
|
||
<label class="checkbox-label"><input type="checkbox" id="traderModalAutoPause" checked> Auto-Pause Kill-Switch</label>
|
||
<label class="checkbox-label"><input type="checkbox" id="traderModalMaker"> Maker-Einstieg (GTC-Limit)</label>
|
||
<label class="checkbox-label"><input type="checkbox" id="traderModalHidden"> Ausgeblendet (Archiv)</label>
|
||
</div>
|
||
<div class="form-row" style="grid-column: span 2;">
|
||
<label for="traderModalDesc">Beschreibung</label>
|
||
<input type="text" id="traderModalDesc" class="form-input" placeholder="Optionale Notiz zur Strategie / Herkunft">
|
||
</div>
|
||
<div class="form-row" style="grid-column: span 2;">
|
||
<label for="traderModalReasoning">Begründung / Reasoning</label>
|
||
<input type="text" id="traderModalReasoning" class="form-input" placeholder="Warum dieser Master kopiert wird">
|
||
</div>
|
||
<div class="form-row" style="grid-column: span 2;">
|
||
<label style="margin-bottom: 6px; display: block; font-weight: 500; font-size: 13px;">Zugewiesene Konten:</label>
|
||
<div id="traderModalAccountsList" style="display: flex; flex-wrap: wrap; gap: 12px; background: var(--surface-alt); padding: 10px; border-radius: var(--radius-sm); border: 1px solid var(--border);"></div>
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer" style="display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; padding-top: 12px; border-top: 1px solid var(--border);">
|
||
<button type="button" class="btn btn-secondary" onclick="closeTraderModal()">Abbrechen</button>
|
||
<button type="submit" class="btn btn-primary">Speichern</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- MODAL: REPORT / DOSSIER VIEWER -->
|
||
<div id="modalReport" class="modal-overlay" style="display: none;">
|
||
<div class="modal-dialog" style="max-width: 860px;">
|
||
<div class="modal-header">
|
||
<h3 id="modalReportTitle" style="margin: 0; font-size: 16px;">Bericht / Dossier</h3>
|
||
<button class="modal-close" onclick="closeReportModal()">×</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div id="modalReportMeta" style="margin-bottom: 12px; font-size: 12px; color: var(--muted); display: flex; gap: 14px; flex-wrap: wrap;"></div>
|
||
<pre id="modalReportContent" class="markdown-pre"></pre>
|
||
</div>
|
||
<div class="modal-footer" style="display: flex; justify-content: flex-end; margin-top: 14px;">
|
||
<button type="button" class="btn btn-secondary" onclick="closeReportModal()">Schließen</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="/js/app.js"></script>
|
||
</body>
|
||
</html>
|