"""期期到期结算指数:虚值 Call fill=0 不得反推成行权价。""" from __future__ import annotations from app.api.trades import _infer_settle_index, _overlay_expiry_zero_fills def test_otm_call_zero_fill_does_not_become_strike(monkeypatch) -> None: g = { "hedge_mode": "option_option", "option_side": "call", "option2_side": "put", "option_inst_id": "ETH-USD-260811-1920-C", # OKX 样式:不走公开回退 "strike": 1920.0, "strike2": 1890.0, "settle_index_px": None, "close_reason": "expiry", "close_at_ms": 1, } fills = [ {"leg": "option", "action": "close", "fill_px": 0.0, "slip": 0}, {"leg": "option2", "action": "close", "fill_px": 0.0, "slip": 0}, ] monkeypatch.setattr( "app.api.public_index.maybe_public_settle_index", lambda _g: None ) assert _infer_settle_index(g, fills) is None def test_itm_put_fill_infers_settle_near_1875() -> None: g = { "hedge_mode": "option_option", "option_side": "call", "option2_side": "put", "strike": 1920.0, "strike2": 1920.0, "settle_index_px": None, } fills = [ {"leg": "option", "action": "close", "fill_px": 0.0, "slip": 0}, {"leg": "option2", "action": "close", "fill_px": 45.0, "slip": 0}, ] assert _infer_settle_index(g, fills) == 1875.0 def test_stored_settle_wins() -> None: g = { "option_side": "call", "strike": 1920.0, "settle_index_px": 1875.2, } fills = [{"leg": "option", "action": "close", "fill_px": 0.0, "slip": 0}] assert _infer_settle_index(g, fills) == 1875.2 def test_public_fallback_and_overlay(monkeypatch) -> None: g = { "hedge_mode": "option_option", "option_side": "call", "option2_side": "put", "option_inst_id": "ETH-USD_UM-260811-1940-C", "strike": 1940.0, "strike2": 1920.0, "settle_index_px": None, "close_reason": "expiry", "close_at_ms": 1786435200000, } fills = [ {"leg": "option", "action": "close", "fill_px": 0.0, "qty_eth": 7, "slip": 0}, {"leg": "option2", "action": "close", "fill_px": 0.0, "qty_eth": 7, "slip": 0}, ] monkeypatch.setattr( "app.api.public_index.maybe_public_settle_index", lambda _g: 1877.8 ) assert _infer_settle_index(g, fills) == 1877.8 view = _overlay_expiry_zero_fills(g, fills, 1877.8) assert view[0]["fill_px"] == 0.0 # call OTM assert abs(view[1]["fill_px"] - (1920 - 1877.8)) < 1e-9 def test_overlay_wrong_near_zero_put_fill() -> None: """账单误写成 0.2 时,应按内在价值 42.2 覆盖,Put 显示盈利。""" g = { "hedge_mode": "option_option", "option_side": "call", "option2_side": "put", "strike": 1940.0, "strike2": 1920.0, "close_reason": "expiry", } fills = [ { "leg": "option", "action": "open", "fill_px": 12.0, "qty_eth": 7.5, "fee": 0.045, "slip": 0, }, { "leg": "option2", "action": "open", "fill_px": 12.8, "qty_eth": 7.0, "fee": 0.045, "slip": 0, }, { "leg": "option", "action": "close", "fill_px": 0.0, "qty_eth": 7.5, "fee": 0, "slip": 0, }, { "leg": "option2", "action": "close", "fill_px": 0.2, "qty_eth": 7.0, "fee": 0.0007, "slip": 0, }, ] from app.sim.pnl import summarize_fills_pnl view = _overlay_expiry_zero_fills(g, fills, 1877.8) assert abs(view[3]["fill_px"] - 42.2) < 1e-9 s = summarize_fills_pnl(view) # Put: (42.2 - 12.8) * 7 = 205.8 assert abs(float(s["option2_pnl"] or 0) - 205.8) < 1e-6 assert float(s["option2_pnl"] or 0) > 0