Round leg prices to 2 decimals everywhere
Entry price, mark and strike are now rounded to 2dp on add, on edit, on market reload, and on load (self-heals legacy entries) — fixes display of float artifacts like "15.000000001". Also persist the leg's locked/currentMark fields in the store. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,12 @@
|
|||||||
const VERSION = 1;
|
const VERSION = 1;
|
||||||
const MULTIPLIER = 100; // standard equity option contract size
|
const MULTIPLIER = 100; // standard equity option contract size
|
||||||
|
|
||||||
|
/** Round a price to 2 decimals (kills float artifacts like 15.000000001). */
|
||||||
|
function round2(v) {
|
||||||
|
const n = Number(v);
|
||||||
|
return Number.isFinite(n) ? Math.round(n * 100) / 100 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
function empty() {
|
function empty() {
|
||||||
return { v: VERSION, symbol: "", spotSnapshot: 0, updatedAt: null, legs: [] };
|
return { v: VERSION, symbol: "", spotSnapshot: 0, updatedAt: null, legs: [] };
|
||||||
}
|
}
|
||||||
@@ -31,10 +37,15 @@
|
|||||||
if (!raw) return empty();
|
if (!raw) return empty();
|
||||||
const obj = JSON.parse(raw);
|
const obj = JSON.parse(raw);
|
||||||
if (!obj || obj.v !== VERSION || !Array.isArray(obj.legs)) return empty();
|
if (!obj || obj.v !== VERSION || !Array.isArray(obj.legs)) return empty();
|
||||||
// sanitize: drop legs with no usable strike / type
|
// sanitize: drop legs with no usable strike / type; round prices to 2dp (self-heal)
|
||||||
obj.legs = obj.legs.filter(
|
obj.legs = obj.legs
|
||||||
(l) => l && Number.isFinite(Number(l.strike)) && (l.type === "call" || l.type === "put")
|
.filter((l) => l && Number.isFinite(Number(l.strike)) && (l.type === "call" || l.type === "put"))
|
||||||
);
|
.map((l) => ({
|
||||||
|
...l,
|
||||||
|
strike: round2(l.strike),
|
||||||
|
entryPrice: round2(l.entryPrice),
|
||||||
|
currentMark: (typeof l.currentMark === "number" ? round2(l.currentMark) : (l.currentMark ?? null)),
|
||||||
|
}));
|
||||||
return obj;
|
return obj;
|
||||||
} catch {
|
} catch {
|
||||||
return empty();
|
return empty();
|
||||||
@@ -84,11 +95,13 @@
|
|||||||
symbol: leg.symbol || state.symbol,
|
symbol: leg.symbol || state.symbol,
|
||||||
expiry: leg.expiry,
|
expiry: leg.expiry,
|
||||||
type: leg.type,
|
type: leg.type,
|
||||||
strike: strike,
|
strike: round2(strike),
|
||||||
side: leg.side === "short" ? "short" : "long",
|
side: leg.side === "short" ? "short" : "long",
|
||||||
qty: Math.max(1, Math.round(Number(leg.qty) || 1)),
|
qty: Math.max(1, Math.round(Number(leg.qty) || 1)),
|
||||||
entryPrice: Number(leg.entryPrice) || 0,
|
entryPrice: round2(leg.entryPrice),
|
||||||
iv: Number(leg.iv) || 0,
|
iv: Number(leg.iv) || 0,
|
||||||
|
locked: leg.locked === true,
|
||||||
|
currentMark: (typeof leg.currentMark === "number" ? round2(leg.currentMark) : null),
|
||||||
});
|
});
|
||||||
save(state);
|
save(state);
|
||||||
return { state, replacedSymbol };
|
return { state, replacedSymbol };
|
||||||
@@ -105,7 +118,13 @@
|
|||||||
function updateLeg(id, patch) {
|
function updateLeg(id, patch) {
|
||||||
const state = load();
|
const state = load();
|
||||||
const leg = state.legs.find((l) => l.id === id);
|
const leg = state.legs.find((l) => l.id === id);
|
||||||
if (leg) Object.assign(leg, patch);
|
if (leg) {
|
||||||
|
const p = { ...patch };
|
||||||
|
if ("entryPrice" in p) p.entryPrice = round2(p.entryPrice);
|
||||||
|
if ("currentMark" in p && p.currentMark != null) p.currentMark = round2(p.currentMark);
|
||||||
|
if ("strike" in p) p.strike = round2(p.strike);
|
||||||
|
Object.assign(leg, p);
|
||||||
|
}
|
||||||
save(state);
|
save(state);
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -468,7 +468,7 @@
|
|||||||
if (!map) continue;
|
if (!map) continue;
|
||||||
const o = map[Number(leg.strike) + '@' + leg.type];
|
const o = map[Number(leg.strike) + '@' + leg.type];
|
||||||
if (!o) continue;
|
if (!o) continue;
|
||||||
const mark = o.midPrice ?? o.mid ?? o.bsPrice ?? 0;
|
const mark = Math.round((o.midPrice ?? o.mid ?? o.bsPrice ?? 0) * 100) / 100;
|
||||||
leg.currentMark = mark;
|
leg.currentMark = mark;
|
||||||
if (o.iv > 0) leg.iv = o.iv;
|
if (o.iv > 0) leg.iv = o.iv;
|
||||||
if (!leg.locked && mark > 0) { leg.entryPrice = mark; relinked++; }
|
if (!leg.locked && mark > 0) { leg.entryPrice = mark; relinked++; }
|
||||||
|
|||||||
Reference in New Issue
Block a user