Add OKX options expiry and close breakeven to hub monitor and dashboard.
Expose bePx-based expiry balance and mark-to-close breakeven on positions so monitor and dashboard can show both labels per contract. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -132,3 +132,75 @@ def option_moneyness(*, opt_type: str, strike: float, index_px: float) -> str:
|
||||
|
||||
def option_moneyness_label(moneyness: str) -> str:
|
||||
return {"itm": "实值", "otm": "虚值", "atm": "平值"}.get((moneyness or "").lower(), "")
|
||||
|
||||
|
||||
def expiry_breakeven_px(
|
||||
*,
|
||||
opt_type: str,
|
||||
strike: float | None,
|
||||
avg_px: float | None,
|
||||
be_px_api: float | None = None,
|
||||
) -> float | None:
|
||||
"""到期平衡点:持有至到期时标的指数盈亏为 0 的价格。优先 OKX bePx。"""
|
||||
if be_px_api is not None and be_px_api > 0:
|
||||
return round(float(be_px_api), 2)
|
||||
if strike is None or avg_px is None:
|
||||
return None
|
||||
o = (opt_type or "").upper()
|
||||
if o == "C":
|
||||
return round(strike + avg_px, 2)
|
||||
if o == "P":
|
||||
return round(strike - avg_px, 2)
|
||||
return None
|
||||
|
||||
|
||||
def close_breakeven_idx(
|
||||
*,
|
||||
opt_type: str,
|
||||
idx_px: float | None,
|
||||
mark_px: float | None,
|
||||
avg_px: float | None,
|
||||
delta_pa: float | None = None,
|
||||
pos: float = 0,
|
||||
ct_mult: float = 0.01,
|
||||
) -> float | None:
|
||||
"""
|
||||
平掉回本:标的指数达到该价位时,按标记价平仓近似盈亏为 0。
|
||||
优先用 deltaPA 线性外推,否则用时间价值近似(适合短期轻度实值)。
|
||||
"""
|
||||
if idx_px is None or mark_px is None or avg_px is None:
|
||||
return None
|
||||
eth_amt = abs(float(pos)) * float(ct_mult)
|
||||
if eth_amt > 1e-12 and delta_pa is not None and abs(float(delta_pa)) > 1e-12:
|
||||
slope = float(delta_pa) / eth_amt
|
||||
return round(float(idx_px) + (float(avg_px) - float(mark_px)) / slope, 2)
|
||||
o = (opt_type or "").upper()
|
||||
if o == "C":
|
||||
return round(float(idx_px) + float(avg_px) - float(mark_px), 2)
|
||||
if o == "P":
|
||||
return round(float(idx_px) + float(mark_px) - float(avg_px), 2)
|
||||
return None
|
||||
|
||||
|
||||
def idx_distance_to_be(idx_px: float | None, be_px: float | None) -> float | None:
|
||||
"""指数距平衡点(正=指数需上涨才到平衡点)。"""
|
||||
if idx_px is None or be_px is None:
|
||||
return None
|
||||
return round(float(be_px) - float(idx_px), 2)
|
||||
|
||||
|
||||
def format_options_breakeven_line(
|
||||
*,
|
||||
expiry_be_px: float | None,
|
||||
close_be_px: float | None,
|
||||
idx_px: float | None = None,
|
||||
) -> str:
|
||||
"""持仓摘要行:到期平衡 / 平掉回本。"""
|
||||
parts: list[str] = []
|
||||
if expiry_be_px is not None:
|
||||
parts.append(f"到期平衡{expiry_be_px:.0f}")
|
||||
if close_be_px is not None:
|
||||
parts.append(f"平掉回本{close_be_px:.0f}")
|
||||
if idx_px is not None and parts:
|
||||
return " ".join(parts) + f"(指数{idx_px:.0f})"
|
||||
return " ".join(parts)
|
||||
|
||||
Reference in New Issue
Block a user