Add fixed-direction switch for perp/option open side.
When enabled, lock perp long→buy Put or short→buy Call with ITM/ATM only; off keeps ATM/ask rules. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -46,6 +46,46 @@ def pick_atm_strike(strikes: list[float], mark_px: float) -> float | None:
|
||||
return min(strikes, key=lambda s: (abs(s - mark_px), s))
|
||||
|
||||
|
||||
def pick_itm_or_atm_strike(
|
||||
strikes: list[float],
|
||||
mark_px: float,
|
||||
*,
|
||||
option_side: str,
|
||||
) -> float | None:
|
||||
"""
|
||||
固定方向选约:只要实值或平值,不要虚值。
|
||||
- Call:行权价 ≤ 标的(平值/实值)
|
||||
- Put:行权价 ≥ 标的(平值/实值)
|
||||
在合格档中取最接近标的者(优先平值)。
|
||||
"""
|
||||
if not strikes or mark_px <= 0:
|
||||
return None
|
||||
side = (option_side or "").strip().lower()
|
||||
if side == "call":
|
||||
cands = [float(s) for s in strikes if float(s) <= float(mark_px) + 1e-9]
|
||||
elif side == "put":
|
||||
cands = [float(s) for s in strikes if float(s) >= float(mark_px) - 1e-9]
|
||||
else:
|
||||
return None
|
||||
if not cands:
|
||||
return None
|
||||
return min(cands, key=lambda s: (abs(s - float(mark_px)), s))
|
||||
|
||||
|
||||
def is_itm_or_atm(*, option_side: str, strike: float, mark_px: float) -> bool:
|
||||
"""Call: K≤S;Put: K≥S。"""
|
||||
if mark_px <= 0:
|
||||
return False
|
||||
side = (option_side or "").strip().lower()
|
||||
k = float(strike)
|
||||
s = float(mark_px)
|
||||
if side == "call":
|
||||
return k <= s + 1e-9
|
||||
if side == "put":
|
||||
return k >= s - 1e-9
|
||||
return False
|
||||
|
||||
|
||||
def atm_open_offset(strike: float, mark_px: float) -> float:
|
||||
"""开仓用:ATM 行权价相对标的的绝对点差。"""
|
||||
return abs(float(strike) - float(mark_px))
|
||||
@@ -125,7 +165,13 @@ def select_option_pair(
|
||||
expiry_ymd: str | None = None,
|
||||
min_hours: float | None = None,
|
||||
now: datetime | None = None,
|
||||
option_side: str | None = None,
|
||||
) -> OptionPair | None:
|
||||
"""
|
||||
选到期 + 行权价。
|
||||
option_side 为 call/put 时:按实值/平值选档(固定方向模式);
|
||||
否则仍选 ATM(现有规则)。
|
||||
"""
|
||||
complete = _complete_by_expiry(contracts)
|
||||
if not complete:
|
||||
return None
|
||||
@@ -148,14 +194,20 @@ def select_option_pair(
|
||||
ymd = eligible[0]
|
||||
|
||||
ems, strikes_map = complete[ymd]
|
||||
atm = pick_atm_strike(list(strikes_map.keys()), mark_px)
|
||||
if atm is None:
|
||||
side = (option_side or "").strip().lower() or None
|
||||
if side in ("call", "put"):
|
||||
strike = pick_itm_or_atm_strike(
|
||||
list(strikes_map.keys()), mark_px, option_side=side
|
||||
)
|
||||
else:
|
||||
strike = pick_atm_strike(list(strikes_map.keys()), mark_px)
|
||||
if strike is None:
|
||||
return None
|
||||
legs = strikes_map[atm]
|
||||
legs = strikes_map[strike]
|
||||
return OptionPair(
|
||||
expiry_ymd=ymd,
|
||||
expiry_ms=ems,
|
||||
strike=atm,
|
||||
strike=strike,
|
||||
call_inst_id=legs["C"],
|
||||
put_inst_id=legs["P"],
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user