diff --git a/public/index.html b/public/index.html index 5557550..7e205fe 100644 --- a/public/index.html +++ b/public/index.html @@ -157,7 +157,8 @@
Open Positions
-
Booked P&L Today
Closed legs realised
+
Booked PnL (7d)
Closed legs realised
Alerts Today
@@ -469,11 +470,30 @@ async function loadHealth(){ const pill=document.getElementById('mkt-pill'); document.getElementById('mkt-lbl').textContent=d.marketOpen?'Market Open':'Market Closed'; pill.className='pill'+(d.marketOpen?' open':''); - const e=document.getElementById('s-err'); - if(d.lastError){e.textContent=d.lastError.error.slice(0,30)+'\u2026';e.style.color='var(--red)';} - else{e.textContent='Healthy';e.style.color='var(--green)';} + const errEl=document.getElementById('s-err'); + const reauthBtn=document.getElementById('reauth-btn'); + if(d.lastError){ + errEl.textContent=d.lastError.error.slice(0,40)+'\u2026'; + errEl.style.display='inline'; + if(reauthBtn)reauthBtn.style.display='inline-block'; + } else { + errEl.textContent='';errEl.style.display='none'; + if(reauthBtn)reauthBtn.style.display='none'; + } document.getElementById('ts').textContent=new Date().toLocaleTimeString('en-IN',{timeZone:'Asia/Kolkata',hour12:false})+' IST'; } + +async function forceReauth(){ + const btn=document.getElementById('reauth-btn'); + if(btn){btn.textContent='Authing\u2026';btn.disabled=true;} + try{ + const r=await fetch('/api/reauth',{method:'POST'}).then(function(x){return x.json();}); + if(r.ok){await refresh();await loadAnalysis();} + else{alert('Reauth failed: '+r.error);} + }catch(e){alert('Reauth error: '+String(e));} + if(btn){btn.textContent='\u26a1 Reauth';btn.disabled=false;} + loadHealth(); +} async function loadConfig(){ const {global:g}=await fetch('/api/config').then(r=>r.json()).catch(()=>({})); if(!g)return; diff --git a/src/api/server.ts b/src/api/server.ts index 3348d45..9901a76 100644 --- a/src/api/server.ts +++ b/src/api/server.ts @@ -86,6 +86,18 @@ export function createServer(): express.Application { res.json({ ok: true, message: 'Refresh complete' }); }); + // ── POST /api/reauth ────────────────────────────────────────────────────── + // Force a fresh Angel One login (use when token has expired) + app.post('/api/reauth', async (_req, res) => { + try { + const { login } = await import('../angel/auth.js'); + await login(); + res.json({ ok: true, message: 'Re-authenticated with Angel One' }); + } catch (err) { + res.status(500).json({ ok: false, error: String(err) }); + } + }); + // ── GET /api/pnl-history ────────────────────────────────────────────────── // Returns P&L snapshots for charting. ?hours=N (default 8, max 72) app.get('/api/pnl-history', (_req, res) => { @@ -105,15 +117,14 @@ export function createServer(): express.Application { FROM positions WHERE is_closed = 0 AND netqty != 0 `).get() as any; - // Booked P&L: fully closed positions TODAY only (netqty=0, updated today IST) + // Booked P&L: fully closed positions in the last 7 days (covers a full trading week) // Separate from open-position realised (partial fills on live legs) const bookedToday = db.prepare(` SELECT COALESCE(SUM(realised_pnl),0) as r FROM positions WHERE netqty = 0 AND realised_pnl != 0 - AND date(updated_at, '+5 hours', '+30 minutes') - = date('now', '+5 hours', '+30 minutes') + AND updated_at >= datetime('now', '-7 days') `).get() as any; // Open-position realised = partial fills on still-open legs (shown separately) @@ -149,8 +160,7 @@ export function createServer(): express.Application { const bookedRealised = (db.prepare(` SELECT COALESCE(SUM(realised_pnl),0) as r FROM positions WHERE netqty = 0 AND realised_pnl != 0 - AND date(updated_at, '+5 hours', '+30 minutes') - = date('now', '+5 hours', '+30 minutes') + AND updated_at >= datetime('now', '-7 days') `).get() as { r: number }).r; res.json({ @@ -166,18 +176,16 @@ export function createServer(): express.Application { // ── GET /api/closed-positions ───────────────────────────────────────────── - // Positions closed TODAY (IST). Groups by expiry so UI can show per-expiry view. + // Positions closed in last 7 days with realised P&L. app.get('/api/closed-positions', (_req, res) => { - const todayIST = "date('now', '+5 hours', '+30 minutes')"; - - // Today's closed positions only — filtered by IST date + // Last 7 days of closed positions (covers a full trading week + weekend buffer) const closed = db.prepare(` SELECT tradingsymbol, exchange, producttype, instrumenttype, netqty, avg_price, ltp, realised_pnl, updated_at FROM positions WHERE realised_pnl != 0 AND netqty = 0 - AND date(updated_at, '+5 hours', '+30 minutes') = date('now', '+5 hours', '+30 minutes') + AND updated_at >= datetime('now', '-7 days') ORDER BY ABS(realised_pnl) DESC `).all();