fix: tab filtering uses filtered not open; tab class quote; booked=netqty=0 today only
This commit is contained in:
parent
e8bb8fdd30
commit
a1945d06e2
2 changed files with 17 additions and 12 deletions
|
|
@ -156,7 +156,7 @@
|
|||
</nav>
|
||||
<div class="g3">
|
||||
<div class="card pcard pu"><div class="plbl">Unrealised P&L</div><div class="pval fl" id="v-u">—</div><div class="psub">Open positions MTM</div></div>
|
||||
<div class="card pcard pr"><div class="plbl">Realised P&L</div><div class="pval fl" id="v-r">—</div><div class="psub">Closed legs today</div></div>
|
||||
<div class="card pcard pr"><div class="plbl">Realised P&L</div><div class="pval fl" id="v-r">—</div><div class="psub">Booked today (netqty=0)</div></div>
|
||||
<div class="card pcard pt"><div class="plbl">Total P&L</div><div class="pval fl" id="v-t">—</div><div class="psub">Unrealised + Realised</div></div>
|
||||
</div>
|
||||
<div class="g6" id="market-grid">
|
||||
|
|
@ -307,7 +307,7 @@ async function loadChart(h=8){
|
|||
curH=h;['b2','b8','b24','b72'].forEach(id=>document.getElementById(id)?.classList.remove('on'));
|
||||
document.getElementById({2:'b2',8:'b8',24:'b24',72:'b72'}[h])?.classList.add('on');
|
||||
const {summary,history}=await fetch('/api/pnl-history?hours='+h).then(r=>r.json());
|
||||
if(summary){const set=(id,v)=>{const e=document.getElementById(id);e.textContent=fmt(v);e.className='pval '+cls(v)};set('v-u',summary.totalUnrealised);set('v-r',summary.totalRealised);set('v-t',summary.totalPnl);document.getElementById('s-pos').textContent=summary.openPositions;var bEl=document.getElementById('s-booked');if(bEl){bEl.textContent=fmt(summary.bookedPnl||0);bEl.className='sval '+cls(summary.bookedPnl||0);}}
|
||||
if(summary){const set=(id,v)=>{const e=document.getElementById(id);e.textContent=fmt(v);e.className='pval '+cls(v)};set('v-u',summary.totalUnrealised);set('v-r',summary.bookedPnl||0);set('v-t',summary.totalPnl);document.getElementById('s-pos').textContent=summary.openPositions;var bEl=document.getElementById('s-booked');if(bEl){bEl.textContent=fmt(summary.bookedPnl||0);bEl.className='sval '+cls(summary.bookedPnl||0);}var bEl=document.getElementById('s-booked');if(bEl){bEl.textContent=fmt(summary.bookedPnl||0);bEl.className='sval '+cls(summary.bookedPnl||0);}}
|
||||
const canvas=document.getElementById('pnl-chart'),empty=document.getElementById('chart-empty');
|
||||
if(!history||history.length<2){canvas.style.display='none';empty.classList.add('show');return;}
|
||||
canvas.style.display='block';empty.classList.remove('show');
|
||||
|
|
@ -374,7 +374,7 @@ async function loadPositions(){
|
|||
if(expiries.length>2){
|
||||
tabsEl.style.display='flex';
|
||||
tabsEl.innerHTML=expiries.map(function(e){
|
||||
return '<button class="exp-tab'+(e===_activeExpiry?' active':'"')+'" onclick="event.stopPropagation();setExpiry(this,\''+e+'\')">'+
|
||||
return '<button class="exp-tab'+(e===_activeExpiry?' active':'')+'" onclick="event.stopPropagation();setExpiry(this,\''+e+'\')">'+
|
||||
(e==='ALL'?'All Expiries':e)+'</button>';
|
||||
}).join('');
|
||||
} else {
|
||||
|
|
@ -391,7 +391,7 @@ async function loadPositions(){
|
|||
// Update collapsed header badge
|
||||
const phEl=document.getElementById('pos-hpnl');
|
||||
if(phEl){phEl.textContent=fmt(sT);phEl.className='';phEl.style.cssText='font-family:Geist Mono,monospace;font-size:.75rem;font-weight:600;display:inline;color:'+(sT>50?'var(--green)':sT<-50?'var(--red)':'var(--text2)');}
|
||||
tbody.innerHTML=open.map(p=>{const tte=parseTTE(p.tradingsymbol);return'<tr><td><div class="sym">'+p.tradingsymbol+'</div><div class="sym-meta">'+p.exchange+' \u00b7 '+p.producttype+'</div>'+(tte?'<div class="tte">'+tte+'</div>':'')+'</td><td class="'+(p.netqty<0?'qs':'ql')+'">'+(p.netqty>0?'+':'')+p.netqty+'</td><td class="mono">\u20b9'+(+p.ltp).toFixed(2)+'</td><td class="mono" style="color:var(--text2)">\u20b9'+(+p.avg_price).toFixed(2)+'</td><td class="mono '+cls(p.unrealised_pnl)+'">'+fmt(p.unrealised_pnl)+'</td><td class="mono '+cls(p.realised_pnl)+'">'+fmt(p.realised_pnl)+'</td><td class="mono '+cls(p.total_pnl)+'" style="font-weight:600">'+fmt(p.total_pnl)+'</td></tr>';}).join('');
|
||||
tbody.innerHTML=filtered.map(p=>{const tte=parseTTE(p.tradingsymbol);return'<tr><td><div class="sym">'+p.tradingsymbol+'</div><div class="sym-meta">'+p.exchange+' \u00b7 '+p.producttype+'</div>'+(tte?'<div class="tte">'+tte+'</div>':'')+'</td><td class="'+(p.netqty<0?'qs':'ql')+'">'+(p.netqty>0?'+':'')+p.netqty+'</td><td class="mono">\u20b9'+(+p.ltp).toFixed(2)+'</td><td class="mono" style="color:var(--text2)">\u20b9'+(+p.avg_price).toFixed(2)+'</td><td class="mono '+cls(p.unrealised_pnl)+'">'+fmt(p.unrealised_pnl)+'</td><td class="mono '+cls(p.realised_pnl)+'">'+fmt(p.realised_pnl)+'</td><td class="mono '+cls(p.total_pnl)+'" style="font-weight:600">'+fmt(p.total_pnl)+'</td></tr>';}).join('');
|
||||
tfoot.style.display='';
|
||||
const sf=(id,v)=>{const e=document.getElementById(id);e.textContent=fmt(v);e.className='mono '+cls(v)};sf('f-u',sU);sf('f-r',sR);sf('f-t',sT);
|
||||
document.getElementById('override-body').innerHTML=filtered.map(p=>'<tr><td><div class="sym" style="font-size:.75rem">'+p.tradingsymbol+'</div></td><td><input type="number" min="1" max="50" step="0.5" placeholder="Global default" id="op-'+p.key+'" style="width:130px;padding:4px 8px;border-radius:7px;border:1px solid var(--border2);background:var(--bg3);color:var(--text);font-size:.75rem;font-family:\'Geist Mono\',monospace;outline:none"/></td><td><input type="datetime-local" id="om-'+p.key+'" style="padding:4px 8px;border-radius:7px;border:1px solid var(--border2);background:var(--bg3);color:var(--text);font-size:.72rem;outline:none"/></td><td><button onclick="saveOverride(\''+p.key+'\')" style="padding:3px 10px;border-radius:7px;background:var(--bg3);border:1px solid var(--border2);color:var(--text2);font-size:.72rem;cursor:pointer">Save</button></td></tr>').join('');
|
||||
|
|
|
|||
|
|
@ -105,30 +105,35 @@ export function createServer(): express.Application {
|
|||
FROM positions WHERE is_closed = 0 AND netqty != 0
|
||||
`).get() as any;
|
||||
|
||||
// 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(`
|
||||
// Booked P&L: fully closed positions TODAY only (netqty=0, updated today IST)
|
||||
// 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 realised_pnl != 0
|
||||
WHERE netqty = 0
|
||||
AND realised_pnl != 0
|
||||
AND date(updated_at, '+5 hours', '+30 minutes')
|
||||
= date('now', '+5 hours', '+30 minutes')
|
||||
`).get() as any;
|
||||
|
||||
// Open-position realised = partial fills on still-open legs (shown separately)
|
||||
const totalUnrealised = liveOpen.u;
|
||||
const totalRealised = liveOpen.r + closedRealised.r;
|
||||
const openRealised = liveOpen.r;
|
||||
const bookedPnl = bookedToday.r;
|
||||
const totalRealised = openRealised + bookedPnl;
|
||||
const totalPnl = totalUnrealised + totalRealised;
|
||||
const closedRealised = bookedToday; // keep alias for summary below
|
||||
|
||||
const latest = rows[rows.length - 1] as any;
|
||||
res.json({
|
||||
ok: true,
|
||||
summary: {
|
||||
totalUnrealised,
|
||||
openRealised,
|
||||
bookedPnl,
|
||||
totalRealised,
|
||||
totalPnl,
|
||||
openPositions: liveOpen.cnt,
|
||||
bookedPnl: closedRealised.r,
|
||||
asOf: latest?.recorded_at ?? new Date().toISOString(),
|
||||
},
|
||||
history: rows,
|
||||
|
|
@ -143,7 +148,7 @@ 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 realised_pnl != 0
|
||||
WHERE netqty = 0 AND realised_pnl != 0
|
||||
AND date(updated_at, '+5 hours', '+30 minutes')
|
||||
= date('now', '+5 hours', '+30 minutes')
|
||||
`).get() as { r: number }).r;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue