diff --git a/crypto_monitor_okx/.env.example b/crypto_monitor_okx/.env.example index 41b86d1..8569c90 100644 --- a/crypto_monitor_okx/.env.example +++ b/crypto_monitor_okx/.env.example @@ -125,6 +125,9 @@ OKX_OPTIONS_ALLOW_MARKET_CLOSE=false # 对冲计划(仅 OKX;前端 env「对冲计划」;详见 docs/对冲计划开发方案.md) # ============================================================================= HEDGE_PLAN_ENABLED=false +# 页面 Tab 显示(默认全部显示,可单独关闭;不影响已有进行中/历史计划) +HEDGE_PLAN_SHOW_PERP_OPTIONS=true +HEDGE_PLAN_SHOW_OPTIONS_OPTIONS=true HEDGE_PLAN_LIVE_ORDER=false HEDGE_PLAN_OPEN_ORDER=options_first HEDGE_PLAN_ON_PERP_SL_CLOSE_OPTIONS=true diff --git a/crypto_monitor_okx/app.py b/crypto_monitor_okx/app.py index 8555625..ece3d99 100644 --- a/crypto_monitor_okx/app.py +++ b/crypto_monitor_okx/app.py @@ -6785,6 +6785,10 @@ def render_main_page(page="trade", embed_mode=None): options_nav_visible=True, hedge_plan_enabled=os.getenv("HEDGE_PLAN_ENABLED", "false").lower() in ("1", "true", "yes", "on"), hedge_plan_nav_visible=os.getenv("HEDGE_PLAN_ENABLED", "false").lower() in ("1", "true", "yes", "on"), + hedge_plan_show_perp_options=os.getenv("HEDGE_PLAN_SHOW_PERP_OPTIONS", "true").lower() + in ("1", "true", "yes", "on"), + hedge_plan_show_options_options=os.getenv("HEDGE_PLAN_SHOW_OPTIONS_OPTIONS", "true").lower() + in ("1", "true", "yes", "on"), options_trade_budget=OKX_OPTIONS_TRADE_BUDGET_USDC, options_default_underly=OKX_OPTIONS_DEFAULT_UNDERLY, risk_status=risk_status, diff --git a/docs/对冲计划开发方案.md b/docs/对冲计划开发方案.md index b8d2e39..7c6f5e3 100644 --- a/docs/对冲计划开发方案.md +++ b/docs/对冲计划开发方案.md @@ -553,6 +553,8 @@ realized_pnl_total = pnl_option_close - abs(pnl_perp_sl) | 变量 | 前端标签 | 默认 | 控件 | 热更新 | 说明 | |------|----------|------|------|--------|------| | `HEDGE_PLAN_ENABLED` | 启用对冲计划 | false | bool | 热更优先 | 总开关:导航 + API | +| `HEDGE_PLAN_SHOW_PERP_OPTIONS` | 显示永期对冲 | true | bool | 热更 | 关则隐藏永期 Tab,不可测算/开仓 | +| `HEDGE_PLAN_SHOW_OPTIONS_OPTIONS` | 显示期期对冲 | true | bool | 热更 | 关则隐藏期期 Tab,不可测算/开仓 | | `HEDGE_PLAN_LIVE_ORDER` | 允许对冲真实下单 | false | bool | 热更 | 关则只测算/草稿 | | `HEDGE_PLAN_OPEN_ORDER` | 永期开仓顺序 | options_first | select:`options_first`/`perp_first` | 热更 | 默认先期权后永续 | | `HEDGE_PLAN_ON_PERP_SL_CLOSE_OPTIONS` | 永期止损后强制平期权 | true | bool | 热更 | **保护机制,默认 true** | @@ -577,6 +579,8 @@ realized_pnl_total = pnl_option_close - abs(pnl_perp_sl) ```env # --- 对冲计划(仅 OKX;前端 env「对冲计划」) --- HEDGE_PLAN_ENABLED=false +HEDGE_PLAN_SHOW_PERP_OPTIONS=true +HEDGE_PLAN_SHOW_OPTIONS_OPTIONS=true HEDGE_PLAN_LIVE_ORDER=false HEDGE_PLAN_OPEN_ORDER=options_first HEDGE_PLAN_ON_PERP_SL_CLOSE_OPTIONS=true diff --git a/lib/common/static/hedge_plan.js b/lib/common/static/hedge_plan.js index 92ba5ae..a856708 100644 --- a/lib/common/static/hedge_plan.js +++ b/lib/common/static/hedge_plan.js @@ -5,9 +5,22 @@ const root = document.getElementById("hedge-plan-root"); if (!root) return; + function flagOn(attr) { + return root.getAttribute(attr) !== "0"; + } + + const showPerp = flagOn("data-show-perp"); + const showOo = flagOn("data-show-oo"); + + function pickDefaultTab() { + if (showPerp) return "perp_options"; + if (showOo) return "options_options"; + return "active"; + } + const state = { - tab: "perp_options", - mode: "perp_options", + tab: pickDefaultTab(), + mode: showPerp ? "perp_options" : showOo ? "options_options" : "perp_options", underlying: root.getAttribute("data-default-underly") || "ETH", moneyFilter: "all", chain: null, @@ -103,7 +116,10 @@ } function syncTabUI() { - const tab = state.tab || "perp_options"; + let tab = state.tab || pickDefaultTab(); + if (tab === "perp_options" && !showPerp) tab = pickDefaultTab(); + if (tab === "options_options" && !showOo) tab = pickDefaultTab(); + state.tab = tab; document.querySelectorAll(".hp-tab").forEach(function (b) { const on = b.getAttribute("data-tab") === tab; b.classList.toggle("active", on); @@ -120,6 +136,16 @@ if (tab === "perp_options" || tab === "options_options") { state.mode = tab; } + const hint = $("hp-acct-hint"); + if (hint) { + if (tab === "options_options") { + hint.textContent = "期期双腿→期权账户"; + } else if (tab === "perp_options") { + hint.textContent = "永续腿→合约账户 · 期权腿→期权账户"; + } else { + hint.textContent = "进行中/历史含永期与期期;显示开关只影响新建测算 Tab"; + } + } } function setGateLine(gates) { @@ -716,7 +742,10 @@ function bind() { document.querySelectorAll(".hp-tab").forEach(function (b) { b.addEventListener("click", function () { - state.tab = b.getAttribute("data-tab") || "perp_options"; + const next = b.getAttribute("data-tab") || pickDefaultTab(); + if (next === "perp_options" && !showPerp) return; + if (next === "options_options" && !showOo) return; + state.tab = next; syncTabUI(); if (state.tab === "perp_options" || state.tab === "options_options") { void loadGates(); diff --git a/lib/env/env_schema.py b/lib/env/env_schema.py index 4c659e2..6bb14a1 100644 --- a/lib/env/env_schema.py +++ b/lib/env/env_schema.py @@ -83,6 +83,8 @@ HOT_RELOAD_EXACT = frozenset({ "APP_AUTH_DISABLED", "WECHAT_WEBHOOK", "HEDGE_PLAN_ENABLED", + "HEDGE_PLAN_SHOW_PERP_OPTIONS", + "HEDGE_PLAN_SHOW_OPTIONS_OPTIONS", "HEDGE_PLAN_LIVE_ORDER", "HEDGE_PLAN_OPEN_ORDER", "HEDGE_PLAN_ON_PERP_SL_CLOSE_OPTIONS", diff --git a/lib/env/env_ui_manifest.py b/lib/env/env_ui_manifest.py index 268d1f6..ac1983d 100644 --- a/lib/env/env_ui_manifest.py +++ b/lib/env/env_ui_manifest.py @@ -134,6 +134,8 @@ _HEDGE_PLAN_SECTION: dict[str, Any] = { "exchanges": frozenset({"okx"}), "fields": [ ("HEDGE_PLAN_ENABLED", "启用对冲计划", "关闭则隐藏导航且不可开仓"), + ("HEDGE_PLAN_SHOW_PERP_OPTIONS", "显示永期对冲", "默认 true;关闭后隐藏永期 Tab,不可测算/开仓"), + ("HEDGE_PLAN_SHOW_OPTIONS_OPTIONS", "显示期期对冲", "默认 true;关闭后隐藏期期 Tab,不可测算/开仓"), ("HEDGE_PLAN_LIVE_ORDER", "允许对冲真实下单", "再与实盘 LIVE_TRADING_ENABLED 同开才可启动永期"), ("HEDGE_PLAN_OPEN_ORDER", "永期开仓顺序", "options_first 或 perp_first"), ("HEDGE_PLAN_ON_PERP_SL_CLOSE_OPTIONS", "永期止损后强制平期权", "保护机制,建议保持 true"), @@ -153,6 +155,8 @@ _RUNTIME_ENV_DEFAULTS: dict[str, str] = { "RISK_COOLING_HOURS_MANUAL_JOURNAL": "1", "RISK_MANUAL_CLOSE_DAILY_LIMIT": "2", "RISK_MOOD_ISSUES_DAILY_FREEZE": "true", + "HEDGE_PLAN_SHOW_PERP_OPTIONS": "true", + "HEDGE_PLAN_SHOW_OPTIONS_OPTIONS": "true", } diff --git a/lib/hedge_plan/hedge_plan_calc_lib.py b/lib/hedge_plan/hedge_plan_calc_lib.py index a4fae7d..0f2633b 100644 --- a/lib/hedge_plan/hedge_plan_calc_lib.py +++ b/lib/hedge_plan/hedge_plan_calc_lib.py @@ -334,6 +334,8 @@ def gate_status( live_trading: bool = False, active_count: int = 0, max_active: int = 1, + show_perp_options: bool = True, + show_options_options: bool = True, ) -> dict[str, Any]: from lib.trade.position_sizing_lib import is_full_margin_mode @@ -349,6 +351,14 @@ def gate_status( can_preview = False can_start = False reasons.append("期权模块未启用") + if pt == "perp_options" and not show_perp_options: + can_preview = False + can_start = False + reasons.append("永期对冲已隐藏(HEDGE_PLAN_SHOW_PERP_OPTIONS)") + if pt == "options_options" and not show_options_options: + can_preview = False + can_start = False + reasons.append("期期对冲已隐藏(HEDGE_PLAN_SHOW_OPTIONS_OPTIONS)") if not live_order: can_start = False reasons.append("未允许对冲真实下单(HEDGE_PLAN_LIVE_ORDER)") @@ -379,6 +389,8 @@ def gate_status( "live_trading": live_trading, "active_count": active_count, "max_active": max_active, + "show_perp_options": bool(show_perp_options), + "show_options_options": bool(show_options_options), "can_preview": can_preview, "can_start": can_start, "reasons": reasons, diff --git a/lib/hedge_plan/hedge_plan_register.py b/lib/hedge_plan/hedge_plan_register.py index 5a7e26a..b339d2a 100644 --- a/lib/hedge_plan/hedge_plan_register.py +++ b/lib/hedge_plan/hedge_plan_register.py @@ -106,6 +106,14 @@ def _hedge_enabled() -> bool: return _env_bool("HEDGE_PLAN_ENABLED", False) +def _show_perp_options() -> bool: + return _env_bool("HEDGE_PLAN_SHOW_PERP_OPTIONS", True) + + +def _show_options_options() -> bool: + return _env_bool("HEDGE_PLAN_SHOW_OPTIONS_OPTIONS", True) + + def _live_order() -> bool: return _env_bool("HEDGE_PLAN_LIVE_ORDER", False) @@ -140,6 +148,8 @@ def _gates_dict(cfg: dict[str, Any], plan_type: str) -> dict[str, Any]: live_trading=bool(cfg.get("live_trading")) or _env_bool("LIVE_TRADING_ENABLED", False), active_count=active, max_active=_max_active(), + show_perp_options=_show_perp_options(), + show_options_options=_show_options_options(), ) diff --git a/lib/hedge_plan/templates/hedge_plan_panel.html b/lib/hedge_plan/templates/hedge_plan_panel.html index 20176e0..1204ccf 100644 --- a/lib/hedge_plan/templates/hedge_plan_panel.html +++ b/lib/hedge_plan/templates/hedge_plan_panel.html @@ -2,6 +2,8 @@ data-default-underly="{{ options_default_underly | default('ETH') }}" data-hedge-enabled="{{ '1' if hedge_plan_enabled else '0' }}" data-options-enabled="{{ '1' if options_enabled else '0' }}" + data-show-perp="{{ '1' if hedge_plan_show_perp_options | default(true) else '0' }}" + data-show-oo="{{ '1' if hedge_plan_show_options_options | default(true) else '0' }}" data-sizing-mode="{{ position_sizing_mode | default('risk') }}" data-is-full-margin="{{ '1' if position_sizing_mode == 'full_margin' else '0' }}"> {% if not hedge_plan_enabled %} @@ -10,6 +12,9 @@ {% if not options_enabled %}
env配置 → 对冲计划 打开显示开关;进行中/历史仍可查看.