Show OTM option quotes in option-option mode.
Align session to amplitude Call/Put pair and replace perp/ATM market panels. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -204,9 +204,21 @@ export type MarketSnapshot = {
|
||||
index_px: number | null;
|
||||
exchange?: string;
|
||||
perp_inst_id?: string;
|
||||
hedge_mode?: "perp_option" | "option_option";
|
||||
oo_amplitude?: {
|
||||
high?: number;
|
||||
low?: number;
|
||||
mid?: number;
|
||||
range_pct?: number;
|
||||
hours?: number;
|
||||
min_pct?: number;
|
||||
ok?: boolean;
|
||||
} | null;
|
||||
pair: {
|
||||
expiry_ymd: string;
|
||||
strike: number;
|
||||
call_strike?: number;
|
||||
put_strike?: number;
|
||||
call_inst_id: string;
|
||||
put_inst_id: string;
|
||||
} | null;
|
||||
|
||||
+158
-59
@@ -187,6 +187,7 @@ export default function PlanPage() {
|
||||
const pos = plan?.position;
|
||||
const isOo =
|
||||
plan?.hedge_mode === "option_option" ||
|
||||
snap?.hedge_mode === "option_option" ||
|
||||
pos?.hedge_mode === "option_option" ||
|
||||
!!pos?.option2_inst_id;
|
||||
const open = !!pos?.has_position;
|
||||
@@ -851,6 +852,11 @@ export default function PlanPage() {
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : isOo ? (
|
||||
<>
|
||||
<div className="pos-empty">Call 持仓 · 暂无</div>
|
||||
<div className="pos-empty">Put 持仓 · 暂无</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="pos-empty">永续持仓 · 暂无</div>
|
||||
@@ -861,43 +867,102 @@ export default function PlanPage() {
|
||||
</div>
|
||||
|
||||
<div className="plan-market">
|
||||
<div className="card">
|
||||
<h3 className="plan-panel-title">永续行情</h3>
|
||||
<div className="kv">
|
||||
<span>买一</span>
|
||||
<span className="mono">{fmtExPx("perp", snap?.perp?.bid)}</span>
|
||||
{isOo ? (
|
||||
<div className="card">
|
||||
<h3 className="plan-panel-title">指数 / 振幅</h3>
|
||||
<div className="kv">
|
||||
<span>指数</span>
|
||||
<span className="mono">{fmtExPx("index", snap?.index_px)}</span>
|
||||
</div>
|
||||
<div className="kv">
|
||||
<span>
|
||||
高点
|
||||
{snap?.oo_amplitude?.hours != null
|
||||
? `(${fmt(snap.oo_amplitude.hours, 0)}h)`
|
||||
: ""}
|
||||
</span>
|
||||
<span className="mono">
|
||||
{fmtExPx("index", snap?.oo_amplitude?.high)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="kv">
|
||||
<span>低点</span>
|
||||
<span className="mono">
|
||||
{fmtExPx("index", snap?.oo_amplitude?.low)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="kv">
|
||||
<span>振幅</span>
|
||||
<span className="mono">
|
||||
{snap?.oo_amplitude?.range_pct != null
|
||||
? `${fmt(snap.oo_amplitude.range_pct, 2)}%`
|
||||
: "—"}
|
||||
{snap?.oo_amplitude?.min_pct != null
|
||||
? ` · 门限≥${fmt(snap.oo_amplitude.min_pct, 1)}%`
|
||||
: ""}
|
||||
{snap?.oo_amplitude?.ok === false
|
||||
? " · 不足"
|
||||
: snap?.oo_amplitude?.ok === true
|
||||
? " · 达标"
|
||||
: ""}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="kv">
|
||||
<span>卖一</span>
|
||||
<span className="mono">{fmtExPx("perp", snap?.perp?.ask)}</span>
|
||||
) : (
|
||||
<div className="card">
|
||||
<h3 className="plan-panel-title">永续行情</h3>
|
||||
<div className="kv">
|
||||
<span>买一</span>
|
||||
<span className="mono">{fmtExPx("perp", snap?.perp?.bid)}</span>
|
||||
</div>
|
||||
<div className="kv">
|
||||
<span>卖一</span>
|
||||
<span className="mono">{fmtExPx("perp", snap?.perp?.ask)}</span>
|
||||
</div>
|
||||
<div className="kv">
|
||||
<span>市价</span>
|
||||
<span className="mono">
|
||||
{fmtExPx(
|
||||
"perp",
|
||||
snap?.perp?.mark_px ??
|
||||
(snap?.perp?.bid != null && snap?.perp?.ask != null
|
||||
? (snap.perp.bid + snap.perp.ask) / 2
|
||||
: null),
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="kv">
|
||||
<span>指数</span>
|
||||
<span className="mono">{fmtExPx("index", snap?.index_px)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="kv">
|
||||
<span>市价</span>
|
||||
<span className="mono">
|
||||
{fmtExPx(
|
||||
"perp",
|
||||
snap?.perp?.mark_px ??
|
||||
(snap?.perp?.bid != null && snap?.perp?.ask != null
|
||||
? (snap.perp.bid + snap.perp.ask) / 2
|
||||
: null),
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="kv">
|
||||
<span>指数</span>
|
||||
<span className="mono">{fmtExPx("index", snap?.index_px)}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="card">
|
||||
<h3 className="plan-panel-title">
|
||||
{open ? "持仓期权" : "期权 ATM"}
|
||||
{snap?.pair
|
||||
? ` @ ${
|
||||
snap.pair.strike != null
|
||||
? Math.round(Number(snap.pair.strike))
|
||||
: "—"
|
||||
}`
|
||||
: ""}
|
||||
{isOo
|
||||
? open
|
||||
? "持仓虚值"
|
||||
: "期期虚值"
|
||||
: open
|
||||
? "持仓期权"
|
||||
: "期权 ATM"}
|
||||
{isOo && snap?.pair
|
||||
? ` · C@${Math.round(
|
||||
Number(
|
||||
snap.pair.call_strike ?? snap.pair.strike ?? 0,
|
||||
),
|
||||
)} / P@${Math.round(
|
||||
Number(
|
||||
snap.pair.put_strike ?? snap.pair.strike ?? 0,
|
||||
),
|
||||
)}`
|
||||
: snap?.pair
|
||||
? ` @ ${
|
||||
snap.pair.strike != null
|
||||
? Math.round(Number(snap.pair.strike))
|
||||
: "—"
|
||||
}`
|
||||
: ""}
|
||||
</h3>
|
||||
{(() => {
|
||||
const under =
|
||||
@@ -921,17 +986,29 @@ export default function PlanPage() {
|
||||
: open && heldSide === "put"
|
||||
? putLev
|
||||
: null;
|
||||
const callK = snap?.pair?.call_strike ?? snap?.pair?.strike;
|
||||
const putK = snap?.pair?.put_strike ?? snap?.pair?.strike;
|
||||
return (
|
||||
<>
|
||||
<div className="kv">
|
||||
<span>Call {sideLabel}</span>
|
||||
<span>
|
||||
Call {sideLabel}
|
||||
{isOo && callK != null
|
||||
? ` @${Math.round(Number(callK))}`
|
||||
: ""}
|
||||
</span>
|
||||
<span className="mono">
|
||||
{fmtTopEx("option", callPx, callSz)}
|
||||
{!open ? ` · 杠杆 ${callLev}` : ""}
|
||||
</span>
|
||||
</div>
|
||||
<div className="kv">
|
||||
<span>Put {sideLabel}</span>
|
||||
<span>
|
||||
Put {sideLabel}
|
||||
{isOo && putK != null
|
||||
? ` @${Math.round(Number(putK))}`
|
||||
: ""}
|
||||
</span>
|
||||
<span className="mono">
|
||||
{fmtTopEx("option", putPx, putSz)}
|
||||
{!open ? ` · 杠杆 ${putLev}` : ""}
|
||||
@@ -940,7 +1017,7 @@ export default function PlanPage() {
|
||||
<div className="kv">
|
||||
<span>实际杠杆</span>
|
||||
<span className="mono">
|
||||
{open
|
||||
{open && !isOo
|
||||
? heldLev ||
|
||||
(heldSide
|
||||
? "—"
|
||||
@@ -951,29 +1028,51 @@ export default function PlanPage() {
|
||||
</>
|
||||
);
|
||||
})()}
|
||||
<div className="kv">
|
||||
<span>距现价</span>
|
||||
<span className="mono">
|
||||
{(() => {
|
||||
const strike = snap?.pair?.strike;
|
||||
const px =
|
||||
snap?.index_px ??
|
||||
(snap?.perp?.bid != null && snap?.perp?.ask != null
|
||||
? (snap.perp.bid + snap.perp.ask) / 2
|
||||
: null);
|
||||
if (strike == null || px == null) return "—";
|
||||
const abs = Math.abs(strike - px);
|
||||
const sign = strike - px > 0 ? "+" : "";
|
||||
const delta = `${sign}${(strike - px).toFixed(0)}`;
|
||||
if (!plan?.atm_open_offset_enabled) {
|
||||
return `${delta} · 偏差限制关`;
|
||||
}
|
||||
const lim = plan?.max_atm_open_offset ?? 3;
|
||||
const ok = abs <= lim + 1e-9;
|
||||
return `${delta} · 开仓${ok ? "可" : "不可"}(|Δ|≤${lim})`;
|
||||
})()}
|
||||
</span>
|
||||
</div>
|
||||
{isOo ? (
|
||||
<div className="kv">
|
||||
<span>相对现价</span>
|
||||
<span className="mono">
|
||||
{(() => {
|
||||
const px = snap?.index_px;
|
||||
const ck = snap?.pair?.call_strike ?? snap?.pair?.strike;
|
||||
const pk = snap?.pair?.put_strike;
|
||||
if (px == null || ck == null) return "—";
|
||||
const cOff = Number(ck) - Number(px);
|
||||
const pOff =
|
||||
pk != null ? Number(pk) - Number(px) : null;
|
||||
const fmtOff = (n: number) =>
|
||||
`${n > 0 ? "+" : ""}${n.toFixed(0)}`;
|
||||
return pOff != null
|
||||
? `C ${fmtOff(cOff)} · P ${fmtOff(pOff)}`
|
||||
: `C ${fmtOff(cOff)}`;
|
||||
})()}
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="kv">
|
||||
<span>距现价</span>
|
||||
<span className="mono">
|
||||
{(() => {
|
||||
const strike = snap?.pair?.strike;
|
||||
const px =
|
||||
snap?.index_px ??
|
||||
(snap?.perp?.bid != null && snap?.perp?.ask != null
|
||||
? (snap.perp.bid + snap.perp.ask) / 2
|
||||
: null);
|
||||
if (strike == null || px == null) return "—";
|
||||
const abs = Math.abs(strike - px);
|
||||
const sign = strike - px > 0 ? "+" : "";
|
||||
const delta = `${sign}${(strike - px).toFixed(0)}`;
|
||||
if (!plan?.atm_open_offset_enabled) {
|
||||
return `${delta} · 偏差限制关`;
|
||||
}
|
||||
const lim = plan?.max_atm_open_offset ?? 3;
|
||||
const ok = abs <= lim + 1e-9;
|
||||
return `${delta} · 开仓${ok ? "可" : "不可"}(|Δ|≤${lim})`;
|
||||
})()}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="kv">
|
||||
<span>到期</span>
|
||||
<span className="mono">{snap?.pair?.expiry_ymd || "—"}</span>
|
||||
|
||||
Reference in New Issue
Block a user