Auto-fill 期期 sheets from trading balance with same-sheets default.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -86,6 +86,146 @@ def floor_contracts_to_precision(contracts: float, decimals: int) -> float:
|
||||
return math.floor(raw * scale + 1e-12) / scale
|
||||
|
||||
|
||||
def option_unit_cost_usdc(*, ask: float, ct_mult: float) -> float:
|
||||
"""单张权利金(USDC) = 卖一价 × ct_mult."""
|
||||
a = _f(ask)
|
||||
if a is None or a <= 0:
|
||||
return 0.0
|
||||
return float(a) * float(ct_mult or 0.01)
|
||||
|
||||
|
||||
def resolve_oo_budget_usdc(
|
||||
*,
|
||||
trading_usdc: Any,
|
||||
trade_budget_usdc: Any,
|
||||
buffer_ratio: Any = 0.95,
|
||||
) -> dict[str, Any]:
|
||||
"""期期可用预算 = min(交易户×buffer, 单笔预算)."""
|
||||
import math
|
||||
|
||||
trading = _f(trading_usdc)
|
||||
cap = _f(trade_budget_usdc)
|
||||
buf = _f(buffer_ratio)
|
||||
if buf is None or buf <= 0:
|
||||
buf = 0.95
|
||||
if buf > 1:
|
||||
buf = 1.0
|
||||
trading_cap = None if trading is None else max(0.0, float(trading) * float(buf))
|
||||
trade_cap = None if cap is None else max(0.0, float(cap))
|
||||
if trading_cap is None and trade_cap is None:
|
||||
return {
|
||||
"ok": False,
|
||||
"budget_usdc": 0.0,
|
||||
"trading_cap": None,
|
||||
"trade_budget_cap": None,
|
||||
"buffer_ratio": float(buf),
|
||||
"msg": "缺少交易户余额与单笔预算",
|
||||
}
|
||||
if trading_cap is None:
|
||||
budget = float(trade_cap or 0.0)
|
||||
elif trade_cap is None:
|
||||
budget = float(trading_cap)
|
||||
else:
|
||||
budget = min(float(trading_cap), float(trade_cap))
|
||||
budget = float(math.floor(budget * 1e6 + 1e-12) / 1e6)
|
||||
return {
|
||||
"ok": budget > 0,
|
||||
"budget_usdc": budget,
|
||||
"trading_cap": None if trading_cap is None else round(float(trading_cap), 6),
|
||||
"trade_budget_cap": None if trade_cap is None else round(float(trade_cap), 6),
|
||||
"buffer_ratio": float(buf),
|
||||
"msg": "" if budget > 0 else "可用预算为 0",
|
||||
}
|
||||
|
||||
|
||||
def _cap_sheets_by_ask_depth(sheets: int, ask_sz: Any) -> int:
|
||||
import math
|
||||
|
||||
n = max(0, int(sheets))
|
||||
depth = _f(ask_sz)
|
||||
if depth is None:
|
||||
return n
|
||||
if depth <= 0:
|
||||
return 0
|
||||
return min(n, int(math.floor(float(depth) + 1e-12)))
|
||||
|
||||
|
||||
def suggest_oo_sheets(
|
||||
*,
|
||||
mode: str,
|
||||
budget_usdc: float,
|
||||
ask_a: float,
|
||||
ct_mult_a: float = 0.01,
|
||||
ask_sz_a: Any = None,
|
||||
ask_b: float,
|
||||
ct_mult_b: float = 0.01,
|
||||
ask_sz_b: Any = None,
|
||||
) -> dict[str, Any]:
|
||||
"""期期建议张数:same_sheets(同张数,默认) / split_budget(均分预算)."""
|
||||
import math
|
||||
|
||||
m = (mode or "same_sheets").strip().lower()
|
||||
if m in ("split", "equal_budget", "split_budget", "均分"):
|
||||
m = "split_budget"
|
||||
else:
|
||||
m = "same_sheets"
|
||||
budget = max(0.0, float(budget_usdc or 0.0))
|
||||
cost_a = option_unit_cost_usdc(ask=ask_a, ct_mult=ct_mult_a)
|
||||
cost_b = option_unit_cost_usdc(ask=ask_b, ct_mult=ct_mult_b)
|
||||
if budget <= 0:
|
||||
return {
|
||||
"mode": m,
|
||||
"sheets_a": 0,
|
||||
"sheets_b": 0,
|
||||
"cost_a": round(cost_a, 8),
|
||||
"cost_b": round(cost_b, 8),
|
||||
"premium_est": 0.0,
|
||||
"ok": False,
|
||||
"msg": "可用预算为 0",
|
||||
}
|
||||
if cost_a <= 0 or cost_b <= 0:
|
||||
return {
|
||||
"mode": m,
|
||||
"sheets_a": 0,
|
||||
"sheets_b": 0,
|
||||
"cost_a": round(cost_a, 8),
|
||||
"cost_b": round(cost_b, 8),
|
||||
"premium_est": 0.0,
|
||||
"ok": False,
|
||||
"msg": "缺少有效卖一价,无法建议张数",
|
||||
}
|
||||
if m == "split_budget":
|
||||
half = budget / 2.0
|
||||
n_a = int(math.floor(half / cost_a + 1e-12))
|
||||
n_b = int(math.floor(half / cost_b + 1e-12))
|
||||
else:
|
||||
pair = cost_a + cost_b
|
||||
n = int(math.floor(budget / pair + 1e-12)) if pair > 0 else 0
|
||||
n_a = n
|
||||
n_b = n
|
||||
n_a = _cap_sheets_by_ask_depth(n_a, ask_sz_a)
|
||||
n_b = _cap_sheets_by_ask_depth(n_b, ask_sz_b)
|
||||
if m == "same_sheets":
|
||||
n = min(n_a, n_b)
|
||||
n_a = n
|
||||
n_b = n
|
||||
prem = cost_a * n_a + cost_b * n_b
|
||||
ok = n_a >= 1 and n_b >= 1
|
||||
msg = ""
|
||||
if not ok:
|
||||
msg = "预算不够开 1+1(或卖一深度不足)"
|
||||
return {
|
||||
"mode": m,
|
||||
"sheets_a": n_a,
|
||||
"sheets_b": n_b,
|
||||
"cost_a": round(cost_a, 8),
|
||||
"cost_b": round(cost_b, 8),
|
||||
"premium_est": round(prem, 6),
|
||||
"ok": ok,
|
||||
"msg": msg,
|
||||
}
|
||||
|
||||
|
||||
def build_perp_options_preview(
|
||||
*,
|
||||
direction: str,
|
||||
|
||||
@@ -97,6 +97,8 @@ def _build_cfg(app_module: Any) -> dict[str, Any]:
|
||||
"chain_max_dte": float(os.getenv("OKX_OPTIONS_CHAIN_MAX_DTE_DAYS") or os.getenv("OKX_OPTIONS_MAX_DTE_DAYS") or "14"),
|
||||
"perp_account_label": (os.getenv("OKX_ACCOUNT_LABEL") or "合约账户").strip(),
|
||||
"options_account_label": (os.getenv("OKX_OPTIONS_ACCOUNT_LABEL") or "期权账户").strip(),
|
||||
"trade_budget_usdc": float(os.getenv("OKX_OPTIONS_TRADE_BUDGET_USDC") or "10"),
|
||||
"budget_buffer": float(os.getenv("OKX_OPTIONS_BUDGET_BUFFER") or "0.95"),
|
||||
"live_trading": _env_bool("LIVE_TRADING_ENABLED", False),
|
||||
"send_wechat": getattr(app_module, "send_wechat_msg", None),
|
||||
}
|
||||
@@ -405,6 +407,8 @@ def register_hedge_plan_routes(app: Flask, cfg: dict[str, Any]) -> None:
|
||||
"account_label": cfg.get("options_account_label") or "期权账户",
|
||||
"account_note": "期权腿使用期权账户(交易 USDC)",
|
||||
"options_account": opt_acct,
|
||||
"trade_budget_usdc": cfg.get("trade_budget_usdc"),
|
||||
"budget_buffer": cfg.get("budget_buffer"),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -138,17 +138,23 @@
|
||||
<div id="hp-oo-index" class="muted hp-quote-line"></div>
|
||||
<div id="hp-oo-bal-line" class="muted hp-quote-line"></div>
|
||||
<p class="muted hp-unit-hint">震荡突破:设上下两个目标价(USD);触达任一侧重平盈利腿。张数=<strong>期权张</strong> · 权利金=USDC</p>
|
||||
<div class="form-row hp-oo-size-row">
|
||||
<span class="muted">自动张数</span>
|
||||
<button type="button" class="btn-secondary hp-oo-size-mode active" data-oo-size="same_sheets">同张数</button>
|
||||
<button type="button" class="btn-secondary hp-oo-size-mode" data-oo-size="split_budget">均分预算</button>
|
||||
</div>
|
||||
<p class="muted" id="hp-oo-budget-line"></p>
|
||||
<div id="hp-oo-legs" class="hp-oo-legs">
|
||||
<div class="hp-oo-leg-row" data-leg="a">
|
||||
<div class="muted" id="hp-oo-leg-a-info">腿A: 尚未选用</div>
|
||||
<label>张数 <span class="hp-unit">期权张</span>
|
||||
<input type="number" step="1" min="1" id="hp-oo-sheets-a" value="1" disabled />
|
||||
<input type="number" step="1" min="0" id="hp-oo-sheets-a" value="1" disabled />
|
||||
</label>
|
||||
</div>
|
||||
<div class="hp-oo-leg-row" data-leg="b">
|
||||
<div class="muted" id="hp-oo-leg-b-info">腿B: 尚未选用</div>
|
||||
<label>张数 <span class="hp-unit">期权张</span>
|
||||
<input type="number" step="1" min="1" id="hp-oo-sheets-b" value="1" disabled />
|
||||
<input type="number" step="1" min="0" id="hp-oo-sheets-b" value="1" disabled />
|
||||
</label>
|
||||
</div>
|
||||
<p class="muted" id="hp-oo-prem-line"></p>
|
||||
@@ -264,4 +270,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/static/hedge_plan.js?v=14"></script>
|
||||
<script src="/static/hedge_plan.js?v=15"></script>
|
||||
|
||||
Reference in New Issue
Block a user