Files
dekun f1e3d5527a Fix semi open stalls: one-leg asks, OTM realign, clearer pick errors.
Monitor no longer shows ATM Put bias while semi-auto is authorized for Call.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-08 14:43:00 +08:00

109 lines
2.9 KiB
Python

from __future__ import annotations
from dataclasses import dataclass
@dataclass(slots=True)
class Signal:
bias: str # strike_below_spot | strike_above_spot | call_ask_gt_put | put_ask_gt_call
option_side: str # call | put
perp_side: str # long | short
call_ask: float
put_ask: float
def decide(
call_ask: float | None,
put_ask: float | None,
*,
strike: float | None = None,
mark_px: float | None = None,
) -> Signal | None:
"""
开仓方向:
- 行权价 < 标的 → 买 Call + 永续空(ATM 偏下)
- 行权价 > 标的 → 买 Put + 永续多(ATM 偏上)
- 行权价 ≈ 标的 → 回退 Call/Put 卖一比价
"""
if call_ask is None or put_ask is None:
return None
ca = float(call_ask)
pa = float(put_ask)
if strike is not None and mark_px is not None and float(mark_px) > 0:
diff = float(strike) - float(mark_px)
if diff < -1e-9:
return Signal(
bias="strike_below_spot",
option_side="call",
perp_side="short",
call_ask=ca,
put_ask=pa,
)
if diff > 1e-9:
return Signal(
bias="strike_above_spot",
option_side="put",
perp_side="long",
call_ask=ca,
put_ask=pa,
)
if ca > pa:
return Signal(
bias="call_ask_gt_put",
option_side="call",
perp_side="short",
call_ask=ca,
put_ask=pa,
)
if pa > ca:
return Signal(
bias="put_ask_gt_call",
option_side="put",
perp_side="long",
call_ask=ca,
put_ask=pa,
)
return None
def decide_fixed(
call_ask: float | None,
put_ask: float | None,
*,
perp_side: str,
) -> Signal | None:
"""
固定方向:
- 永续多 → 买 Put(只需 Put 卖一)
- 永续空 → 买 Call(只需 Call 卖一)
对侧卖一缺失时用本侧占位,避免半自动虚值因对侧盘口空而拒单。
"""
side = (perp_side or "").strip().lower()
if side == "long":
if put_ask is None or float(put_ask) <= 0:
return None
pa = float(put_ask)
ca = float(call_ask) if call_ask is not None and float(call_ask) > 0 else pa
return Signal(
bias="fixed_long_put",
option_side="put",
perp_side="long",
call_ask=ca,
put_ask=pa,
)
if side == "short":
if call_ask is None or float(call_ask) <= 0:
return None
ca = float(call_ask)
pa = float(put_ask) if put_ask is not None and float(put_ask) > 0 else ca
return Signal(
bias="fixed_short_call",
option_side="call",
perp_side="short",
call_ask=ca,
put_ask=pa,
)
return None