diff --git a/crypto_monitor_okx/.env.example b/crypto_monitor_okx/.env.example index 9434c31..b01fc5f 100644 --- a/crypto_monitor_okx/.env.example +++ b/crypto_monitor_okx/.env.example @@ -141,8 +141,8 @@ HEDGE_PLAN_OPTIONS_MUTUAL_EXCLUSIVE=true HEDGE_PLAN_MANUAL_COMPLETE_ON_PARTIAL=true MAX_ACTIVE_HEDGE_PLANS=1 HEDGE_PLAN_MONITOR_POLL_SECONDS=15 -# 半腿失败自动平期权;若 MANUAL_COMPLETE_ON_PARTIAL=true 则不会执行自动平 -HEDGE_PLAN_PARTIAL_AUTO_CLOSE_OPTION=true +# 半腿失败自动平期权;若 MANUAL_COMPLETE_ON_PARTIAL=true 则运行时强制无效(建议一并写成 false) +HEDGE_PLAN_PARTIAL_AUTO_CLOSE_OPTION=false # ============================================================================= # 关键位程序自动下单(与 POSITION_SIZING_MODE 联动,修改后须重启 PM2) diff --git a/lib/env/env_ui_manifest.py b/lib/env/env_ui_manifest.py index 89ebc55..b29a05b 100644 --- a/lib/env/env_ui_manifest.py +++ b/lib/env/env_ui_manifest.py @@ -193,6 +193,10 @@ def _effective_env_value(key: str, file_values: dict[str, str], schema_default: return _RUNTIME_ENV_DEFAULTS.get(key, "") +def _env_truthy(raw: str) -> bool: + return str(raw or "").strip().lower() in ("1", "true", "yes", "on") + + def _schema_field_map(example_path: str) -> dict[str, dict[str, Any]]: out: dict[str, dict[str, Any]] = {} for group in parse_env_example_schema(example_path): @@ -211,6 +215,13 @@ def _build_field( meta = schema.get(key) or {} schema_default = meta.get("default") or "" val = _effective_env_value(key, values, schema_default) + # 与运行时一致:手动补开开启时,「自动平期权」展示为关闭(实际也不会执行) + if key == "HEDGE_PLAN_PARTIAL_AUTO_CLOSE_OPTION": + manual = _effective_env_value( + "HEDGE_PLAN_MANUAL_COMPLETE_ON_PARTIAL", values, "true" + ) + if _env_truthy(manual): + val = "false" masked = _mask_value(key, val) ftype = meta.get("type") or _field_type(key, val or schema_default) options = select_options_for(key) @@ -322,3 +333,26 @@ def validate_env_ui_updates( ) groups.append({"title": sec["title"], "fields": fields}) return validate_env_updates(groups, updates) + + +def coerce_hedge_partial_close_with_manual( + clean: dict[str, str], + *, + env_path: str = "", +) -> dict[str, str]: + """手动补开为开启时,强制把自动平写成 false(与运行时一致).""" + out = dict(clean or {}) + manual = out.get("HEDGE_PLAN_MANUAL_COMPLETE_ON_PARTIAL") + if manual is None and env_path: + try: + from lib.env.env_file_lib import env_get_all, read_env_lines + + file_vals = env_get_all(read_env_lines(env_path)) + manual = _effective_env_value( + "HEDGE_PLAN_MANUAL_COMPLETE_ON_PARTIAL", file_vals, "true" + ) + except Exception: + manual = "true" + if _env_truthy(str(manual or "")): + out["HEDGE_PLAN_PARTIAL_AUTO_CLOSE_OPTION"] = "false" + return out diff --git a/lib/instance/instance_settings_register.py b/lib/instance/instance_settings_register.py index f55666a..d928fcc 100644 --- a/lib/instance/instance_settings_register.py +++ b/lib/instance/instance_settings_register.py @@ -11,6 +11,7 @@ from lib.env.env_file_lib import apply_env_updates, env_get, read_env_lines from lib.env.env_ui_manifest import ( build_env_ui_payload, filter_updates_for_ui, + coerce_hedge_partial_close_with_manual, validate_env_ui_updates, ) from lib.env.env_schema import parse_env_example_schema @@ -102,6 +103,7 @@ def register_instance_settings_routes( clean, errors = validate_env_ui_updates(exchange_key, example_path, updates) if errors: return jsonify({"ok": False, "msg": "; ".join(errors)}), 400 + clean = coerce_hedge_partial_close_with_manual(clean, env_path=env_path) if not clean: return jsonify({"ok": True, "changed_keys": [], "restart_required": False}) changed = apply_env_updates(env_path, clean)