From a2075ba73e75840e1d6e081a06fe222f1e0a3b4d Mon Sep 17 00:00:00 2001 From: dekun Date: Sun, 26 Jul 2026 08:54:38 +0800 Subject: [PATCH] Cap options budget-full sizing at min(balance, trade budget) with UI hint. Co-authored-by: Cursor --- lib/common/static/options_panel.js | 7 +++++++ lib/options/options_pricing_lib.py | 5 +++++ lib/options/options_register.py | 9 +++++++-- lib/options/templates/options_panel.html | 8 ++++++-- tests/test_options_budget_full.py | 16 ++++++++++++++++ 5 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 tests/test_options_budget_full.py diff --git a/lib/common/static/options_panel.js b/lib/common/static/options_panel.js index d9ff3c9..87e3017 100644 --- a/lib/common/static/options_panel.js +++ b/lib/common/static/options_panel.js @@ -280,8 +280,15 @@ 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 capEl = document.getElementById("opt-budget-full-cap"); 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 (capEl && root && root.dataset.tradeBudget) { + const n = Number(root.dataset.tradeBudget); + if (Number.isFinite(n) && n > 0) capEl.textContent = n.toFixed(2); + } document.querySelectorAll(".opt-size-mode-chip").forEach(function (chip) { const radio = chip.querySelector('input[name="opt-size-mode"]'); chip.classList.toggle("is-selected", !!(radio && radio.checked)); diff --git a/lib/options/options_pricing_lib.py b/lib/options/options_pricing_lib.py index b86117d..07daf8a 100644 --- a/lib/options/options_pricing_lib.py +++ b/lib/options/options_pricing_lib.py @@ -259,6 +259,11 @@ def eth_amount_from_sheets(sheets: int, ct_mult: float = 0.01) -> float: return round(int(sheets) * float(ct_mult), 8) +def resolve_budget_full_usdc(trading_usdc: float, trade_budget_usdc: float) -> float: + """按可用余额打满:余额大于预算用预算,否则用余额.""" + return min(float(trading_usdc), float(trade_budget_usdc)) + + def calc_order_size( *, quote_per_unit: float, diff --git a/lib/options/options_register.py b/lib/options/options_register.py index 7888b77..c7ee833 100644 --- a/lib/options/options_register.py +++ b/lib/options/options_register.py @@ -163,13 +163,18 @@ def _require_options_ex(cfg: dict[str, Any]): def _budget_full_usdc(cfg: dict[str, Any], ex: Any) -> tuple[float | None, str]: - """交易账户 USDC 可用余额(由 calc_order_size 再乘 budget_buffer 留余量).""" + """打满可用额度 = min(交易户可用 USDC, 单笔预算);calc_order_size 再乘 budget_buffer.""" from lib.exchange.okx_options_lib import fetch_options_trading_usdc + from lib.options.options_pricing_lib import resolve_budget_full_usdc raw = fetch_options_trading_usdc(ex) if raw is None or float(raw) <= 0: return None, "交易账户 USDC 可用余额不足" - return float(raw), "" + trading = float(raw) + cap = _env_float("OKX_OPTIONS_TRADE_BUDGET_USDC", float(cfg.get("trade_budget") or 10.0)) + if cap <= 0: + return None, "单笔预算无效(OKX_OPTIONS_TRADE_BUDGET_USDC)" + return resolve_budget_full_usdc(trading, float(cap)), "" def _open_premium_paid(cfg: dict[str, Any], inst_id: str) -> float | None: diff --git a/lib/options/templates/options_panel.html b/lib/options/templates/options_panel.html index 2cf1ffb..d99f142 100644 --- a/lib/options/templates/options_panel.html +++ b/lib/options/templates/options_panel.html @@ -1,6 +1,7 @@
{% if not options_enabled %}
期权 API 未启用:请在 crypto_monitor_okx/.env 设置 OKX_OPTIONS_ENABLED=true 及主账户 OKX_OPTIONS_API_*,然后 pm2 restart crypto_okx --update-env.
@@ -18,7 +19,7 @@
  • 环境配置「链上仅显示有卖一」开启时,隐藏无真实卖一或深度不足 1 张的合约(估算价 ~ 亦不显示)。
  • 开仓只认真实卖一价且卖一深度≥1;无深度时面板显示参考标记价并禁用买入。
  • 链展示近 14 日到期;T 型默认 ATM ±5 档,可展开全部。
  • -
  • 「按可用余额打满」可用额度 = min(交易 USDC × 预算缓冲 {{ '%.2f'|format(options_budget_buffer|default(0.95)|float) }}, 单笔预算);可在 env「预算缓冲比例」改。
  • +
  • 「按可用余额打满」可用额度 = min(交易户可用 USDC, 单笔预算 {{ '%.2f'|format(options_trade_budget|default(10)|float) }}),再 × 预算缓冲 {{ '%.2f'|format(options_budget_buffer|default(0.95)|float) }} 算张数(env 可改)。
  • 平仓仅买一限价,详见说明文档。
  • 打开《期权开平仓与监控说明》

    @@ -133,6 +134,9 @@
    + @@ -316,4 +320,4 @@ - + diff --git a/tests/test_options_budget_full.py b/tests/test_options_budget_full.py new file mode 100644 index 0000000..579fd70 --- /dev/null +++ b/tests/test_options_budget_full.py @@ -0,0 +1,16 @@ +"""按可用余额打满:min(余额, 单笔预算).""" +from __future__ import annotations + +from lib.options.options_pricing_lib import resolve_budget_full_usdc + + +def test_balance_above_budget_uses_budget(): + assert resolve_budget_full_usdc(100.0, 10.0) == 10.0 + + +def test_balance_below_budget_uses_balance(): + assert resolve_budget_full_usdc(5.0, 10.0) == 5.0 + + +def test_balance_equals_budget(): + assert resolve_budget_full_usdc(10.0, 10.0) == 10.0