Reject OO strikes more than 1% from amplitude high/low.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-08-07 17:50:12 +08:00
parent 6d63c52ae0
commit 0daac05ef5
9 changed files with 124 additions and 19 deletions
+40 -8
View File
@@ -36,17 +36,42 @@ class OoPickCore:
detail: str = "ok"
def pick_otm_call_strike(strikes: list[float], *, spot: float, high: float) -> float | None:
"""虚值 CallK > spot,优先贴近振幅高点"""
def _within_ref_pct(strike: float, ref: float, max_dev_pct: float) -> bool:
"""|Kref|/ref ≤ max_dev_pct%"""
if ref <= 0 or max_dev_pct < 0:
return False
return abs(float(strike) - float(ref)) / float(ref) * 100.0 <= float(
max_dev_pct
) + 1e-12
def pick_otm_call_strike(
strikes: list[float],
*,
spot: float,
high: float,
max_dev_pct: float = 1.0,
) -> float | None:
"""虚值 CallK > spot,贴近振幅高点,且 |K−高|/高 ≤ max_dev_pct%"""
cands = [float(s) for s in strikes if float(s) > float(spot) + 1e-9]
if max_dev_pct >= 0 and high > 0:
cands = [s for s in cands if _within_ref_pct(s, high, max_dev_pct)]
if not cands:
return None
return min(cands, key=lambda s: (abs(s - float(high)), s))
def pick_otm_put_strike(strikes: list[float], *, spot: float, low: float) -> float | None:
"""虚值 PutK < spot,优先贴近振幅低点。"""
def pick_otm_put_strike(
strikes: list[float],
*,
spot: float,
low: float,
max_dev_pct: float = 1.0,
) -> float | None:
"""虚值 PutK < spot,贴近振幅低点,且 |K−低|/低 ≤ max_dev_pct%"""
cands = [float(s) for s in strikes if float(s) < float(spot) - 1e-9]
if max_dev_pct >= 0 and low > 0:
cands = [s for s in cands if _within_ref_pct(s, low, max_dev_pct)]
if not cands:
return None
return min(cands, key=lambda s: (abs(s - float(low)), s))
@@ -61,10 +86,11 @@ def select_oo_pair(
min_hours: float,
now: datetime | None = None,
skip_expiry_ymds: set[str] | None = None,
max_dev_pct: float = 1.0,
) -> tuple[str, int, float, float, str, str] | None:
"""
返回 (expiry_ymd, expiry_ms, call_strike, put_strike, call_inst, put_inst)。
Call/Put 可不同行权价;须同到期均为虚值。
Call/Put 可不同行权价;须同到期均为虚值,且相对高低点偏离不超过 max_dev_pct%
"""
if spot <= 0 or high <= 0 or low <= 0 or high < low:
return None
@@ -80,8 +106,12 @@ def select_oo_pair(
for ymd in eligible:
ems, strikes_map = complete[ymd]
strikes = list(strikes_map.keys())
ck = pick_otm_call_strike(strikes, spot=spot, high=high)
pk = pick_otm_put_strike(strikes, spot=spot, low=low)
ck = pick_otm_call_strike(
strikes, spot=spot, high=high, max_dev_pct=max_dev_pct
)
pk = pick_otm_put_strike(
strikes, spot=spot, low=low, max_dev_pct=max_dev_pct
)
if ck is None or pk is None:
continue
call_inst = strikes_map[ck].get("C")
@@ -113,8 +143,9 @@ def build_oo_pick_core(
amplitude: AmplitudeHL | None = None,
skip_expiry_ymds: set[str] | None = None,
now: datetime | None = None,
max_dev_pct: float = 1.0,
) -> OoPickCore | None:
"""完整期期选约:振幅门 + 虚值双腿 + 杠杆。"""
"""完整期期选约:振幅门 + 虚值双腿(贴高低≤max_dev% + 杠杆。"""
amp = amplitude or fetch_amplitude_hl_for_runtime(amplitude_hours)
if amp is None:
return None
@@ -130,6 +161,7 @@ def build_oo_pick_core(
min_hours=float(min_hours),
now=now,
skip_expiry_ymds=skip_expiry_ymds,
max_dev_pct=float(max_dev_pct),
)
if picked is None:
return None