feat: reorder cards (payoff below positions), booked=totalRealised, payoff respects expiry tab

This commit is contained in:
Manohar 2026-05-27 14:00:41 +05:30
parent a1945d06e2
commit ef459facfc

View file

@ -156,7 +156,7 @@
</nav> </nav>
<div class="g3"> <div class="g3">
<div class="card pcard pu"><div class="plbl">Unrealised P&amp;L</div><div class="pval fl" id="v-u">&#8212;</div><div class="psub">Open positions MTM</div></div> <div class="card pcard pu"><div class="plbl">Unrealised P&amp;L</div><div class="pval fl" id="v-u">&#8212;</div><div class="psub">Open positions MTM</div></div>
<div class="card pcard pr"><div class="plbl">Realised P&amp;L</div><div class="pval fl" id="v-r">&#8212;</div><div class="psub">Booked today (netqty=0)</div></div> <div class="card pcard pr"><div class="plbl">Realised P&amp;L</div><div class="pval fl" id="v-r">&#8212;</div><div class="psub">Partial + full exits today</div></div>
<div class="card pcard pt"><div class="plbl">Total P&amp;L</div><div class="pval fl" id="v-t">&#8212;</div><div class="psub">Unrealised + Realised</div></div> <div class="card pcard pt"><div class="plbl">Total P&amp;L</div><div class="pval fl" id="v-t">&#8212;</div><div class="psub">Unrealised + Realised</div></div>
</div> </div>
<div class="g6" id="market-grid"> <div class="g6" id="market-grid">
@ -196,8 +196,33 @@
<tfoot id="pos-foot" style="display:none"><tr><td colspan="4">Portfolio Total</td><td id="f-u" class="mono">&#8212;</td><td id="f-r" class="mono">&#8212;</td><td id="f-t" class="mono">&#8212;</td></tr></tfoot> <tfoot id="pos-foot" style="display:none"><tr><td colspan="4">Portfolio Total</td><td id="f-u" class="mono">&#8212;</td><td id="f-r" class="mono">&#8212;</td><td id="f-t" class="mono">&#8212;</td></tr></tfoot>
</table></div> </table></div>
</div> </div>
<div class="card collapsible" id="sec-payoff" style="margin-bottom:16px">
<div class="card-head" onclick="toggleCard('sec-payoff')">
<span class="card-title">Strategy Payoff at Expiry</span>
<div style="display:flex;align-items:center;gap:8px">
<span id="pf-ul" style="font-size:.7rem;font-weight:600;color:var(--text2);font-family:Geist Mono,monospace"></span>
<span id="pf-strat" style="font-size:.68rem;padding:2px 8px;border-radius:9999px;background:var(--bg3);border:1px solid var(--border2);color:var(--text2)"></span>
</div>
<span class="collapse-arrow">&#9660;</span>
</div>
<div class="collapse-body">
<div style="display:grid;grid-template-columns:repeat(6,1fr);border-bottom:1px solid var(--border)">
<div class="pf-stat"><div class="pfs-l">NET PREMIUM</div><div class="pfs-v" id="pf-prem">&#8212;</div></div>
<div class="pf-stat"><div class="pfs-l">MAX PROFIT</div><div class="pfs-v up" id="pf-maxp">&#8212;</div></div>
<div class="pf-stat"><div class="pfs-l">MAX LOSS</div><div class="pfs-v dn" id="pf-maxl">&#8212;</div></div>
<div class="pf-stat"><div class="pfs-l">REWARD/RISK</div><div class="pfs-v" id="pf-rr">&#8212;</div></div>
<div class="pf-stat"><div class="pfs-l">BREAKEVEN(S)</div><div class="pfs-v" id="pf-be" style="font-size:.8rem">&#8212;</div></div>
<div class="pf-stat"><div class="pfs-l">DTE</div><div class="pfs-v" id="pf-dte">&#8212;</div></div>
</div>
<div style="padding:14px 16px 10px;height:250px;position:relative">
<canvas id="payoff-chart"></canvas>
<div id="pf-empty" style="display:none;position:absolute;inset:0;align-items:center;justify-content:center;color:var(--text3);font-size:.8rem;flex-direction:column;gap:6px">
<span style="font-size:1.4rem">&#128200;</span><span>No option positions to analyse</span>
</div>
</div>
<div style="padding:0 16px 10px;font-size:.63rem;color:var(--text3)">Theoretical payoff at expiry based on avg cost. Does not account for time value or IV. Current spot shown as vertical line.</div>
</div>
</div>
<div class="card collapsible" id="sec-closed" style="margin-bottom:16px"> <div class="card collapsible" id="sec-closed" style="margin-bottom:16px">
<div class="card-head" onclick="toggleCard('sec-closed')"> <div class="card-head" onclick="toggleCard('sec-closed')">
<span class="card-title">Closed / Booked Positions</span> <span class="card-title">Closed / Booked Positions</span>
@ -234,33 +259,6 @@
<div id="closed-stale" style="display:none;padding:10px 18px;font-size:.7rem;color:var(--amber);border-top:1px solid var(--border)"></div> <div id="closed-stale" style="display:none;padding:10px 18px;font-size:.7rem;color:var(--amber);border-top:1px solid var(--border)"></div>
</div> </div>
</div> </div>
<div class="card collapsible" id="sec-payoff" style="margin-bottom:16px">
<div class="card-head" onclick="toggleCard('sec-payoff')">
<span class="card-title">Strategy Payoff at Expiry</span>
<div style="display:flex;align-items:center;gap:8px">
<span id="pf-ul" style="font-size:.7rem;font-weight:600;color:var(--text2);font-family:Geist Mono,monospace"></span>
<span id="pf-strat" style="font-size:.68rem;padding:2px 8px;border-radius:9999px;background:var(--bg3);border:1px solid var(--border2);color:var(--text2)"></span>
</div>
<span class="collapse-arrow">&#9660;</span>
</div>
<div class="collapse-body">
<div style="display:grid;grid-template-columns:repeat(6,1fr);border-bottom:1px solid var(--border)">
<div class="pf-stat"><div class="pfs-l">NET PREMIUM</div><div class="pfs-v" id="pf-prem">&#8212;</div></div>
<div class="pf-stat"><div class="pfs-l">MAX PROFIT</div><div class="pfs-v up" id="pf-maxp">&#8212;</div></div>
<div class="pf-stat"><div class="pfs-l">MAX LOSS</div><div class="pfs-v dn" id="pf-maxl">&#8212;</div></div>
<div class="pf-stat"><div class="pfs-l">REWARD/RISK</div><div class="pfs-v" id="pf-rr">&#8212;</div></div>
<div class="pf-stat"><div class="pfs-l">BREAKEVEN(S)</div><div class="pfs-v" id="pf-be" style="font-size:.8rem">&#8212;</div></div>
<div class="pf-stat"><div class="pfs-l">DTE</div><div class="pfs-v" id="pf-dte">&#8212;</div></div>
</div>
<div style="padding:14px 16px 10px;height:250px;position:relative">
<canvas id="payoff-chart"></canvas>
<div id="pf-empty" style="display:none;position:absolute;inset:0;align-items:center;justify-content:center;color:var(--text3);font-size:.8rem;flex-direction:column;gap:6px">
<span style="font-size:1.4rem">&#128200;</span><span>No option positions to analyse</span>
</div>
</div>
<div style="padding:0 16px 10px;font-size:.63rem;color:var(--text3)">Theoretical payoff at expiry based on avg cost. Does not account for time value or IV. Current spot shown as vertical line.</div>
</div>
</div>
<div class="card collapsible" id="sec-alrt" style="margin-bottom:16px"> <div class="card collapsible" id="sec-alrt" style="margin-bottom:16px">
<div class="card-head" onclick="toggleCard('sec-alrt')"><span class="card-title">Alert History</span><div style="display:flex;align-items:center;gap:8px"><span id="alrt-hcount" style="font-size:.7rem;font-weight:600;padding:2px 9px;border-radius:9999px;background:rgba(245,166,35,.15);color:var(--amber);display:none"></span><span id="alrt-hmuted" style="font-size:.7rem;font-weight:600;padding:2px 9px;border-radius:9999px;background:rgba(231,76,60,.12);color:var(--red);display:none">MUTED</span></div><span class="collapse-arrow">&#9660;</span></div> <div class="card-head" onclick="toggleCard('sec-alrt')"><span class="card-title">Alert History</span><div style="display:flex;align-items:center;gap:8px"><span id="alrt-hcount" style="font-size:.7rem;font-weight:600;padding:2px 9px;border-radius:9999px;background:rgba(245,166,35,.15);color:var(--amber);display:none"></span><span id="alrt-hmuted" style="font-size:.7rem;font-weight:600;padding:2px 9px;border-radius:9999px;background:rgba(231,76,60,.12);color:var(--red);display:none">MUTED</span></div><span class="collapse-arrow">&#9660;</span></div>
<div class="collapse-body"><table> <div class="collapse-body"><table>
@ -307,7 +305,7 @@ async function loadChart(h=8){
curH=h;['b2','b8','b24','b72'].forEach(id=>document.getElementById(id)?.classList.remove('on')); 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'); 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()); 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.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);}} 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||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.totalRealised||0);bEl.className='sval '+cls(summary.totalRealised||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'); 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;} if(!history||history.length<2){canvas.style.display='none';empty.classList.add('show');return;}
canvas.style.display='block';empty.classList.remove('show'); canvas.style.display='block';empty.classList.remove('show');
@ -566,7 +564,8 @@ async function loadPayoff() {
var mktRes = await fetch('/api/market').then(function(r){return r.json();}).catch(function(){return {data:[]};}); var mktRes = await fetch('/api/market').then(function(r){return r.json();}).catch(function(){return {data:[]};});
var open = (posRes.data || []).filter(function(p){return p.is_closed===0;}); var open = (posRes.data || []).filter(function(p){return p.is_closed===0;});
var opts = open.filter(function(p){return /CE|PE/.test(p.tradingsymbol);}).map(function(p){ var expFiltered=(_activeExpiry&&_activeExpiry!=='ALL')?open.filter(function(p){return expiryLabel(p.tradingsymbol)===_activeExpiry;}):open;
var opts = expFiltered.filter(function(p){return /CE|PE/.test(p.tradingsymbol);}).map(function(p){
p._parsed = parseOptionSym(p.tradingsymbol); p._parsed = parseOptionSym(p.tradingsymbol);
return p; return p;
}).filter(function(p){return p._parsed !== null;}); }).filter(function(p){return p._parsed !== null;});
@ -760,6 +759,7 @@ function setExpiry(btn,exp){
if(row) row.querySelectorAll('.exp-tab').forEach(function(b){b.classList.remove('active');}); if(row) row.querySelectorAll('.exp-tab').forEach(function(b){b.classList.remove('active');});
if(btn) btn.classList.add('active'); if(btn) btn.classList.add('active');
loadPositions(); loadPositions();
loadPayoff();
} }
loadConfig();refresh(); loadConfig();refresh();
setInterval(refresh,60000); setInterval(refresh,60000);