Move settings hints into rules; add OO amplitude filter toggle default off.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-08-07 17:58:50 +08:00
parent 0daac05ef5
commit ab612df818
10 changed files with 201 additions and 118 deletions
+2 -1
View File
@@ -370,6 +370,7 @@ export type PlanState = {
hedge_mode?: "perp_option" | "option_option";
oo_amplitude_pct?: number;
oo_amplitude_hours?: number;
oo_amplitude_filter_enabled?: boolean;
oo_min_option_hours?: number;
oo_min_leverage?: number;
oo_reward_ratio?: number;
@@ -425,12 +426,12 @@ export type StrategySettings = {
hedge_mode?: "perp_option" | "option_option";
oo_amplitude_pct?: number;
oo_amplitude_hours?: number;
oo_amplitude_filter_enabled?: boolean;
oo_min_option_hours?: number;
oo_min_leverage?: number;
oo_reward_ratio?: number;
oo_budget_cushion?: number;
oo_strike_max_dev_pct?: number;
oo_strike_max_dev_pct?: number;
exchange?: string;
};
+3 -1
View File
@@ -264,7 +264,9 @@ export default function PlanPage() {
? `ATM偏差≤${fmt(plan?.max_atm_open_offset ?? 3, 0)}`
: "ATM偏差关";
const ooSelectLabel = [
`振幅≤${fmt(plan?.oo_amplitude_pct ?? 1.5, 1)}%/${fmt(plan?.oo_amplitude_hours ?? 12, 0)}h`,
plan?.oo_amplitude_filter_enabled
? `振幅≤${fmt(plan?.oo_amplitude_pct ?? 1.5, 1)}%/${fmt(plan?.oo_amplitude_hours ?? 12, 0)}h`
: `振幅回看${fmt(plan?.oo_amplitude_hours ?? 12, 0)}h(过滤关)`,
`贴高低≤${fmt(plan?.oo_strike_max_dev_pct ?? 1, 1)}%`,
"虚值Call@高·Put@低",
`剩余≥${fmt(plan?.oo_min_option_hours ?? 24, 0)}h`,
+104 -102
View File
@@ -113,6 +113,7 @@ export default function SettingsPage() {
);
const [ooAmpPct, setOoAmpPct] = useState(1.5);
const [ooAmpHours, setOoAmpHours] = useState(12);
const [ooAmpFilterOn, setOoAmpFilterOn] = useState(false);
const [ooMinHours, setOoMinHours] = useState(24);
const [ooMinLev, setOoMinLev] = useState(200);
const [ooStrikeDev, setOoStrikeDev] = useState(1);
@@ -235,6 +236,7 @@ export default function SettingsPage() {
);
setOoAmpPct(s.oo_amplitude_pct ?? 1.5);
setOoAmpHours(s.oo_amplitude_hours ?? 12);
setOoAmpFilterOn(Boolean(s.oo_amplitude_filter_enabled));
setOoMinHours(s.oo_min_option_hours ?? 24);
setOoMinLev(s.oo_min_leverage ?? 200);
setOoStrikeDev(s.oo_strike_max_dev_pct ?? 1);
@@ -412,6 +414,7 @@ export default function SettingsPage() {
hedge_mode: hedgeMode,
oo_amplitude_pct: ooAmpPct,
oo_amplitude_hours: ooAmpHours,
oo_amplitude_filter_enabled: ooAmpFilterOn,
oo_min_option_hours: ooMinHours,
oo_min_leverage: ooMinLev,
oo_strike_max_dev_pct: ooStrikeDev,
@@ -739,29 +742,68 @@ export default function SettingsPage() {
<option value="perp_option">永期对冲(永续+期权)</option>
<option value="option_option">期期对冲(双期权)</option>
</select>
<p className="hint" style={{ margin: "0.35rem 0 0" }}>
二选一。期期:近 N 小时振幅高低匹配虚值 Call/Put;达标只平盈利腿。
</p>
</div>
{isOo ? (
<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))
}
/>
<p className="hint" style={{ margin: "0.35rem 0 0" }}>
目标盈利 = 以损预算 × 盈亏比(例预算 100U、比 2 → 目标
200U)。预算平分给 Call/Put,各按卖一独立定仓。
</p>
</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}
<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">
@@ -816,11 +858,6 @@ export default function SettingsPage() {
</option>
<option value="actual">实际杠杆(盘口卖一)</option>
</select>
<p className="hint" style={{ margin: "0.35rem 0 0" }}>
选约杠杆:按「指数÷期权杠杆≥」估权利金算
k,权利金再便宜也不放大仓位。
实际杠杆:按盘口卖一定仓,便宜时 k 会变大。
</p>
</div>
) : null}
{!isOo ? (
@@ -914,11 +951,6 @@ export default function SettingsPage() {
<option value="off">关闭(默认)</option>
<option value="on">开启</option>
</select>
<p className="hint" style={{ margin: "0.35rem 0 0" }}>
{riskLossPct > 3
? "亏损幅度超过 3% 时不可启用倍投。"
: "连续亏损日达阈值后翻倍。到期结算无论盈亏(含小盈利)都按亏损日计;达标平仓盈利才打断连亏。"}
</p>
</div>
{martingaleOn && riskLossPct <= 3 ? (
<>
@@ -957,26 +989,6 @@ export default function SettingsPage() {
)
}
/>
<p
className="hint"
style={{ margin: "0.35rem 0 0" }}
>
例:幅度 {riskLossPct}%、连亏{" "}
{martingaleStartAfter} 天起翻、最多{" "}
{martingaleMaxDoubles} 次 →{" "}
{[0, 1, 2, 3]
.filter((d) => d <= martingaleMaxDoubles)
.map(
(d) =>
`${Number(
(
riskLossPct *
2 ** d
).toPrecision(6),
)}%`,
)
.join(" → ")}
</p>
</div>
</>
) : null}
@@ -1230,35 +1242,6 @@ export default function SettingsPage() {
<div className="settings-fields">
{isOo ? (
<>
<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))}
/>
<p className="hint" style={{ margin: "0.35rem 0 0" }}>
回看窗内振幅超过该上限则不开仓。
</p>
</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>
<div className="field">
<label htmlFor="ooMinH">最短剩余到期(小时)</label>
<input
@@ -1299,10 +1282,6 @@ export default function SettingsPage() {
setOoStrikeDev(Number(e.target.value))
}
/>
<p className="hint" style={{ margin: "0.35rem 0 0" }}>
虚值 Call/Put 行权价相对振幅高/低点 |K−HL|/HL
不超过该比例(默认 1%)。
</p>
</div>
</>
) : (
@@ -1412,9 +1391,6 @@ export default function SettingsPage() {
setOoRewardRatio(Number(e.target.value))
}
/>
<p className="hint" style={{ margin: "0.35rem 0 0" }}>
净盈 ≥ 预算×盈亏比时只平盈利腿;亏损腿进残留,按下方回收比例或到期结算。
</p>
</div>
) : (
<>
@@ -1585,9 +1561,6 @@ export default function SettingsPage() {
<option value="1">开启(推荐)</option>
<option value="0">关闭</option>
</select>
<p className="hint" style={{ margin: "0.35rem 0 0" }}>
开启后:历史上已开过某到期日(如 0803)后,不论今天还是明天都不能再开同到期,只能监控/开下一到期(如 0804)。
</p>
</div>
<div className="field">
<label htmlFor="fee">手续费率</label>
@@ -1637,24 +1610,50 @@ export default function SettingsPage() {
10000。
</li>
) : null}
<li>
对冲模式二选一:永期=永续+期权;期期=近 N
小时振幅高低匹配虚值 Call/Put,达标只平盈利腿。
</li>
{isOo ? (
<li>
期期对冲:强制以损定仓 + 亏损幅度%;两腿 1:1 平分预算;出场用盈亏比,不使用永续名义/比例/k。
</li>
<>
<li>
期期定仓:强制以损定仓 + 亏损幅度%;预算平分
Call/Put,各按卖一独立定仓;出场目标 = 预算 × 盈亏比。
</li>
<li>
振幅过滤:默认关闭。关闭时仍用「振幅回看」取高低点选约,但不因振幅超限拒开;开启后回看窗内振幅超过「振幅最大%」则不开仓。
</li>
</>
) : (
<li>
永续保证金模式:仅作用于永续(全仓/逐仓,默认全仓)。OKX
期权始终为现金/逐仓(cash),不受此选项影响。
</li>
<>
<li>
永续保证金模式:仅作用于永续(全仓/逐仓,默认全仓)。OKX
期权始终为现金/逐仓(cash),不受此选项影响。
</li>
<li>
节奏杠杆:选约杠杆按「指数÷期权杠杆≥」估权利金算
k,权利金再便宜也不放大仓位;实际杠杆按盘口卖一定仓,便宜时
k 会变大。
</li>
</>
)}
<li>
倍投:默认关。仅以损定仓且亏损幅度≤3%时可开;连续亏损日达阈值后翻倍;到期结算(含小盈利)仍计亏损日,达标平仓盈利才打断连亏。
</li>
</>
) : null}
{stratSub === "select" ? (
isOo ? (
<li>
期期选约:回看窗内真实高低点振幅不超过上限后,同到期虚值 Call
贴高、Put 贴低;剩余到期与单腿杠杆门限见本页。
</li>
<>
<li>
期期选约:用振幅回看窗高低点匹配同到期虚值 Call@高 /
Put@低;振幅过滤在「仓位」页开关。
</li>
<li>
贴高低最大偏离:行权价相对高/低点 |K−HL|/HL
不超过该比例(默认 1%),否则跳过该到期。
</li>
</>
) : (
<>
<li>
@@ -1679,7 +1678,7 @@ export default function SettingsPage() {
</li>
<li>
{isOo
? "残留回收:达标只平盈利腿后,亏损腿权利金回升到初始比例及以上时可尝试平仓;否则到期结算。"
? "期期出场:净盈 ≥ 预算×盈亏比时只平盈利腿;亏损腿进残留,按回收比例或到期结算。"
: "残留期权回收比例:只平永续后,当买一权利金回升到初始权利金的该比例及以上时,按最新买一 IOC 限价卖掉归档期权(不扫市价);默认 20%。未达标或未完全成交则等到下次巡检或到期结算。"}
</li>
</>
@@ -1690,6 +1689,9 @@ export default function SettingsPage() {
实盘下单最小间隔:LIVE 私有下单/查单间隔,默认 1s。范围
0.2–30。
</li>
<li>
同到期日一天只开一次:开启后历史上已开过某到期日则不能再开同到期,只能下一到期。
</li>
<li>
显示手动开仓:默认关闭。开启后计划页才出现「手动开一组 /
手动全平」。策略自动运行中禁止手动开仓(须先暂停);紧急全平始终可用。