diff --git a/frontend/strategy.html b/frontend/strategy.html index c6c3f5e..9210248 100644 --- a/frontend/strategy.html +++ b/frontend/strategy.html @@ -301,7 +301,9 @@ 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)))); }, - get minDTE() { return Math.max(0, Math.floor(Math.min(...this.legs.map(legDTE)))); }, + // 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 dteLabel() { const d = new Date(Date.now() + this.dteOffset * DAY_MS); const ds = d.toISOString().slice(0,10); @@ -441,19 +443,25 @@ 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.30, span*1.4, (maxK-spot)*1.3, (spot-minK)*1.3, 5); + const half = Math.max(spot*0.22, span*1.5, (maxK-spot)*1.4, (spot-minK)*1.4, 5); const lo = Math.max(0.01, spot - half), hi = spot + half; - const N = 141; + const expAt = this.minDTE; + const N = 161; const expData = [], tnData = []; let yMin = Infinity, yMax = -Infinity; for (let i = 0; i <= N; i++) { const x = lo + (hi-lo)*i/N; - const ye = plAt(legs, net, x, this.minDTE); + const ye = plAt(legs, net, x, expAt); const yt = plAt(legs, net, x, this.dteOffset); expData.push([x, +ye.toFixed(2)]); tnData.push([x, +yt.toFixed(2)]); yMin = Math.min(yMin, ye, yt); yMax = Math.max(yMax, ye, yt); } + // Keep the chart readable when one tail is (near-)unbounded: don't let it + // dominate the y-axis so badly the rest of the curve is a flat sliver. + const aHi = Math.max(yMax, 0), aLo = Math.max(-yMin, 0); + if (aLo > 1 && aHi > 6 * aLo) yMax = 6 * aLo; + if (aHi > 1 && aLo > 6 * aHi) yMin = -6 * aHi; const pad = Math.max((yMax - yMin) * 0.08, 1); yMin -= pad; yMax += pad;