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:
@@ -0,0 +1,69 @@
|
|||||||
|
"""振幅过滤门:回看窗内 range% 须 ≤ 上限(可关)。永期开仓第一关 / 期期共用。"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from ..exchange.candles import AmplitudeHL
|
||||||
|
|
||||||
|
|
||||||
|
def evaluate_amplitude_gate(
|
||||||
|
*,
|
||||||
|
filter_enabled: bool,
|
||||||
|
amp: AmplitudeHL | None,
|
||||||
|
max_pct: float,
|
||||||
|
hours: float,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""
|
||||||
|
返回:
|
||||||
|
blocked: 过滤开启且未过关(无K线或超限)
|
||||||
|
ok: 展示用是否过关(过滤关视为 True)
|
||||||
|
reason: 拒开文案(未拒则为 None)
|
||||||
|
snapshot: 写入 session._oo_amp 的字典(amp 为 None 时仅含元数据)
|
||||||
|
"""
|
||||||
|
max_p = float(max_pct)
|
||||||
|
hrs = float(hours)
|
||||||
|
filt = bool(filter_enabled)
|
||||||
|
if amp is None:
|
||||||
|
snap = {
|
||||||
|
"high": None,
|
||||||
|
"low": None,
|
||||||
|
"mid": None,
|
||||||
|
"range_pct": None,
|
||||||
|
"hours": hrs,
|
||||||
|
"max_pct": max_p,
|
||||||
|
"filter_enabled": filt,
|
||||||
|
"ok": False if filt else True,
|
||||||
|
}
|
||||||
|
if filt:
|
||||||
|
return {
|
||||||
|
"blocked": True,
|
||||||
|
"ok": False,
|
||||||
|
"reason": f"振幅未过关:无法获取近 {hrs:g}h K 线高低",
|
||||||
|
"snapshot": snap,
|
||||||
|
}
|
||||||
|
return {"blocked": False, "ok": True, "reason": None, "snapshot": snap}
|
||||||
|
|
||||||
|
range_pct = float(amp.range_pct)
|
||||||
|
over = range_pct > max_p + 1e-12
|
||||||
|
ok = (not filt) or (not over)
|
||||||
|
snap = {
|
||||||
|
"high": float(amp.high),
|
||||||
|
"low": float(amp.low),
|
||||||
|
"mid": float(amp.mid),
|
||||||
|
"range_pct": range_pct,
|
||||||
|
"hours": hrs,
|
||||||
|
"max_pct": max_p,
|
||||||
|
"filter_enabled": filt,
|
||||||
|
"ok": ok,
|
||||||
|
}
|
||||||
|
if filt and over:
|
||||||
|
return {
|
||||||
|
"blocked": True,
|
||||||
|
"ok": False,
|
||||||
|
"reason": (
|
||||||
|
f"振幅未过关:{hrs:g}h 内 {range_pct:.2f}% > {max_p:g}%"
|
||||||
|
),
|
||||||
|
"snapshot": snap,
|
||||||
|
}
|
||||||
|
return {"blocked": False, "ok": ok, "reason": None, "snapshot": snap}
|
||||||
@@ -1047,6 +1047,14 @@ class StrategyEngine:
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
if pick is None:
|
if pick is None:
|
||||||
|
amp_fail = None
|
||||||
|
try:
|
||||||
|
amp_fail = get_session().amplitude_gate_fail_reason()
|
||||||
|
except Exception:
|
||||||
|
amp_fail = None
|
||||||
|
if amp_fail:
|
||||||
|
self._set_state(last_error=amp_fail)
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
from .auto_usdc import preview_capacity_for_convert
|
from .auto_usdc import preview_capacity_for_convert
|
||||||
from .open_capacity import funds_gate_blocks
|
from .open_capacity import funds_gate_blocks
|
||||||
|
|||||||
@@ -352,7 +352,6 @@ class StrategySession:
|
|||||||
|
|
||||||
def align_to_held_position(self) -> OptionPair | None:
|
def align_to_held_position(self) -> OptionPair | None:
|
||||||
"""有活跃仓时:监控对锁定为持仓合约的到期/行权价。"""
|
"""有活跃仓时:监控对锁定为持仓合约的到期/行权价。"""
|
||||||
if _hedge_mode() == "option_option":
|
|
||||||
self.refresh_oo_amplitude()
|
self.refresh_oo_amplitude()
|
||||||
call_id, put_id = _held_option_legs()
|
call_id, put_id = _held_option_legs()
|
||||||
held = call_id or _held_option_inst_id()
|
held = call_id or _held_option_inst_id()
|
||||||
@@ -421,6 +420,8 @@ class StrategySession:
|
|||||||
return self.align_to_held_position()
|
return self.align_to_held_position()
|
||||||
if _hedge_mode() == "option_option":
|
if _hedge_mode() == "option_option":
|
||||||
return self.align_oo_instruments()
|
return self.align_oo_instruments()
|
||||||
|
# 永期:刷新振幅供 Plan(过滤关也展示;开仓门禁在 pick)
|
||||||
|
self.refresh_oo_amplitude()
|
||||||
s = self.settings
|
s = self.settings
|
||||||
idx = self.ex.fetch_index(s.index_inst_id)
|
idx = self.ex.fetch_index(s.index_inst_id)
|
||||||
mark = self.ex.fetch_mark(s.perp_inst_id) or idx
|
mark = self.ex.fetch_mark(s.perp_inst_id) or idx
|
||||||
@@ -464,35 +465,67 @@ class StrategySession:
|
|||||||
return self._apply_pair(pair, mark=float(mark), idx=idx)
|
return self._apply_pair(pair, mark=float(mark), idx=idx)
|
||||||
|
|
||||||
def refresh_oo_amplitude(self) -> dict[str, Any] | None:
|
def refresh_oo_amplitude(self) -> dict[str, Any] | None:
|
||||||
"""刷新振幅高低(有仓/无仓都要,否则持仓后 UI 指数/振幅会空)。"""
|
"""刷新振幅高低(永期/期期;有仓/无仓都要,否则 UI 指数/振幅会空)。"""
|
||||||
if _hedge_mode() != "option_option":
|
|
||||||
return None
|
|
||||||
try:
|
try:
|
||||||
from ..exchange.candles import fetch_amplitude_hl_for_runtime
|
from ..exchange.candles import fetch_amplitude_hl_for_runtime
|
||||||
|
from .amplitude_gate import evaluate_amplitude_gate
|
||||||
|
|
||||||
amp_pct, amp_hours, _, _, _, amp_filt = _oo_settings()
|
amp_pct, amp_hours, _, _, _, amp_filt = _oo_settings()
|
||||||
amp = fetch_amplitude_hl_for_runtime(amp_hours)
|
amp = fetch_amplitude_hl_for_runtime(amp_hours)
|
||||||
if amp is None:
|
gate = evaluate_amplitude_gate(
|
||||||
return self._oo_amp
|
filter_enabled=bool(amp_filt),
|
||||||
self._oo_amp = {
|
amp=amp,
|
||||||
"high": float(amp.high),
|
max_pct=float(amp_pct),
|
||||||
"low": float(amp.low),
|
hours=float(amp_hours),
|
||||||
"mid": float(amp.mid),
|
)
|
||||||
"range_pct": float(amp.range_pct),
|
self._oo_amp = dict(gate["snapshot"])
|
||||||
"hours": float(amp_hours),
|
|
||||||
"max_pct": float(amp_pct),
|
|
||||||
"filter_enabled": bool(amp_filt),
|
|
||||||
"ok": (
|
|
||||||
True
|
|
||||||
if not amp_filt
|
|
||||||
else float(amp.range_pct) <= float(amp_pct) + 1e-12
|
|
||||||
),
|
|
||||||
}
|
|
||||||
return self._oo_amp
|
return self._oo_amp
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("refresh_oo_amplitude failed")
|
logger.exception("refresh_oo_amplitude failed")
|
||||||
return self._oo_amp
|
return self._oo_amp
|
||||||
|
|
||||||
|
def _apply_amplitude_first_gate(self) -> bool:
|
||||||
|
"""
|
||||||
|
振幅过滤为开仓第一关。返回 True=可继续选约;False=拒开。
|
||||||
|
无论是否开启过滤都写入 _oo_amp 供 Plan 展示。
|
||||||
|
"""
|
||||||
|
from ..exchange.candles import fetch_amplitude_hl_for_runtime
|
||||||
|
from .amplitude_gate import evaluate_amplitude_gate
|
||||||
|
|
||||||
|
amp_pct, amp_hours, _, _, _, amp_filt = _oo_settings()
|
||||||
|
amp = fetch_amplitude_hl_for_runtime(amp_hours)
|
||||||
|
gate = evaluate_amplitude_gate(
|
||||||
|
filter_enabled=bool(amp_filt),
|
||||||
|
amp=amp,
|
||||||
|
max_pct=float(amp_pct),
|
||||||
|
hours=float(amp_hours),
|
||||||
|
)
|
||||||
|
self._oo_amp = dict(gate["snapshot"])
|
||||||
|
if gate["blocked"]:
|
||||||
|
logger.info("amplitude gate blocked: %s", gate.get("reason"))
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def amplitude_gate_fail_reason(self) -> str | None:
|
||||||
|
"""若最近一次振幅快照显示过滤开启且未过关,返回文案。"""
|
||||||
|
amp = self._oo_amp
|
||||||
|
if not amp or not amp.get("filter_enabled"):
|
||||||
|
return None
|
||||||
|
if amp.get("ok") is True:
|
||||||
|
return None
|
||||||
|
hours = amp.get("hours")
|
||||||
|
range_pct = amp.get("range_pct")
|
||||||
|
max_pct = amp.get("max_pct")
|
||||||
|
if range_pct is None:
|
||||||
|
return f"振幅未过关:无法获取近 {hours:g}h K 线高低" if hours is not None else "振幅未过关"
|
||||||
|
try:
|
||||||
|
return (
|
||||||
|
f"振幅未过关:{float(hours):g}h 内 "
|
||||||
|
f"{float(range_pct):.2f}% > {float(max_pct):g}%"
|
||||||
|
)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return "振幅未过关"
|
||||||
|
|
||||||
def align_oo_instruments(self) -> OptionPair | None:
|
def align_oo_instruments(self) -> OptionPair | None:
|
||||||
"""期期监控:按振幅高低点选虚值 Call/Put(展示用;振幅超限仍对齐候选)。"""
|
"""期期监控:按振幅高低点选虚值 Call/Put(展示用;振幅超限仍对齐候选)。"""
|
||||||
from .oo_selection import select_oo_pair
|
from .oo_selection import select_oo_pair
|
||||||
@@ -693,6 +726,9 @@ class StrategySession:
|
|||||||
min_hours, min_lev, max_atm_off, atm_off_on = _strategy_floats()
|
min_hours, min_lev, max_atm_off, atm_off_on = _strategy_floats()
|
||||||
fixed_on, fixed_perp = _fixed_direction()
|
fixed_on, fixed_perp = _fixed_direction()
|
||||||
opt_side_hint = _option_side_for_perp(fixed_perp) if fixed_on else None
|
opt_side_hint = _option_side_for_perp(fixed_perp) if fixed_on else None
|
||||||
|
# 第一关:振幅过滤(默认关;开启则回看窗振幅须 ≤ 最大%)
|
||||||
|
if not self._apply_amplitude_first_gate():
|
||||||
|
return None
|
||||||
idx = self.ex.fetch_index(s.index_inst_id)
|
idx = self.ex.fetch_index(s.index_inst_id)
|
||||||
mark = self.ex.fetch_mark(s.perp_inst_id) or idx
|
mark = self.ex.fetch_mark(s.perp_inst_id) or idx
|
||||||
if mark is None or mark <= 0:
|
if mark is None or mark <= 0:
|
||||||
@@ -932,8 +968,7 @@ class StrategySession:
|
|||||||
|
|
||||||
async def ensure_atm_async(self, *, force: bool = False) -> OptionPair | None:
|
async def ensure_atm_async(self, *, force: bool = False) -> OptionPair | None:
|
||||||
if _has_open_position():
|
if _has_open_position():
|
||||||
# 持仓期间:钉住持仓行权价(禁止漂到新 ATM/虚值);期期仍刷新振幅供 UI
|
# 持仓期间:钉住持仓行权价(禁止漂到新 ATM/虚值);仍刷新振幅供 UI
|
||||||
if _hedge_mode() == "option_option":
|
|
||||||
await asyncio.to_thread(self.refresh_oo_amplitude)
|
await asyncio.to_thread(self.refresh_oo_amplitude)
|
||||||
call_id, put_id = _held_option_legs()
|
call_id, put_id = _held_option_legs()
|
||||||
held = call_id or _held_option_inst_id()
|
held = call_id or _held_option_inst_id()
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
"""振幅过滤门:永期开仓第一关 / 与期期共用口径。"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from app.exchange.candles import AmplitudeHL
|
||||||
|
from app.strategy.amplitude_gate import evaluate_amplitude_gate
|
||||||
|
|
||||||
|
|
||||||
|
def test_amplitude_gate_off_always_pass() -> None:
|
||||||
|
amp = AmplitudeHL(high=2060, low=1940, mid=2000, hours=12, bar_count=12)
|
||||||
|
# 6% 超常见上限,但过滤关 → 不拦
|
||||||
|
g = evaluate_amplitude_gate(
|
||||||
|
filter_enabled=False, amp=amp, max_pct=2.0, hours=12
|
||||||
|
)
|
||||||
|
assert g["blocked"] is False
|
||||||
|
assert g["ok"] is True
|
||||||
|
assert g["reason"] is None
|
||||||
|
assert g["snapshot"]["filter_enabled"] is False
|
||||||
|
assert g["snapshot"]["range_pct"] == amp.range_pct
|
||||||
|
|
||||||
|
|
||||||
|
def test_amplitude_gate_on_blocks_over_max() -> None:
|
||||||
|
amp = AmplitudeHL(high=2060, low=1940, mid=2000, hours=12, bar_count=12)
|
||||||
|
assert amp.range_pct == 6.0
|
||||||
|
g = evaluate_amplitude_gate(
|
||||||
|
filter_enabled=True, amp=amp, max_pct=2.0, hours=12
|
||||||
|
)
|
||||||
|
assert g["blocked"] is True
|
||||||
|
assert g["ok"] is False
|
||||||
|
assert "振幅未过关" in (g["reason"] or "")
|
||||||
|
assert "6.00%" in (g["reason"] or "")
|
||||||
|
assert "2%" in (g["reason"] or "")
|
||||||
|
|
||||||
|
|
||||||
|
def test_amplitude_gate_on_pass_within_max() -> None:
|
||||||
|
amp = AmplitudeHL(high=2010, low=1990, mid=2000, hours=12, bar_count=12)
|
||||||
|
assert amp.range_pct == 1.0
|
||||||
|
g = evaluate_amplitude_gate(
|
||||||
|
filter_enabled=True, amp=amp, max_pct=2.0, hours=12
|
||||||
|
)
|
||||||
|
assert g["blocked"] is False
|
||||||
|
assert g["ok"] is True
|
||||||
|
assert g["reason"] is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_amplitude_gate_on_no_candles_fail_closed() -> None:
|
||||||
|
g = evaluate_amplitude_gate(
|
||||||
|
filter_enabled=True, amp=None, max_pct=2.0, hours=12
|
||||||
|
)
|
||||||
|
assert g["blocked"] is True
|
||||||
|
assert g["ok"] is False
|
||||||
|
assert "无法获取" in (g["reason"] or "")
|
||||||
|
|
||||||
|
|
||||||
|
def test_amplitude_gate_off_no_candles_still_ok() -> None:
|
||||||
|
g = evaluate_amplitude_gate(
|
||||||
|
filter_enabled=False, amp=None, max_pct=2.0, hours=12
|
||||||
|
)
|
||||||
|
assert g["blocked"] is False
|
||||||
|
assert g["ok"] is True
|
||||||
@@ -214,6 +214,7 @@ export type MarketSnapshot = {
|
|||||||
max_pct?: number;
|
max_pct?: number;
|
||||||
/** @deprecated 兼容旧字段,等同 max_pct */
|
/** @deprecated 兼容旧字段,等同 max_pct */
|
||||||
min_pct?: number;
|
min_pct?: number;
|
||||||
|
filter_enabled?: boolean;
|
||||||
ok?: boolean;
|
ok?: boolean;
|
||||||
} | null;
|
} | null;
|
||||||
pair: {
|
pair: {
|
||||||
|
|||||||
@@ -288,6 +288,9 @@ export default function PlanPage() {
|
|||||||
]
|
]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join(" · ");
|
.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
|
const exitDetail = isOo
|
||||||
? `净盈利≥预算×${fmt(ooRatio, 1)} → 只平盈利腿,亏损腿残留`
|
? `净盈利≥预算×${fmt(ooRatio, 1)} → 只平盈利腿,亏损腿残留`
|
||||||
: exitMode === "premium_multiple"
|
: exitMode === "premium_multiple"
|
||||||
@@ -380,6 +383,7 @@ export default function PlanPage() {
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
{poAmpLabel ? `${poAmpLabel} · ` : ""}
|
||||||
永续{" "}
|
永续{" "}
|
||||||
{displayPerpQty != null
|
{displayPerpQty != null
|
||||||
? `${fmt(displayPerpQty, 2)} ETH`
|
? `${fmt(displayPerpQty, 2)} ETH`
|
||||||
@@ -520,6 +524,7 @@ export default function PlanPage() {
|
|||||||
ooSelectLabel
|
ooSelectLabel
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
{poAmpLabel ? `${poAmpLabel} · ` : ""}
|
||||||
永续
|
永续
|
||||||
{displayPerpQty != null
|
{displayPerpQty != null
|
||||||
? `${fmt(displayPerpQty, 2)}ETH`
|
? `${fmt(displayPerpQty, 2)}ETH`
|
||||||
@@ -1033,7 +1038,6 @@ export default function PlanPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="plan-market">
|
<div className="plan-market">
|
||||||
{isOo ? (
|
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<h3 className="plan-panel-title">指数 / 振幅</h3>
|
<h3 className="plan-panel-title">指数 / 振幅</h3>
|
||||||
<div className="kv">
|
<div className="kv">
|
||||||
@@ -1073,7 +1077,9 @@ export default function PlanPage() {
|
|||||||
1,
|
1,
|
||||||
)}%`
|
)}%`
|
||||||
: ""}
|
: ""}
|
||||||
{snap?.oo_amplitude?.ok === false
|
{snap?.oo_amplitude?.filter_enabled === false
|
||||||
|
? " · 过滤关"
|
||||||
|
: snap?.oo_amplitude?.ok === false
|
||||||
? " · 超限"
|
? " · 超限"
|
||||||
: snap?.oo_amplitude?.ok === true
|
: snap?.oo_amplitude?.ok === true
|
||||||
? " · 可开"
|
? " · 可开"
|
||||||
@@ -1081,7 +1087,7 @@ export default function PlanPage() {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
{!isOo ? (
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<h3 className="plan-panel-title">永续行情</h3>
|
<h3 className="plan-panel-title">永续行情</h3>
|
||||||
<div className="kv">
|
<div className="kv">
|
||||||
@@ -1104,12 +1110,8 @@ export default function PlanPage() {
|
|||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="kv">
|
|
||||||
<span>指数</span>
|
|
||||||
<span className="mono">{fmtExPx("index", snap?.index_px)}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
) : null}
|
||||||
)}
|
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<h3 className="plan-panel-title">
|
<h3 className="plan-panel-title">
|
||||||
{isOo
|
{isOo
|
||||||
|
|||||||
@@ -742,8 +742,6 @@ export default function SettingsPage() {
|
|||||||
<option value="option_option">期期对冲(双期权)</option>
|
<option value="option_option">期期对冲(双期权)</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
{isOo ? (
|
|
||||||
<>
|
|
||||||
<div className="field">
|
<div className="field">
|
||||||
<label htmlFor="ooAmpFilt">振幅过滤</label>
|
<label htmlFor="ooAmpFilt">振幅过滤</label>
|
||||||
<select
|
<select
|
||||||
@@ -788,6 +786,7 @@ export default function SettingsPage() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
{isOo ? (
|
||||||
<div className="field">
|
<div className="field">
|
||||||
<label htmlFor="ooRR">盈亏比</label>
|
<label htmlFor="ooRR">盈亏比</label>
|
||||||
<input
|
<input
|
||||||
@@ -802,7 +801,6 @@ export default function SettingsPage() {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
) : null}
|
) : null}
|
||||||
{!isOo ? (
|
{!isOo ? (
|
||||||
<div className="field">
|
<div className="field">
|
||||||
@@ -1692,16 +1690,17 @@ export default function SettingsPage() {
|
|||||||
对冲模式二选一:永期=永续+期权;期期=近 N
|
对冲模式二选一:永期=永续+期权;期期=近 N
|
||||||
小时振幅高低匹配虚值 Call/Put,达标只平盈利腿。
|
小时振幅高低匹配虚值 Call/Put,达标只平盈利腿。
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
振幅过滤:默认关闭。开启后回看窗内振幅超过「振幅最大%」则不开仓
|
||||||
|
{isOo
|
||||||
|
? ";关闭时仍用回看高低点选约,但不因振幅超限拒开。"
|
||||||
|
: "(永期开仓第一关,不过关不再看 ATM/杠杆等)。"}
|
||||||
|
</li>
|
||||||
{isOo ? (
|
{isOo ? (
|
||||||
<>
|
|
||||||
<li>
|
<li>
|
||||||
期期定仓:强制以损定仓 + 亏损幅度%;预算平分
|
期期定仓:强制以损定仓 + 亏损幅度%;预算平分
|
||||||
Call/Put,各按卖一独立定仓;出场目标 = 预算 × 盈亏比。
|
Call/Put,各按卖一独立定仓;出场目标 = 预算 × 盈亏比。
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
振幅过滤:默认关闭。关闭时仍用「振幅回看」取高低点选约,但不因振幅超限拒开;开启后回看窗内振幅超过「振幅最大%」则不开仓。
|
|
||||||
</li>
|
|
||||||
</>
|
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<li>
|
<li>
|
||||||
@@ -1738,6 +1737,10 @@ export default function SettingsPage() {
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
<li>
|
||||||
|
振幅过滤(仓位页):开启时为开仓第一关——回看窗内振幅须 ≤
|
||||||
|
最大%,不过关则不开仓。
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
固定方向:默认关。开启后固定永续多→买 Put,或永续空→买
|
固定方向:默认关。开启后固定永续多→买 Put,或永续空→买
|
||||||
Call;期权只选实值或平值,不买虚值。关闭时仍按 ATM/卖一比价规则。
|
Call;期权只选实值或平值,不买虚值。关闭时仍按 ATM/卖一比价规则。
|
||||||
|
|||||||
Reference in New Issue
Block a user