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 @@
+ @@ -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