jeeva780's picture
Upload 7 files
948485c verified
Raw History Blame Contribute Delete
7.32 kB
const $ = id => document.getElementById(id);
let lastResult = null;
function log(msg, cls = "") {
const line = document.createElement("div");
line.textContent = msg;
if (cls) line.className = cls;
$("log").appendChild(line);
$("log").scrollTop = $("log").scrollHeight;
}
function setStatus(online) {
$("status").textContent = online ? "● ONLINE" : "● OFFLINE";
$("status").className = online ? "status online" : "status offline";
}
function fmt(n) {
return Number(n || 0).toLocaleString("en-IN", {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
}
function fmtDate(s) {
if (!s) return "";
return new Date(`${s}T00:00:00Z`).toLocaleDateString("en-IN", {
day: "2-digit", month: "short", year: "numeric", timeZone: "UTC"
});
}
function initDates() {
const today = new Date();
const end = new Date(Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate()));
const start = new Date(end);
start.setUTCDate(start.getUTCDate() - 30);
$("start").value = start.toISOString().slice(0,10);
$("end").value = end.toISOString().slice(0,10);
}
async function refreshStatus() {
try {
const r = await fetch("/api/status");
const d = await r.json();
setStatus(Boolean(d.connected));
} catch {
setStatus(false);
}
}
$("loginLink").onclick = async () => {
try {
const r = await fetch("/api/login-url");
const d = await r.json();
if (!d.url) throw new Error(d.error || "Login URL unavailable");
window.open(d.url, "_blank", "noopener,noreferrer");
log("> ICICI Direct login opened", "ok");
} catch (e) {
log("> " + e.message, "error");
}
};
$("connect").onclick = async () => {
const apiSession = $("session").value.trim();
if (!apiSession) {
log("> API Session is required", "error");
return;
}
$("connect").disabled = true;
$("log").textContent = "";
log("> POST /api/connect");
log("> generating Breeze session …");
try {
const r = await fetch("/api/connect", {
method: "POST",
headers: {"Content-Type":"application/json"},
body: JSON.stringify({ apiSession })
});
const d = await r.json();
if (!r.ok) throw new Error(d.error || "Breeze connection failed");
log("> generate_session → OK", "ok");
log("> BREEZE SESSION ESTABLISHED", "ok");
setStatus(true);
} catch (e) {
setStatus(false);
log("> " + e.message, "error");
} finally {
$("connect").disabled = false;
}
};
$("logout").onclick = async () => {
await fetch("/api/logout", {method:"POST"});
$("session").value = "";
$("log").textContent = "/ session cleared";
setStatus(false);
};
function renderMetrics(m) {
const cards = [
["TOTAL LEGS", m.trades],
["WIN RATE", `${Number(m.winRate).toFixed(2)}%`],
["NET P&L", `₹ ${fmt(m.netPnl)}`],
["PROFIT FACTOR", m.profitFactor == null ? "∞" : Number(m.profitFactor).toFixed(2)],
["MAX DRAWDOWN", `₹ ${fmt(m.maxDrawdown)}`],
["EXPECTANCY / LEG", `₹ ${fmt(m.expectancy)}`],
["GROSS PROFIT", `₹ ${fmt(m.grossProfit)}`],
["GROSS LOSS", `₹ ${fmt(m.grossLoss)}`],
["BROKERAGE", `₹ ${fmt(m.brokerage)}`],
["WINS", m.wins],
["LOSSES", m.losses]
];
$("metrics").innerHTML = cards.map(([a,b]) =>
`<div class="metric"><div class="label">${a}</div><div class="value">${b}</div></div>`
).join("");
}
function renderTables(r) {
$("dailyTable").innerHTML = `
<thead><tr>
<th>ENTRY</th><th>EXIT</th><th>P&L</th><th>CUMULATIVE</th><th>RESULT</th>
</tr></thead>
<tbody>${r.daily.map(d => `
<tr>
<td>${fmtDate(d.entryDate)} ${d.entryTime}</td>
<td>${fmtDate(d.exitDate)} ${d.exitTime}</td>
<td class="${d.pnl >= 0 ? "pos":"neg"}">₹ ${fmt(d.pnl)}</td>
<td class="${d.cum >= 0 ? "pos":"neg"}">₹ ${fmt(d.cum)}</td>
<td>${d.result}</td>
</tr>`).join("")}</tbody>`;
$("tradesTable").innerHTML = `
<thead><tr>
<th>ENTRY</th><th>EXIT</th><th>RIGHT</th><th>STRIKE</th><th>EXPIRY</th>
<th>ENTRY ₹</th><th>EXIT ₹</th><th>GROSS</th><th>NET</th><th>REASON</th>
</tr></thead>
<tbody>${r.trades.map(t => `
<tr>
<td>${fmtDate(t.entryDate)} ${t.entryTime}</td>
<td>${fmtDate(t.exitDate)} ${t.exitTime}</td>
<td>${t.right}</td><td>${t.strike}</td><td>${fmtDate(t.expiry)}</td>
<td>${fmt(t.entry)}</td><td>${fmt(t.exit)}</td>
<td class="${t.gross >= 0 ? "pos":"neg"}">₹ ${fmt(t.gross)}</td>
<td class="${t.net >= 0 ? "pos":"neg"}">₹ ${fmt(t.net)}</td>
<td>${t.reason}</td>
</tr>`).join("")}</tbody>`;
}
function downloadCSV(filename, rows) {
const csv = rows.map(row => row.map(v => {
const s = String(v ?? "");
return /[",\n]/.test(s) ? `"${s.replaceAll('"','""')}"` : s;
}).join(",")).join("\n");
const blob = new Blob([csv], {type:"text/csv;charset=utf-8"});
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = filename;
a.click();
URL.revokeObjectURL(a.href);
}
$("run").onclick = async () => {
const start = $("start").value;
const end = $("end").value;
if (!start || !end || start > end) {
alert("Check the backtest date range.");
return;
}
$("run").disabled = true;
$("run").textContent = "⏳ FETCHING REAL DATA…";
$("progress").classList.remove("hidden");
$("bar").style.width = "10%";
$("progressText").textContent = "Requesting Breeze historical candles…";
try {
const r = await fetch("/api/backtest", {
method: "POST",
headers: {"Content-Type":"application/json"},
body: JSON.stringify({
start,
end,
targetPts: Number($("target").value || 20),
slPts: Number($("sl").value || 10),
brokerage: Number($("brokerage").value || 40),
sqOff: $("sqoff").value || "15:10"
})
});
const d = await r.json();
if (!r.ok) throw new Error(d.error || "Backtest failed");
lastResult = d;
$("bar").style.width = "100%";
$("progressText").textContent = `REAL DATA COMPLETE · ${d.trades.length} LEGS`;
renderMetrics(d.metrics);
renderTables(d);
$("results").classList.remove("hidden");
} catch (e) {
alert(e.message);
$("progressText").textContent = "ERROR: " + e.message;
} finally {
setTimeout(() => $("progress").classList.add("hidden"), 700);
$("run").disabled = false;
$("run").textContent = "▶ RUN REAL BREEZE BACKTEST";
}
};
$("downloadTrades").onclick = () => {
if (!lastResult) return;
const rows = [
["Entry Date","Entry Time","Exit Date","Exit Time","Right","Strike","Expiry","Entry","Exit","Gross","Brokerage","Net","Reason"],
...lastResult.trades.map(t => [
t.entryDate,t.entryTime,t.exitDate,t.exitTime,t.right,t.strike,t.expiry,
t.entry,t.exit,t.gross,t.brokerage,t.net,t.reason
])
];
downloadCSV("nifty_real_breeze_trades.csv", rows);
};
$("downloadDaily").onclick = () => {
if (!lastResult) return;
const rows = [
["Entry Date","Entry Time","Exit Date","Exit Time","P&L","Cumulative","Result"],
...lastResult.daily.map(d => [
d.entryDate,d.entryTime,d.exitDate,d.exitTime,d.pnl,d.cum,d.result
])
];
downloadCSV("nifty_real_breeze_daily.csv", rows);
};
initDates();
refreshStatus();