Download public/scripts/main.js from jeeva780/Selva-Option-Backtest: direct link, hf CLI and curl.
- Browser
- Download file 7.32 kB
-
https://huggingface.co/spaces/jeeva780/Selva-Option-Backtest/resolve/main/public/scripts/main.js
- Command line
-
hf download hf://spaces/jeeva780/Selva-Option-Backtest/public/scripts/main.js
-
curl -L -o main.js https://huggingface.co/spaces/jeeva780/Selva-Option-Backtest/resolve/main/public/scripts/main.js
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(); | |