增加独立的全仓复利开关,与上限开关分离;关闭时隐藏下单模式并拒绝开仓。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-08-12 09:52:13 +08:00
parent 1522117eeb
commit 51e454b0f6
6 changed files with 52 additions and 9 deletions
+4
View File
@@ -115,6 +115,10 @@ OKX_OPTIONS_ENABLED=false
OKX_OPTIONS_ACCOUNT_LABEL=账户·期权
OKX_OPTIONS_TRADE_BUDGET_USDC=10
OKX_OPTIONS_BUDGET_BUFFER=0.95
# 全仓复利:开关控制下单页是否出现该模式;上限开关另控封顶额度
OKX_OPTIONS_COMPOUND_FULL_ENABLED=true
OKX_OPTIONS_COMPOUND_FULL_CAP_ENABLED=false
OKX_OPTIONS_COMPOUND_FULL_CAP_USDC=300
# 交易模式三选一(热更):options=单独期权 / perp_options=永期对冲 / options_options=期期对冲
# 选单独期权时隐藏对冲导航与对冲配置;选对冲时不可单独开期权,仓位按「对冲组数上限」
OKX_TRADE_MODE=options
+4
View File
@@ -6875,6 +6875,10 @@ def render_main_page(page="trade", embed_mode=None):
hedge_plan_budget_buffer=float(os.getenv("HEDGE_PLAN_BUDGET_BUFFER") or "0.95"),
options_trade_budget=OKX_OPTIONS_TRADE_BUDGET_USDC,
options_budget_buffer=float(os.getenv("OKX_OPTIONS_BUDGET_BUFFER") or "0.95"),
options_compound_full_enabled=os.getenv(
"OKX_OPTIONS_COMPOUND_FULL_ENABLED", "true"
).lower()
in ("1", "true", "yes", "on"),
options_compound_full_cap_enabled=os.getenv(
"OKX_OPTIONS_COMPOUND_FULL_CAP_ENABLED", "false"
).lower()
+22 -4
View File
@@ -276,18 +276,36 @@
return el ? el.value : "sheets";
}
function compoundFullEnabled() {
return !!(root && String(root.dataset.compoundFullEnabled || "1") === "1");
}
function updateSizeInputs() {
const mode = currentSizeMode();
const sheetsEl = document.getElementById("opt-sheets-amount");
const ethEl = document.getElementById("opt-eth-amount");
const hint = document.getElementById("opt-budget-full-hint");
const compoundHint = document.getElementById("opt-compound-full-hint");
const compoundWrap = document.getElementById("opt-size-mode-compound-wrap");
const capEl = document.getElementById("opt-budget-full-cap");
const compoundCapLine = document.getElementById("opt-compound-cap-line");
if (sheetsEl) sheetsEl.style.display = mode === "sheets" ? "" : "none";
if (ethEl) ethEl.style.display = mode === "eth_amount" ? "" : "none";
if (hint) hint.style.display = mode === "budget_full" ? "" : "none";
if (compoundHint) compoundHint.style.display = mode === "compound_full" ? "" : "none";
const compoundOn = compoundFullEnabled();
if (compoundWrap) {
compoundWrap.hidden = !compoundOn;
const radio = compoundWrap.querySelector('input[name="opt-size-mode"]');
if (radio) radio.disabled = !compoundOn;
if (!compoundOn && mode === "compound_full") {
const sheetsRadio = document.querySelector('input[name="opt-size-mode"][value="sheets"]');
if (sheetsRadio) {
sheetsRadio.checked = true;
}
}
}
const modeNow = currentSizeMode();
if (sheetsEl) sheetsEl.style.display = modeNow === "sheets" ? "" : "none";
if (ethEl) ethEl.style.display = modeNow === "eth_amount" ? "" : "none";
if (hint) hint.style.display = modeNow === "budget_full" ? "" : "none";
if (compoundHint) compoundHint.style.display = modeNow === "compound_full" && compoundOn ? "" : "none";
if (capEl && root && root.dataset.tradeBudget) {
const n = Number(root.dataset.tradeBudget);
if (Number.isFinite(n) && n > 0) capEl.textContent = n.toFixed(2);
+7 -2
View File
@@ -145,15 +145,20 @@ _OPTIONS_SECTION: dict[str, Any] = {
("OKX_OPTIONS_ACCOUNT_LABEL", "期权账户备注", ""),
("OKX_OPTIONS_TRADE_BUDGET_USDC", "单笔预算(USDC)", ""),
("OKX_OPTIONS_BUDGET_BUFFER", "预算缓冲比例", "如 0.95;打满/全仓复利共用"),
(
"OKX_OPTIONS_COMPOUND_FULL_ENABLED",
"全仓复利开关",
"默认 true;开启后下单页出现「全仓复利」模式;关闭则隐藏且拒绝该模式开仓",
),
(
"OKX_OPTIONS_COMPOUND_FULL_CAP_ENABLED",
"全仓复利上限开关",
"默认 false=关闭上限,用期权户全部可用;true 时按下方上限封顶",
"仅全仓复利开启时有意义;默认 false=不设上限用期权户全部可用;true 时按下方上限封顶",
),
(
"OKX_OPTIONS_COMPOUND_FULL_CAP_USDC",
"全仓复利上限(USDC)",
"仅上限开关开启时生效;例如 300",
"「全仓复利」且「上限开关」都开启时生效;例如 300",
),
(
"OKX_OPTIONS_MAX_ACTIVE_POSITIONS",
+11
View File
@@ -103,6 +103,7 @@ def _build_cfg(app_module: Any) -> dict[str, Any]:
"render_main_page": app_module.render_main_page,
"trade_budget": _env_float("OKX_OPTIONS_TRADE_BUDGET_USDC", 10.0),
"budget_buffer": _env_float("OKX_OPTIONS_BUDGET_BUFFER", 0.95),
"compound_full_enabled": _env_bool("OKX_OPTIONS_COMPOUND_FULL_ENABLED", True),
"compound_full_cap_enabled": _env_bool("OKX_OPTIONS_COMPOUND_FULL_CAP_ENABLED", False),
"compound_full_cap_usdc": _env_float("OKX_OPTIONS_COMPOUND_FULL_CAP_USDC", 300.0),
"default_underly": (os.getenv("OKX_OPTIONS_DEFAULT_UNDERLY") or "ETH").strip().upper(),
@@ -176,8 +177,14 @@ def _budget_full_usdc(cfg: dict[str, Any], ex: Any) -> tuple[float | None, str]:
return resolve_budget_full_usdc(trading, float(cap)), ""
def _compound_full_enabled() -> bool:
return _env_bool("OKX_OPTIONS_COMPOUND_FULL_ENABLED", True)
def _compound_full_usdc(cfg: dict[str, Any], ex: Any) -> tuple[float | None, str]:
"""全仓复利 = 期权交易户可用(可选上限封顶);再由 calc_order_size × budget_buffer."""
if not _compound_full_enabled():
return None, "全仓复利未开启(OKX_OPTIONS_COMPOUND_FULL_ENABLED)"
from lib.exchange.okx_options_lib import fetch_options_trading_usdc
from lib.options.options_pricing_lib import resolve_compound_full_usdc
@@ -472,6 +479,8 @@ def register_options_routes(app: Flask, cfg: dict[str, Any]) -> None:
available_usdc = fetch_options_trading_usdc(ex)
elif mode == "compound_full":
if not _compound_full_enabled():
return jsonify({"ok": False, "msg": "全仓复利未开启(OKX_OPTIONS_COMPOUND_FULL_ENABLED)"})
budget, budget_err = _compound_full_usdc(cfg, ex)
if budget is None:
return jsonify({"ok": False, "msg": budget_err})
@@ -785,6 +794,8 @@ def register_options_routes(app: Flask, cfg: dict[str, Any]) -> None:
return jsonify({"ok": False, "msg": budget_err})
budget_cap = budget
elif mode == "compound_full":
if not _compound_full_enabled():
return jsonify({"ok": False, "msg": "全仓复利未开启(OKX_OPTIONS_COMPOUND_FULL_ENABLED)"})
budget, budget_err = _compound_full_usdc(cfg, ex)
if budget is None:
return jsonify({"ok": False, "msg": budget_err})
+4 -3
View File
@@ -2,6 +2,7 @@
data-default-underly="{{ options_default_underly | default('ETH') }}"
data-budget-buffer="{{ options_budget_buffer | default(0.95) }}"
data-trade-budget="{{ options_trade_budget | default(10) }}"
data-compound-full-enabled="{% if options_compound_full_enabled %}1{% else %}0{% endif %}"
data-compound-cap-enabled="{% if options_compound_full_cap_enabled %}1{% else %}0{% endif %}"
data-compound-cap-usdc="{{ '%.2f'|format(options_compound_full_cap_usdc|default(300)|float) }}"
data-ask-liq-filter="{% if options_chain_ask_liq_filter is defined %}{{ '1' if options_chain_ask_liq_filter else '0' }}{% else %}1{% endif %}">
@@ -134,8 +135,8 @@
<input type="radio" name="opt-size-mode" value="budget_full">
<span>按可用余额打满</span>
</label>
<label class="btn-secondary opt-order-chip opt-size-mode-chip">
<input type="radio" name="opt-size-mode" value="compound_full">
<label class="btn-secondary opt-order-chip opt-size-mode-chip" id="opt-size-mode-compound-wrap"{% if options_compound_full_enabled is defined and not options_compound_full_enabled %} hidden{% endif %}>
<input type="radio" name="opt-size-mode" value="compound_full"{% if options_compound_full_enabled is defined and not options_compound_full_enabled %} disabled{% endif %}>
<span>全仓复利</span>
</label>
<label class="btn-secondary opt-order-chip opt-size-mode-chip">
@@ -334,4 +335,4 @@
</div>
</div>
<script src="/static/options_expiry_countdown.js?v=1"></script>
<script src="/static/options_panel.js?v=57"></script>
<script src="/static/options_panel.js?v=58"></script>