let allTrades = []; let editTradeId = null; let currentNoteId = null; let currentNoteType = null; document.addEventListener("DOMContentLoaded", () => { noteModal = document.getElementById("noteModal"); window.addEventListener("click", (event) => { if (event.target === noteModal) closeNoteModal(); }); loadTradeSummary(); }); function loadTradeSummary() { fetch("/api/trade_summary", { credentials: "include" }) .then(r => r.json()) .then(trades => { allTrades = trades; renderTradeSummary(allTrades); updateBottomBar(allTrades); }) .catch(err => console.error("Error loading trade summary", err)); } function renderTradeSummary(trades) { const container = document.getElementById("tradeSummaryContainer"); container.innerHTML = ""; let grouped = {}; trades.forEach(trade => { if (!grouped[trade.symbol]) { grouped[trade.symbol] = []; } grouped[trade.symbol].push(trade); }); for (let symbol in grouped) { let section = document.createElement("div"); section.className = "coin-section"; let heading = document.createElement("h2"); heading.textContent = symbol; section.appendChild(heading); let table = document.createElement("table"); let thead = document.createElement("thead"); thead.innerHTML = ` Symbol Amount Buy Price Invest Sell Price Profit % Profit Buy Date Sell Date `; table.appendChild(thead); let tbody = document.createElement("tbody"); grouped[symbol].sort((a, b) => new Date(b.sellDate) - new Date(a.sellDate)); let totalProfit = 0; let totalBuyCost = 0; let totalSellValue = 0; let totalAmount = 0; grouped[symbol].forEach(trade => { let row = document.createElement("tr"); let profitClass = trade.profit >= 0 ? "positive" : "negative"; let invest = trade.buyPrice * trade.amount; const editButton = ``; const noteButton = ``; row.innerHTML = ` ${trade.symbol} ${trade.amount} ${trade.buyPrice} ${invest.toFixed(2)} ${trade.sellPrice} ${trade.profit.toFixed(2)} ${trade.percentProfit.toFixed(2)}% ${trade.buyDate} ${trade.sellDate}${editButton}${noteButton} `; tbody.appendChild(row); totalProfit += trade.profit; totalAmount += trade.amount; totalBuyCost += invest; totalSellValue += trade.sellPrice * trade.amount; }); let totalPctProfit = 0; if (totalBuyCost > 0) { totalPctProfit = ((totalSellValue - totalBuyCost) / totalBuyCost) * 100; } let summaryRow = document.createElement("tr"); summaryRow.className = "summary-row"; let summaryProfitClass = totalProfit >= 0 ? "positive" : "negative"; summaryRow.innerHTML = ` ${symbol} (Total) ${totalAmount} - ${totalBuyCost.toFixed(2)} - ${totalProfit.toFixed(2)} ${totalPctProfit.toFixed(2)}% - - `; tbody.appendChild(summaryRow); table.appendChild(tbody); section.appendChild(table); container.appendChild(section); } } function updateBottomBar(trades) { let totalProfit = 0; let totalBuyCost = 0; let totalSellValue = 0; trades.forEach(tr => { totalProfit += tr.profit; totalBuyCost += tr.buyPrice * tr.amount; totalSellValue += tr.sellPrice * tr.amount; }); let pctChange = 0; if (totalBuyCost > 0) { pctChange = ((totalSellValue - totalBuyCost) / totalBuyCost) * 100; } document.getElementById("totalTradeInvest").textContent = totalBuyCost.toFixed(2) + " USDT"; document.getElementById("totalTradeProfit").textContent = totalProfit.toFixed(2) + " USDT"; document.getElementById("totalTradePercentChange").textContent = pctChange.toFixed(2) + "%"; } function openNoteModal(id, type) { currentNoteId = id; currentNoteType = type; document.getElementById("noteModal").style.display = "block"; const trade = allTrades.find(x => String(x.id) === String(id)); document.getElementById("noteText").value = trade?.note || ""; } function closeNoteModal() { document.getElementById("noteModal").style.display = "none"; } function saveNote() { const noteText = document.getElementById("noteText").value; fetch("/api/trade_summary/note", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ id: currentNoteId, note: noteText }), credentials: "include" }) .then(r => r.json()) .then(j => { if (j.error) { alert(j.error); } else { closeNoteModal(); loadTradeSummary(); } }) .catch(() => alert("Error saving note")); } function openEditTradeModal(id) { editTradeId = id; const trade = allTrades.find(t => String(t.id) === String(id)); if (!trade) { alert("Invalid trade"); return; } document.getElementById("editTradeAmount").value = trade.amount; document.getElementById("editTradeBuyPrice").value = trade.buyPrice; document.getElementById("editTradeSellPrice").value = trade.sellPrice; document.getElementById("editTradeBuyDate").value = trade.buyDate; document.getElementById("editTradeSellDate").value = trade.sellDate; document.getElementById("editTradeModal").style.display = "block"; } function closeEditTradeModal() { document.getElementById("editTradeModal").style.display = "none"; } function saveEditedTrade() { const trade = allTrades.find(t => String(t.id) === String(editTradeId)); if (!trade) { alert("Invalid trade"); return; } const amount = parseFloat(document.getElementById("editTradeAmount").value); const buyPrice = parseFloat(document.getElementById("editTradeBuyPrice").value); const sellPrice = parseFloat(document.getElementById("editTradeSellPrice").value); const buyDate = document.getElementById("editTradeBuyDate").value; const sellDate = document.getElementById("editTradeSellDate").value; if (isNaN(amount) || isNaN(buyPrice) || isNaN(sellPrice)) { alert("Please enter valid values"); return; } fetch("/api/trade_summary/edit", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ id: editTradeId, amount, buyPrice, sellPrice, buyDate, sellDate }), credentials: "include" }) .then(r => r.json()) .then(j => { if (j.error) { alert(j.error); } else { closeEditTradeModal(); loadTradeSummary(); } }) .catch(() => alert("Error saving trade")); } function deleteTrade() { openDeleteTradeConfirmationModal(); } function openDeleteTradeConfirmationModal() { document.getElementById("deleteTradeConfirmationModal").style.display = "block"; } function closeDeleteTradeConfirmationModal() { document.getElementById("deleteTradeConfirmationModal").style.display = "none"; } function confirmDeleteTrade() { fetch("/api/trade_summary/delete", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ id: editTradeId }), credentials: "include" }) .then(r => r.json()) .then(j => { if (j.error) { alert(j.error); } else { closeDeleteTradeConfirmationModal(); closeEditTradeModal(); loadTradeSummary(); } }) .catch(() => alert("Error deleting trade")); } function openDateFilterModal() { document.getElementById("dateFilterModal").style.display = "block"; } function closeDateFilterModal() { document.getElementById("dateFilterModal").style.display = "none"; } function applyDateFilter() { const radios = document.getElementsByName("dateFilterType"); let filterType = "all"; for (let r of radios) { if (r.checked) { filterType = r.value; break; } } if (filterType === "all") { renderTradeSummary(allTrades); updateBottomBar(allTrades); closeDateFilterModal(); return; } const fromDateValue = document.getElementById("filterFromDate").value; const toDateValue = document.getElementById("filterToDate").value; let filtered = allTrades.filter(tr => { let sd = new Date(tr.sellDate); if (fromDateValue) { let from = new Date(fromDateValue); if (sd < from) return false; } if (toDateValue) { let to = new Date(toDateValue); to.setHours(23,59,59,999); if (sd > to) return false; } return true; }); renderTradeSummary(filtered); updateBottomBar(filtered); closeDateFilterModal(); }