Add ATM open-offset toggle default off.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -52,6 +52,9 @@ class StrategyEngine:
|
||||
min_opt_lev = self.ledger.get_setting_float(
|
||||
"min_option_leverage", s.min_option_leverage
|
||||
)
|
||||
atm_off_on = self.ledger.get_setting_bool(
|
||||
"atm_open_offset_enabled", s.atm_open_offset_enabled
|
||||
)
|
||||
max_atm_off = self.ledger.get_setting_float(
|
||||
"max_atm_open_offset", s.max_atm_open_offset
|
||||
)
|
||||
@@ -80,6 +83,7 @@ class StrategyEngine:
|
||||
"leverage": leverage,
|
||||
"min_option_hours": min_hours,
|
||||
"min_option_leverage": min_opt_lev,
|
||||
"atm_open_offset_enabled": atm_off_on,
|
||||
"max_atm_open_offset": max_atm_off,
|
||||
"can_open": allow_open,
|
||||
"last_error": last_error,
|
||||
@@ -310,7 +314,7 @@ class StrategyEngine:
|
||||
pick = await get_session().pick_for_open_async()
|
||||
if pick is None:
|
||||
self._set_state(
|
||||
last_error="无合格期权:需剩余时长、ATM开仓偏差与杠杆同时满足"
|
||||
last_error="无合格期权:需剩余时长、杠杆(及已开启的ATM偏差)同时满足"
|
||||
)
|
||||
return
|
||||
|
||||
|
||||
@@ -52,9 +52,15 @@ def atm_open_offset(strike: float, mark_px: float) -> float:
|
||||
|
||||
|
||||
def atm_allows_open(
|
||||
strike: float, mark_px: float, *, max_offset: float
|
||||
strike: float,
|
||||
mark_px: float,
|
||||
*,
|
||||
max_offset: float,
|
||||
enabled: bool = False,
|
||||
) -> bool:
|
||||
"""|strike − mark| ≤ max_offset 才允许开仓。"""
|
||||
"""开启限制时:|strike − mark| ≤ max_offset 才允许开仓;关闭则始终允许。"""
|
||||
if not enabled:
|
||||
return True
|
||||
if mark_px <= 0 or max_offset < 0:
|
||||
return False
|
||||
return atm_open_offset(strike, mark_px) <= float(max_offset) + 1e-9
|
||||
|
||||
@@ -36,8 +36,14 @@ def _has_open_position() -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def _strategy_floats() -> tuple[float, float, float]:
|
||||
"""min_hours, min_leverage, max_atm_open_offset"""
|
||||
def _as_bool_setting(raw: str | None, default: bool) -> bool:
|
||||
if raw is None or raw == "":
|
||||
return default
|
||||
return str(raw).strip().lower() in ("1", "true", "yes", "on")
|
||||
|
||||
|
||||
def _strategy_floats() -> tuple[float, float, float, bool]:
|
||||
"""min_hours, min_leverage, max_atm_open_offset, atm_open_offset_enabled"""
|
||||
s = get_settings()
|
||||
try:
|
||||
from ..models.db import get_db
|
||||
@@ -55,9 +61,18 @@ def _strategy_floats() -> tuple[float, float, float]:
|
||||
db.get_setting("max_atm_open_offset", str(s.max_atm_open_offset))
|
||||
or s.max_atm_open_offset
|
||||
)
|
||||
return hours, lev, atm_off
|
||||
atm_on = _as_bool_setting(
|
||||
db.get_setting("atm_open_offset_enabled", str(s.atm_open_offset_enabled)),
|
||||
s.atm_open_offset_enabled,
|
||||
)
|
||||
return hours, lev, atm_off, atm_on
|
||||
except Exception:
|
||||
return s.min_option_hours, s.min_option_leverage, s.max_atm_open_offset
|
||||
return (
|
||||
s.min_option_hours,
|
||||
s.min_option_leverage,
|
||||
s.max_atm_open_offset,
|
||||
s.atm_open_offset_enabled,
|
||||
)
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
@@ -142,7 +157,7 @@ class StrategySession:
|
||||
mark = self.ex.fetch_mark(s.perp_inst_id) or idx
|
||||
if mark is None or mark <= 0:
|
||||
raise RuntimeError("无法获取标的标记/指数价格,无法选 ATM")
|
||||
min_hours, _, _ = _strategy_floats()
|
||||
min_hours, _, _, _ = _strategy_floats()
|
||||
contracts = self.ex.list_option_contracts(s.option_inst_family)
|
||||
pair = select_option_pair(contracts, mark_px=float(mark), min_hours=min_hours)
|
||||
if pair is None:
|
||||
@@ -155,7 +170,7 @@ class StrategySession:
|
||||
from .signal import decide
|
||||
|
||||
s = self.settings
|
||||
min_hours, min_lev, max_atm_off = _strategy_floats()
|
||||
min_hours, min_lev, max_atm_off, atm_off_on = _strategy_floats()
|
||||
idx = self.ex.fetch_index(s.index_inst_id)
|
||||
mark = self.ex.fetch_mark(s.perp_inst_id) or idx
|
||||
if mark is None or mark <= 0:
|
||||
@@ -173,7 +188,10 @@ class StrategySession:
|
||||
continue
|
||||
offset = atm_open_offset(pair.strike, underlying)
|
||||
if not atm_allows_open(
|
||||
pair.strike, underlying, max_offset=max_atm_off
|
||||
pair.strike,
|
||||
underlying,
|
||||
max_offset=max_atm_off,
|
||||
enabled=atm_off_on,
|
||||
):
|
||||
logger.info(
|
||||
"skip expiry=%s strike=%.0f atm_offset=%.1f > max=%.1f",
|
||||
@@ -281,7 +299,7 @@ class StrategySession:
|
||||
def atm_needs_realign(self, mark_px: float | None = None) -> bool:
|
||||
if self._pair is None:
|
||||
return True
|
||||
min_hours, _, _ = _strategy_floats()
|
||||
min_hours, _, _, _ = _strategy_floats()
|
||||
if (
|
||||
hours_until_expiry(self._pair.expiry_ymd, expiry_ms=self._pair.expiry_ms)
|
||||
+ 1e-9
|
||||
|
||||
Reference in New Issue
Block a user