diff --git a/frontend/strategy.html b/frontend/strategy.html index 8e36b21..13742a3 100644 --- a/frontend/strategy.html +++ b/frontend/strategy.html @@ -87,66 +87,6 @@ - -
-
-

Legs

-
- - Net : - - - -
-
-
- - - - - - - - - - - - - - -
SideQtyTypeStrikeExpiryEntry $IVCostΔΘ/d
-
-
-
@@ -175,6 +115,69 @@
Net Vega / 1%
+ +
+
+

Legs — uncheck a leg to drop it from the chart

+
+ + Net : + + + +
+
+
+ + + + + + + + + + + + + + + +
ShowSideQtyTypeStrikeExpiryEntry $IVCostΔΘ/d
+
+
+
@@ -298,12 +301,14 @@ }, // ── derived ─────────────────────────────────────────── - get netCost() { return this.legs.reduce((s,l)=> s + legCost(l), 0); }, - get strategyName() { return detectStrategy(this.legs); }, - get maxDTE() { return Math.max(1, Math.ceil(Math.max(0, ...this.legs.map(legDTE)))); }, + // only legs with the "Show" checkbox ticked drive the chart / stats / Greeks + get activeLegs() { return this.legs.filter(l => l.enabled !== false); }, + get netCost() { return this.activeLegs.reduce((s,l)=> s + legCost(l), 0); }, + get strategyName() { return detectStrategy(this.activeLegs); }, + get maxDTE() { const a = this.activeLegs; return a.length ? Math.max(1, Math.ceil(Math.max(0, ...a.map(legDTE)))) : 1; }, // exact (not floored) days to the earliest expiry — so the "expiration" // curve uses true intrinsic value (sharp hockey stick), not a near-expiry BS approx - get minDTE() { return Math.max(0, Math.min(...this.legs.map(legDTE))); }, + get minDTE() { const a = this.activeLegs; return a.length ? Math.max(0, Math.min(...a.map(legDTE))) : 0; }, get dteLabel() { const d = new Date(Date.now() + this.dteOffset * DAY_MS); const ds = d.toISOString().slice(0,10); @@ -331,7 +336,8 @@ }, get stats() { - const legs = this.legs, net = this.netCost, spot = this.spot; + const legs = this.activeLegs, net = this.netCost, spot = this.spot; + if (legs.length === 0) return { maxProfit:'—', maxLoss:'—', breakevens:'—', delta:0, gamma:0, theta:0, vega:0 }; // dense expiration-curve sample for breakevens / extremes / unbounded const lo0 = 0.01; const hi0 = Math.max(spot * 2, ...legs.map(l=>l.strike)) * 1.5 + 10; @@ -386,6 +392,16 @@ StrategyStore.updateLeg(id, patch); this.reload(); }, + toggleLeg(id) { + const leg = this.legs.find(l => l.id === id); + const cur = leg ? leg.enabled !== false : true; + StrategyStore.updateLeg(id, { enabled: !cur }); + // refresh legs without resetting the date slider + const st = StrategyStore.load(); + this.legs = st.legs || []; + if (this.dteOffset > this.maxDTE) this.dteOffset = this.maxDTE; + this.$nextTick(() => this.renderChart()); + }, removeLeg(id) { StrategyStore.removeLeg(id); this.reload(); @@ -442,8 +458,11 @@ }, renderChart() { - if (this.legs.length === 0) return; - const legs = this.legs, net = this.netCost; + const legs = this.activeLegs, net = this.netCost; + if (legs.length === 0) { + if (this.chart) this.chart.updateSeries([{ name: 'P/L', data: [] }, { name: 'P/L', data: [] }]); + return; + } const spot = this.spot > 0 ? this.spot : (legs.reduce((s,l)=>s+l.strike,0)/legs.length); const strikes = legs.map(l=>l.strike); const minK = Math.min(...strikes), maxK = Math.max(...strikes);