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 @@
—
-
+
+
Checking
@@ -179,7 +180,7 @@
-
Booked P&L Today
—
Closed legs realised
+
Booked PnL (7d)
—
Closed legs realised
@@ -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();