Fix: Implement FixPlan part A9, A10, B

This commit is contained in:
Richard
2026-07-10 12:04:27 +02:00
parent 44f48284a2
commit 1787422243
28 changed files with 1025 additions and 79 deletions
+62 -23
View File
@@ -27,6 +27,7 @@ document.querySelectorAll('.nav-item[data-page]').forEach(item => {
if (page === 'alerts') loadAlerts();
if (page === 'markets') loadMarkets();
if (page === 'jobs') loadJobs();
if (page === 'watchlist') loadWatchlist();
});
});
@@ -106,14 +107,7 @@ async function manualAddTrader() {
}
}
async function manualUpdateTrader(id) {
const res = await fetch(`/api/traders/${id}/refresh`, { method: 'POST' });
if (res.ok) {
alert('Sync triggered manually. Data will update in a few minutes.');
} else {
alert('Failed to trigger sync.');
}
}
let currentPlatform = 'All';
let currentSort = 'default';
@@ -134,14 +128,16 @@ function refreshActivePage() {
if (activePage === 'page-dashboard') loadDashboard();
else if (activePage === 'page-traders') loadTraders();
else if (activePage === 'page-markets') loadMarkets();
else if (activePage === 'page-watchlist') loadWatchlist();
}
// ─── API Helpers ───
async function api(endpoint) {
async function api(endpoint, options = {}) {
try {
const res = await fetch(`${API_BASE}${endpoint}`);
const res = await fetch(`${API_BASE}${endpoint}`, options);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.json();
const text = await res.text();
return text ? JSON.parse(text) : true;
} catch (err) {
console.error(`API Error [${endpoint}]:`, err);
return null;
@@ -349,6 +345,41 @@ async function loadTraders() {
`).join('');
}
async function loadWatchlist() {
const data = await api(`/api/watchlist`);
if (!data) return;
const tbody = document.getElementById('watchlistBody');
tbody.innerHTML = data.map(w => `
<tr>
<td class="trader-name">
<div class="avatar">${w.displayName.substring(0, 2).toUpperCase()}</div>
<div>
<strong>${w.displayName}</strong><br>
<span style="font-size:12px; color:var(--text-secondary)">${w.platformUserId.substring(0, 8)}...</span>
</div>
</td>
<td>${w.platform ?? 'Unknown'}</td>
<td>${Number(w.copytradingScore || 0).toFixed(1)}</td>
<td class="${w.winRate > 0.5 ? 'text-green' : 'text-red'}">${fmt.pct(w.winRate)}</td>
<td class="${w.totalPnl >= 0 ? 'text-green' : 'text-red'}">${fmt.pnl(w.totalPnl)}</td>
<td>${w.label || ''}</td>
<td>${new Date(w.createdAt).toLocaleDateString()}</td>
<td>
<button class="btn-sm" onclick="viewTrader(${w.traderId})">View</button>
<button class="btn-sm btn-outline-danger" onclick="removeFromWatchlist(${w.traderId})">Remove</button>
</td>
</tr>
`).join('') || '<tr><td colspan="8">Your watchlist is empty.</td></tr>';
}
async function removeFromWatchlist(id) {
if (confirm('Remove this trader from watchlist?')) {
await api(`/api/traders/${id}/watchlist`, { method: 'DELETE' });
loadWatchlist();
}
}
// ─── Alerts Page ───
async function loadAlerts() {
const data = await api('/api/alerts?count=50');
@@ -429,22 +460,21 @@ async function viewTrader(id) {
const syncBtn = document.getElementById('btn-sync-trader');
if (syncBtn) {
syncBtn.onclick = () => manualUpdateTrader(id);
syncBtn.onclick = () => queueHistorySync(id);
}
const deepSyncBtn = document.getElementById('btn-deep-resync-trader');
if (deepSyncBtn) {
deepSyncBtn.onclick = () => {
if (confirm("Are you sure? This will delete all compacted trades and reset positions, then fetch all historical trades via pagination.")) {
queueDeepResync(id);
}
};
}
const analyzeBtn = document.getElementById('btn-analyze-trader');
if (analyzeBtn) {
analyzeBtn.onclick = async () => {
analyzeBtn.disabled = true;
analyzeBtn.textContent = '...';
try {
await api(`/api/traders/${id}/force-analyze`, { method: 'POST' });
alert('Deep Analysis queued! Please wait a moment and then refresh.');
} finally {
analyzeBtn.disabled = false;
analyzeBtn.textContent = '⚙ Analyze';
}
};
analyzeBtn.onclick = () => queueTraderAnalysis(id);
}
const aiBtn = document.getElementById('btn-ai-analysis');
@@ -658,6 +688,15 @@ async function queueHistorySync(id) {
}
}
async function queueDeepResync(id) {
const res = await fetch(`/api/jobs/deep-resync/${id}`, { method: 'POST' });
if (res.ok) {
alert('Deep Resync job queued successfully.');
} else {
alert('Failed to queue deep resync.');
}
}
async function queueTraderAnalysis(id) {
const res = await fetch(`/api/jobs/analyze/${id}`, { method: 'POST' });
if (res.ok) {