Extend semi-auto with ITM/ATM/OTM, offset, and 1:4 sizing.

Moneyness and perp:option units are plan-only; OTM enforces leverage >=180.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-08-08 11:42:57 +08:00
parent 4585dba3c3
commit 457838ef64
17 changed files with 428 additions and 41 deletions
+35 -3
View File
@@ -726,8 +726,10 @@ class StrategySession:
s = self.settings
min_hours, min_lev, max_atm_off, atm_off_on = _strategy_floats()
fixed_on, fixed_perp = _fixed_direction()
# 半自动:强制看法方向 + 实值/平值 + 半自动选约门槛(须已授权)
# 半自动:强制看法方向 + 行权类型(itm/atm/otm) + 半自动选约门槛(须已授权)
semi_on = is_semi_auto()
semi_mny: str | None = None
semi_otm_off: float | None = None
if semi_on:
if not is_armed():
return None
@@ -737,6 +739,8 @@ class StrategySession:
min_hours = float(sp["min_option_hours"])
min_lev = float(sp["min_option_leverage"])
atm_off_on = False
semi_mny = str(sp.get("moneyness") or "otm")
semi_otm_off = float(sp.get("otm_max_offset") or 0)
opt_side_hint = _option_side_for_perp(fixed_perp) if fixed_on else None
# 第一关:振幅过滤(默认关;开启则回看窗振幅须 ≤ 最大%)
if not self._apply_amplitude_first_gate():
@@ -766,12 +770,40 @@ class StrategySession:
mark_px=underlying,
expiry_ymd=ymd,
option_side=opt_side_hint,
moneyness=semi_mny if semi_on else None,
otm_max_offset=semi_otm_off if semi_on else None,
)
if pair is None:
if semi_on and semi_mny == "otm":
logger.info(
"skip expiry=%s no OTM within offset=%.1f for %s mark=%.2f",
ymd,
float(semi_otm_off or 0),
opt_side_hint,
underlying,
)
continue
if fixed_on:
if not is_itm_or_atm(
option_side=opt_side_hint or "",
from .selection import is_otm
side = opt_side_hint or ""
if semi_on and semi_mny == "otm":
if not is_otm(
option_side=side,
strike=pair.strike,
mark_px=underlying,
):
continue
if (
atm_open_offset(pair.strike, underlying)
> float(semi_otm_off or 0) + 1e-9
):
continue
elif semi_on and semi_mny == "atm":
# 平值:须为该到期最接近标的的档
pass
elif not is_itm_or_atm(
option_side=side,
strike=pair.strike,
mark_px=underlying,
):