').join('');
}
async function loadAlerts(){
const {data}=await fetch('/api/alerts?limit=20').then(r=>r.json());
@@ -709,6 +743,12 @@ async function loadClosedPositions() {
}
}
+
+function setExpiry(exp){
+ _activeExpiry=exp;
+ // Re-render positions with new filter (re-use cached data via refresh)
+ loadPositions();
+}
loadConfig();refresh();
setInterval(refresh,60000);
setInterval(loadMarket,15000);
diff --git a/src/api/server.ts b/src/api/server.ts
index d7d2250..17285e8 100644
--- a/src/api/server.ts
+++ b/src/api/server.ts
@@ -105,12 +105,15 @@ export function createServer(): express.Application {
FROM positions WHERE is_closed = 0 AND netqty != 0
`).get() as any;
- // Realised from FULLY closed positions only (netqty=0) — booked today
- // Do NOT include is_closed=1 with netqty!=0 (those are incorrectly marked / partially open)
+ // Realised P&L from positions updated TODAY (IST) only.
+ // '+5h30m' converts UTC stored time -> IST date for filtering.
+ // This ensures we never include historical expiry P&L from previous days.
const closedRealised = db.prepare(`
SELECT COALESCE(SUM(realised_pnl),0) as r
FROM positions
- WHERE netqty = 0 AND realised_pnl != 0
+ WHERE realised_pnl != 0
+ AND date(updated_at, '+5 hours', '+30 minutes')
+ = date('now', '+5 hours', '+30 minutes')
`).get() as any;
const totalUnrealised = liveOpen.u;
@@ -140,7 +143,9 @@ export function createServer(): express.Application {
const posCount = (db.prepare(`SELECT COUNT(*) as n FROM positions WHERE is_closed = 0 AND netqty != 0`).get() as { n: number }).n;
const bookedRealised = (db.prepare(`
SELECT COALESCE(SUM(realised_pnl),0) as r FROM positions
- WHERE netqty=0 AND realised_pnl!=0
+ WHERE realised_pnl != 0
+ AND date(updated_at, '+5 hours', '+30 minutes')
+ = date('now', '+5 hours', '+30 minutes')
`).get() as { r: number }).r;
res.json({
@@ -156,19 +161,22 @@ export function createServer(): express.Application {
// ── GET /api/closed-positions ─────────────────────────────────────────────
- // Positions fully closed today (netqty=0, have realised PnL)
- // Also shows incorrectly-flagged positions (is_closed=1 but netqty!=0) for transparency
+ // Positions closed TODAY (IST). Groups by expiry so UI can show per-expiry view.
app.get('/api/closed-positions', (_req, res) => {
- // Truly closed (netqty=0 with realised PnL)
+ const todayIST = "date('now', '+5 hours', '+30 minutes')";
+
+ // Today's closed positions only — filtered by IST date
const closed = db.prepare(`
SELECT tradingsymbol, exchange, producttype, instrumenttype,
netqty, avg_price, ltp, realised_pnl, updated_at
FROM positions
- WHERE netqty = 0 AND realised_pnl != 0
+ WHERE realised_pnl != 0
+ AND netqty = 0
+ AND date(updated_at, '+5 hours', '+30 minutes') = date('now', '+5 hours', '+30 minutes')
ORDER BY ABS(realised_pnl) DESC
`).all();
- // Potentially stale (marked closed by system but still has qty — should not happen after fix)
+ // Stale positions (system incorrectly marked open positions as closed)
const stale = db.prepare(`
SELECT tradingsymbol, exchange, netqty, unrealised_pnl, realised_pnl, total_pnl, updated_at
FROM positions
@@ -177,7 +185,7 @@ export function createServer(): express.Application {
ORDER BY ABS(total_pnl) DESC
`).all();
- const totalBooked = closed.reduce((s: number, r: any) => s + r.realised_pnl, 0);
+ const totalBooked = (closed as any[]).reduce((s: number, r: any) => s + r.realised_pnl, 0);
res.json({ ok: true, data: closed, stalePositions: stale, totalBooked });
});