Add amplitude filter as first open gate for 永期 hedge.

Reuse OO amplitude settings (default off); Plan shows index/HL when filtering.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-08-07 21:41:51 +08:00
parent b377956367
commit a88d708ea3
7 changed files with 320 additions and 142 deletions
+1
View File
@@ -214,6 +214,7 @@ export type MarketSnapshot = {
max_pct?: number;
/** @deprecated 兼容旧字段,等同 max_pct */
min_pct?: number;
filter_enabled?: boolean;
ok?: boolean;
} | null;
pair: {
+51 -49
View File
@@ -288,6 +288,9 @@ export default function PlanPage() {
]
.filter(Boolean)
.join(" · ");
const poAmpLabel = plan?.oo_amplitude_filter_enabled
? `振幅≤${fmt(plan?.oo_amplitude_pct ?? 1.5, 1)}%/${fmt(plan?.oo_amplitude_hours ?? 12, 0)}h(第一关)`
: null;
const exitDetail = isOo
? `净盈利≥预算×${fmt(ooRatio, 1)} → 只平盈利腿,亏损腿残留`
: exitMode === "premium_multiple"
@@ -380,6 +383,7 @@ export default function PlanPage() {
</>
) : (
<>
{poAmpLabel ? `${poAmpLabel} · ` : ""}
{" "}
{displayPerpQty != null
? `${fmt(displayPerpQty, 2)} ETH`
@@ -520,6 +524,7 @@ export default function PlanPage() {
ooSelectLabel
) : (
<>
{poAmpLabel ? `${poAmpLabel} · ` : ""}
{displayPerpQty != null
? `${fmt(displayPerpQty, 2)}ETH`
@@ -1033,55 +1038,56 @@ export default function PlanPage() {
</div>
<div className="plan-market">
{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?.max_pct ?? snap?.oo_amplitude?.min_pct) !=
null
? ` · 上限≤${fmt(
Number(
snap.oo_amplitude?.max_pct ??
snap.oo_amplitude?.min_pct,
),
1,
)}%`
: ""}
{snap?.oo_amplitude?.ok === false
<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?.max_pct ?? snap?.oo_amplitude?.min_pct) !=
null
? ` · 上限≤${fmt(
Number(
snap.oo_amplitude?.max_pct ??
snap.oo_amplitude?.min_pct,
),
1,
)}%`
: ""}
{snap?.oo_amplitude?.filter_enabled === false
? " · 过滤关"
: snap?.oo_amplitude?.ok === false
? " · 超限"
: snap?.oo_amplitude?.ok === true
? " · 可开"
: ""}
</span>
</div>
</span>
</div>
) : (
</div>
{!isOo ? (
<div className="card">
<h3 className="plan-panel-title"></h3>
<div className="kv">
@@ -1104,12 +1110,8 @@ export default function PlanPage() {
)}
</span>
</div>
<div className="kv">
<span></span>
<span className="mono">{fmtExPx("index", snap?.index_px)}</span>
</div>
</div>
)}
) : null}
<div className="card">
<h3 className="plan-panel-title">
{isOo
+72 -69
View File
@@ -742,67 +742,65 @@ export default function SettingsPage() {
<option value="option_option"></option>
</select>
</div>
<div className="field">
<label htmlFor="ooAmpFilt"></label>
<select
id="ooAmpFilt"
className="mono"
value={ooAmpFilterOn ? "on" : "off"}
onChange={(e) =>
setOoAmpFilterOn(e.target.value === "on")
}
>
<option value="off"></option>
<option value="on"></option>
</select>
</div>
<div className="field">
<label htmlFor="ooAmpH"></label>
<input
id="ooAmpH"
className="mono"
type="number"
step="1"
min="1"
value={ooAmpHours}
onChange={(e) =>
setOoAmpHours(Number(e.target.value))
}
/>
</div>
{ooAmpFilterOn ? (
<div className="field">
<label htmlFor="ooAmp">%</label>
<input
id="ooAmp"
className="mono"
type="number"
step="0.1"
min="0.1"
value={ooAmpPct}
onChange={(e) =>
setOoAmpPct(Number(e.target.value))
}
/>
</div>
) : null}
{isOo ? (
<>
<div className="field">
<label htmlFor="ooAmpFilt"></label>
<select
id="ooAmpFilt"
className="mono"
value={ooAmpFilterOn ? "on" : "off"}
onChange={(e) =>
setOoAmpFilterOn(e.target.value === "on")
}
>
<option value="off"></option>
<option value="on"></option>
</select>
</div>
<div className="field">
<label htmlFor="ooAmpH"></label>
<input
id="ooAmpH"
className="mono"
type="number"
step="1"
min="1"
value={ooAmpHours}
onChange={(e) =>
setOoAmpHours(Number(e.target.value))
}
/>
</div>
{ooAmpFilterOn ? (
<div className="field">
<label htmlFor="ooAmp">%</label>
<input
id="ooAmp"
className="mono"
type="number"
step="0.1"
min="0.1"
value={ooAmpPct}
onChange={(e) =>
setOoAmpPct(Number(e.target.value))
}
/>
</div>
) : null}
<div className="field">
<label htmlFor="ooRR"></label>
<input
id="ooRR"
className="mono"
type="number"
step="0.1"
min="0.5"
value={ooRewardRatio}
onChange={(e) =>
setOoRewardRatio(Number(e.target.value))
}
/>
</div>
</>
<div className="field">
<label htmlFor="ooRR"></label>
<input
id="ooRR"
className="mono"
type="number"
step="0.1"
min="0.5"
value={ooRewardRatio}
onChange={(e) =>
setOoRewardRatio(Number(e.target.value))
}
/>
</div>
) : null}
{!isOo ? (
<div className="field">
@@ -1692,16 +1690,17 @@ export default function SettingsPage() {
=+= N
Call/Put
</li>
<li>
%
{isOo
? ";关闭时仍用回看高低点选约,但不因振幅超限拒开。"
: "(永期开仓第一关,不过关不再看 ATM/杠杆等)。"}
</li>
{isOo ? (
<>
<li>
+ %
Call/Put = ×
</li>
<li>
%
</li>
</>
<li>
+ %
Call/Put = ×
</li>
) : (
<>
<li>
@@ -1738,6 +1737,10 @@ export default function SettingsPage() {
</>
) : (
<>
<li>
%
</li>
<li>
Put
Call ATM/