Gate one-open-per-expiry by historical expiry_ymd across days.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -77,15 +77,15 @@ async def sim_open_group(
|
||||
if one_expiry:
|
||||
from ..strategy.clock import (
|
||||
expiry_blocked_by_one_per_day,
|
||||
used_expiry_ymds_for_day,
|
||||
used_expiry_ymds,
|
||||
)
|
||||
|
||||
used = used_expiry_ymds_for_day(get_db())
|
||||
used = used_expiry_ymds(get_db())
|
||||
if expiry_blocked_by_one_per_day(pick.pair.expiry_ymd, used, enabled=True):
|
||||
raise HTTPException(
|
||||
status_code=409,
|
||||
detail=(
|
||||
f"同到期日一天只开一次:今日已用过 {pick.pair.expiry_ymd},"
|
||||
f"每个到期只开一次:已用过 {pick.pair.expiry_ymd},"
|
||||
"请等下一到期日"
|
||||
),
|
||||
)
|
||||
|
||||
@@ -67,7 +67,7 @@ class Settings(BaseSettings):
|
||||
rest_seconds: int = 300
|
||||
live_order_interval_sec: float = 1.0 # LIVE 私有下单/查单最小间隔(秒)
|
||||
skip_weekends: bool = True # 上海时区周六日禁止新开仓(已有仓仍可平)
|
||||
# 同到期日一天只开一次:当日已开过某 expiry_ymd 后,平仓也不可再开同到期,只能开更远到期
|
||||
# 每个到期只开一次(跨日):历史上已开过某 expiry_ymd 后不可再开同到期,只能盯下一档
|
||||
one_expiry_per_day: bool = True
|
||||
leverage: float = 3.0 # 永续杠杆
|
||||
# 永续保证金模式:cross=全仓(默认)| isolated=逐仓;期权仍固定 cash(OKX 逐仓/现金)
|
||||
|
||||
@@ -41,15 +41,15 @@ def group_date_ymd(now: datetime | None = None) -> str:
|
||||
return window_key(now)
|
||||
|
||||
|
||||
def used_expiry_ymds_for_day(db: Any, now: datetime | None = None) -> set[str]:
|
||||
def used_expiry_ymds(db: Any, now: datetime | None = None) -> set[str]:
|
||||
"""
|
||||
上海日历日已开过的期权到期日(groups.expiry_ymd,YYMMDD)。
|
||||
按当日组号 G-{YYYYMMDD}-% 统计;含已平仓,用于「同到期一天只开一次」。
|
||||
历史上已开过的期权到期日(groups.expiry_ymd,YYMMDD)。
|
||||
跨日历日:任一已开组(含已平仓)占用该到期后,不可再开同到期,只能盯下一档。
|
||||
"""
|
||||
wkey = window_key(now)
|
||||
_ = now
|
||||
rows = db.fetchall(
|
||||
"SELECT DISTINCT expiry_ymd FROM groups WHERE group_id LIKE ?",
|
||||
(f"G-{wkey}-%",),
|
||||
"""SELECT DISTINCT expiry_ymd FROM groups
|
||||
WHERE expiry_ymd IS NOT NULL AND TRIM(expiry_ymd) != ''"""
|
||||
)
|
||||
out: set[str] = set()
|
||||
for r in rows or []:
|
||||
@@ -59,6 +59,10 @@ def used_expiry_ymds_for_day(db: Any, now: datetime | None = None) -> set[str]:
|
||||
return out
|
||||
|
||||
|
||||
# 兼容旧名(语义已改为跨日/历史到期占用)
|
||||
used_expiry_ymds_for_day = used_expiry_ymds
|
||||
|
||||
|
||||
def pending_residual_expiry_ymds(db: Any) -> set[str]:
|
||||
"""待到期结算的残留期权到期日(YYMMDD);监控/下一组开仓应跳过这些档。"""
|
||||
rows = db.fetchall(
|
||||
@@ -79,7 +83,7 @@ def expiry_blocked_by_one_per_day(
|
||||
*,
|
||||
enabled: bool = True,
|
||||
) -> bool:
|
||||
"""开启时:候选到期已在当日用过则拦截。"""
|
||||
"""开启时:候选到期已在历史上用过则拦截。"""
|
||||
if not enabled:
|
||||
return False
|
||||
y = str(expiry_ymd or "").strip()
|
||||
|
||||
@@ -873,17 +873,17 @@ class StrategyEngine:
|
||||
if pick is not None and one_expiry_per_day:
|
||||
from .clock import (
|
||||
expiry_blocked_by_one_per_day,
|
||||
used_expiry_ymds_for_day,
|
||||
used_expiry_ymds,
|
||||
)
|
||||
|
||||
used = used_expiry_ymds_for_day(self.db)
|
||||
used = used_expiry_ymds(self.db)
|
||||
if expiry_blocked_by_one_per_day(
|
||||
pick.pair.expiry_ymd, used, enabled=True
|
||||
):
|
||||
self._set_state(
|
||||
phase="idle",
|
||||
last_error=(
|
||||
f"同到期日一天只开一次:今日已用过 {pick.pair.expiry_ymd},"
|
||||
f"每个到期只开一次:已用过 {pick.pair.expiry_ymd},"
|
||||
"请等下一到期日"
|
||||
),
|
||||
)
|
||||
|
||||
@@ -72,13 +72,13 @@ def _as_bool_setting(raw: str | None, default: bool) -> bool:
|
||||
def _skip_expiry_ymds_for_next() -> set[str]:
|
||||
"""
|
||||
空仓选约/监控应跳过的到期日:
|
||||
- 当日已开过(one_expiry_per_day)
|
||||
- 历史上已开过该到期(one_expiry_per_day,跨日)
|
||||
- 仍有待结算残留期权的到期档(该档已「完成」开平,盯下一档)
|
||||
"""
|
||||
skip: set[str] = set()
|
||||
try:
|
||||
from ..models.db import get_db
|
||||
from .clock import pending_residual_expiry_ymds, used_expiry_ymds_for_day
|
||||
from .clock import pending_residual_expiry_ymds, used_expiry_ymds
|
||||
|
||||
s = get_settings()
|
||||
db = get_db()
|
||||
@@ -87,7 +87,7 @@ def _skip_expiry_ymds_for_next() -> set[str]:
|
||||
s.one_expiry_per_day,
|
||||
)
|
||||
if one_exp_day:
|
||||
skip |= used_expiry_ymds_for_day(db)
|
||||
skip |= used_expiry_ymds(db)
|
||||
skip |= pending_residual_expiry_ymds(db)
|
||||
except Exception:
|
||||
logger.exception("skip-expiry lookup failed; continue without skip")
|
||||
|
||||
Reference in New Issue
Block a user