Editable strike in legs — re-prices from loaded chain
The Strike cell becomes a dropdown of available strikes (for that leg's symbol+expiry+type) drawn from the cached chain — seeded from chain.html's last-loaded chain (localStorage) and refreshed by the strategy page's own per-expiry chain fetch on open / Reload. Picking a new strike updates the leg's entry price, IV and mark from that contract and clears the lock. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -165,7 +165,12 @@
|
|||||||
</td>
|
</td>
|
||||||
<td style="width:5rem"><input type="number" min="1" step="1" class="form-control form-control-sm" :value="lv.qty" @change="updateLeg(lv.id, { qty: Math.max(1, Math.round(+$event.target.value||1)) })"></td>
|
<td style="width:5rem"><input type="number" min="1" step="1" class="form-control form-control-sm" :value="lv.qty" @change="updateLeg(lv.id, { qty: Math.max(1, Math.round(+$event.target.value||1)) })"></td>
|
||||||
<td><span class="badge" :class="lv.type==='call' ? 'bg-success-lt text-success' : 'bg-danger-lt text-danger'" x-text="lv.type"></span></td>
|
<td><span class="badge" :class="lv.type==='call' ? 'bg-success-lt text-success' : 'bg-danger-lt text-danger'" x-text="lv.type"></span></td>
|
||||||
<td class="text-end mono" x-text="lv.strike"></td>
|
<td class="text-end mono" style="width:7rem">
|
||||||
|
<select x-show="hasStrikeOpts(lv)" class="form-select form-select-sm text-end" :value="lv.strike" @change="changeStrike(lv.id, +$event.target.value)" title="Change strike — entry price, IV & mark update from the loaded chain">
|
||||||
|
<template x-for="k in strikeOpts(lv)" :key="k"><option :value="k" x-text="k"></option></template>
|
||||||
|
</select>
|
||||||
|
<span x-show="!hasStrikeOpts(lv)" x-text="lv.strike"></span>
|
||||||
|
</td>
|
||||||
<td class="mono small" x-text="lv.expiry"></td>
|
<td class="mono small" x-text="lv.expiry"></td>
|
||||||
<td style="width:8.5rem">
|
<td style="width:8.5rem">
|
||||||
<div class="input-group input-group-sm flex-nowrap">
|
<div class="input-group input-group-sm flex-nowrap">
|
||||||
@@ -314,15 +319,59 @@
|
|||||||
refreshing: false, showManual: false, toast: '',
|
refreshing: false, showManual: false, toast: '',
|
||||||
manual: { side:'long', type:'call', qty:1, strike:null, expiry:'', entryPrice:null, ivPct:null },
|
manual: { side:'long', type:'call', qty:1, strike:null, expiry:'', entryPrice:null, ivPct:null },
|
||||||
chart: null, _renderTimer: null,
|
chart: null, _renderTimer: null,
|
||||||
|
_chainCache: {}, // "SYMBOL@EXPIRY" -> { "strike@type": optionRow }
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this.reload();
|
this.reload();
|
||||||
// pull live spot / marks / IVs on open (does NOT touch entry prices)
|
this._chainCache = this._seedChainCache();
|
||||||
|
// pull live spot / marks / IVs (and per-expiry chains) on open
|
||||||
if (this.legs.length > 0 && this.symbol) this.reloadMarket(false);
|
if (this.legs.length > 0 && this.symbol) this.reloadMarket(false);
|
||||||
// re-sync if another tab changed the basket
|
// re-sync if another tab changed the basket
|
||||||
window.addEventListener('storage', (e) => { if (e.key === StrategyStore.KEY) this.reload(); });
|
window.addEventListener('storage', (e) => { if (e.key === StrategyStore.KEY) this.reload(); });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// seed the strike picker from whatever chain was last loaded on chain.html
|
||||||
|
_seedChainCache() {
|
||||||
|
try {
|
||||||
|
const vs = (typeof ViewState !== 'undefined') ? ViewState.load('chain') : null;
|
||||||
|
if (!vs || !vs.symbol || !vs.expiry) return {};
|
||||||
|
const map = {};
|
||||||
|
for (const o of (vs.calls || [])) map[Number(o.strike) + '@call'] = o;
|
||||||
|
for (const o of (vs.puts || [])) map[Number(o.strike) + '@put'] = o;
|
||||||
|
return Object.keys(map).length ? { [vs.symbol + '@' + vs.expiry]: map } : {};
|
||||||
|
} catch { return {}; }
|
||||||
|
},
|
||||||
|
|
||||||
|
_legMap(lv) { return this._chainCache[lv.symbol + '@' + lv.expiry] || null; },
|
||||||
|
hasStrikeOpts(lv) {
|
||||||
|
const m = this._legMap(lv);
|
||||||
|
if (!m) return false;
|
||||||
|
for (const k of Object.keys(m)) if (k.endsWith('@' + lv.type)) return true;
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
strikeOpts(lv) {
|
||||||
|
const m = this._legMap(lv);
|
||||||
|
const out = [];
|
||||||
|
if (m) for (const k of Object.keys(m)) { if (k.endsWith('@' + lv.type)) out.push(parseFloat(k)); }
|
||||||
|
if (!out.includes(lv.strike)) out.push(lv.strike);
|
||||||
|
return out.sort((a, b) => a - b);
|
||||||
|
},
|
||||||
|
changeStrike(id, newStrike) {
|
||||||
|
const leg = this.legs.find(l => l.id === id);
|
||||||
|
if (!leg || !Number.isFinite(newStrike) || newStrike === leg.strike) return;
|
||||||
|
const m = this._legMap(leg);
|
||||||
|
const o = m && m[Number(newStrike) + '@' + leg.type];
|
||||||
|
const patch = { strike: newStrike };
|
||||||
|
if (o) {
|
||||||
|
const mid = Math.round(((o.midPrice ?? o.mid ?? o.bsPrice ?? leg.entryPrice) || 0) * 100) / 100;
|
||||||
|
patch.entryPrice = mid;
|
||||||
|
patch.currentMark = mid;
|
||||||
|
if (o.iv > 0) patch.iv = o.iv;
|
||||||
|
patch.locked = false; // it's a different contract now — start fresh
|
||||||
|
}
|
||||||
|
this.updateLeg(id, patch);
|
||||||
|
},
|
||||||
|
|
||||||
reload() {
|
reload() {
|
||||||
const st = StrategyStore.load();
|
const st = StrategyStore.load();
|
||||||
this.symbol = st.symbol || '';
|
this.symbol = st.symbol || '';
|
||||||
@@ -492,6 +541,10 @@
|
|||||||
}
|
}
|
||||||
byExpiry[exp] = map;
|
byExpiry[exp] = map;
|
||||||
}
|
}
|
||||||
|
// make these chains available to the strike picker
|
||||||
|
const cacheAdds = {};
|
||||||
|
for (const exp of Object.keys(byExpiry)) cacheAdds[this.symbol + '@' + exp] = byExpiry[exp];
|
||||||
|
this._chainCache = { ...this._chainCache, ...cacheAdds };
|
||||||
const st = StrategyStore.load();
|
const st = StrategyStore.load();
|
||||||
let updated = 0, relinked = 0;
|
let updated = 0, relinked = 0;
|
||||||
for (const leg of st.legs) {
|
for (const leg of st.legs) {
|
||||||
|
|||||||
Reference in New Issue
Block a user