From 6ecc69df99f11155b04e26c2f48cfd6d71c4dcc9 Mon Sep 17 00:00:00 2001 From: ojy Date: Wed, 13 May 2026 04:49:23 +0000 Subject: [PATCH] Add price-range zoom controls to the P/L chart MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit −/+ buttons (with a ±% readout) and a Fit button in the chart header widen or narrow the underlying-price window the curve is sampled over, so you can inspect a tight range around spot or zoom out to see the full payoff shape. Bumped sampling density to 221 points. Co-Authored-By: Claude Sonnet 4.6 --- frontend/strategy.html | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/frontend/strategy.html b/frontend/strategy.html index 98de95c..520fb3b 100644 --- a/frontend/strategy.html +++ b/frontend/strategy.html @@ -96,13 +96,23 @@
-
+

Profit / Loss vs. Underlying Price

-
- Now - - Exp - +
+ +
+ + + + +
+ +
+ Now + + Exp + +
@@ -300,6 +310,7 @@ // state symbol: '', symbols: [], spot: 0, legs: [], dteOffset: 0, + xZoom: 1, lastHalfPct: 0, refreshing: false, showManual: false, toast: '', manual: { side:'long', type:'call', qty:1, strike:null, expiry:'', entryPrice:null, ivPct:null }, chart: null, _renderTimer: null, @@ -517,6 +528,9 @@ clearTimeout(this._renderTimer); this._renderTimer = setTimeout(() => this.renderChart(), 40); }, + zoomIn() { this.xZoom = Math.max(0.2, +(this.xZoom / 1.4).toFixed(3)); this.renderChart(); }, + zoomOut() { this.xZoom = Math.min(8, +(this.xZoom * 1.4).toFixed(3)); this.renderChart(); }, + zoomFit() { this.xZoom = 1; this.renderChart(); }, renderChart() { const legs = this.activeLegs, net = this.netCost; @@ -528,10 +542,12 @@ const strikes = legs.map(l=>l.strike); const minK = Math.min(...strikes), maxK = Math.max(...strikes); const span = maxK - minK; - const half = Math.max(spot*0.22, span*1.5, (maxK-spot)*1.4, (spot-minK)*1.4, 5); + const baseHalf = Math.max(spot*0.22, span*1.5, (maxK-spot)*1.4, (spot-minK)*1.4, 5); + const half = baseHalf * (this.xZoom || 1); const lo = Math.max(0.01, spot - half), hi = spot + half; + this.lastHalfPct = spot > 0 ? Math.round(half / spot * 100) : 0; const expAt = this.minDTE; - const N = 161; + const N = 221; // x-grid = evenly spaced points + the exact strike kinks (so payoff // vertices — butterfly peak, condor body, etc. — render sharply) const xGrid = [];