From 08b38c5d7080ce11ddfd9aa456c01661bc1cdece Mon Sep 17 00:00:00 2001 From: heyitsStylez Date: Thu, 15 Oct 2026 22:46:08 +0800 Subject: [PATCH] =?UTF-8?q?Wheeler:=20show=20negative=20net=20premium=20as?= =?UTF-8?q?=20=E2=88=92$X=20and=20hide=20%=20kept=20on=20rolled=20legs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A CLOSED leg whose buy-back exceeds its premium (common on a roll) rendered as "+$-288"; it now shows "−$288" in red. The % kept badge is suppressed on legs tagged ↻ rolled, where it reads as a misleading loss. --- src/js/core/06-render-table.js | 21 +++++++++++++++++---- test/integration/wheeler-app.test.js | 5 +++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/js/core/06-render-table.js b/src/js/core/06-render-table.js index 328605e..7ae667e 100644 --- a/src/js/core/06-render-table.js +++ b/src/js/core/06-render-table.js @@ -166,8 +166,12 @@ function _openRow(r) { // "↻ rolled" tag on a CLOSED leg that was rolled into a new option (Wheeler // roll: the replacement carries rolledFrom = this id). Derived, so deleting the // replacement drops the tag. +function _isRolled(r) { + return r.outcome === 'CLOSED' && trades.some(t => t.rolledFrom === r.id); +} + function _rolledTag(r) { - if (r.outcome !== 'CLOSED' || !trades.some(t => t.rolledFrom === r.id)) return ''; + if (!_isRolled(r)) return ''; return '\u21bb rolled'; } @@ -175,13 +179,22 @@ function _rolledTag(r) { // collected premium you kept by closing early. Hidden when there is no premium // to capture. Graded green/orange/red by how much was kept. function _captureBadge(r) { - if (r.outcome !== 'CLOSED') return ''; + if (r.outcome !== 'CLOSED' || _isRolled(r)) return ''; const pct = capturePct(r.premium, r.closeCost); if (pct === null) return ''; const col = pct >= 70 ? 'var(--green)' : pct >= 40 ? 'var(--orange)' : 'var(--red)'; return '' + Math.round(pct) + '% kept'; } +// Net premium of a CLOSED leg (premium − closeCost). A buy-back above the +// premium (common on a roll) goes negative: show "−$X" in red, not "+$-X". +function _netPremHtml(r) { + const net = r.premium - (r.closeCost || 0); + return net < 0 + ? '\u2212$' + fmt(-net) + '' + : '+$' + fmt(net); +} + // "days early" tag for a buy-to-close — days still on the clock at close // (expiry − closeDate). Completes the close-vs-hold story next to % kept. function _daysEarlyTag(r) { @@ -211,7 +224,7 @@ function _histRow(r) { + '$' + fmt(r.strike) + '' + '' + fmtSize(r.size, r.asset) + '' + '' + (r.outcome === 'CLOSED' - ? '+$' + fmt(r.premium - (r.closeCost || 0)) + '
-$' + fmt(r.closeCost || 0) + ' to close' + ? _netPremHtml(r) + '
-$' + fmt(r.closeCost || 0) + ' to close' : '+$' + fmt(r.premium)) + '' + '' + aprStr + '' + '' + outcomeLabel(r) + '' @@ -267,7 +280,7 @@ function _histCard(r) { const platBadge = r.platform === 'HSFC' ? 'HSFC' : 'RYSK'; const outBadge = '' + outcomeLabel(r) + '' + _captureBadge(r) + _rolledTag(r); const premHtml = r.outcome === 'CLOSED' - ? '+$' + fmt(r.premium - (r.closeCost || 0)) + ? _netPremHtml(r) : '+$' + fmt(r.premium); const corrBtn = r.outcome === 'EXPIRED' && r.type === 'CALL' ? '' diff --git a/test/integration/wheeler-app.test.js b/test/integration/wheeler-app.test.js index f25be7d..d51e62a 100644 --- a/test/integration/wheeler-app.test.js +++ b/test/integration/wheeler-app.test.js @@ -515,5 +515,10 @@ test('Roll button rolls an open PUT: old CLOSED, new OPEN linked', async (t) => // History shows the closed leg tagged as rolled; the open table has the new leg. assert.match(doc.getElementById('ttbody-hist').innerHTML, /↻ rolled/); + // Buy-back > premium: net shows as −$70 (not "+$-70"), and no "% kept" badge on a rolled leg. + const hist = doc.getElementById('ttbody-hist').innerHTML; + assert.match(hist, /\u2212\$70/); + assert.doesNotMatch(hist, /\+\$-/); + assert.doesNotMatch(hist, /% kept/); assert.match(doc.getElementById('ttbody-open').innerHTML, /195/); });