Add one-expiry-per-day open rhythm gate (default on).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-08-01 16:39:32 +08:00
parent 22c42a19a0
commit f1da2778ef
11 changed files with 166 additions and 2 deletions
+6
View File
@@ -35,6 +35,7 @@ KEYS = (
"rest_seconds",
"live_order_interval_sec",
"skip_weekends",
"one_expiry_per_day",
"initial_equity",
"leverage",
"perp_margin_mode",
@@ -69,6 +70,7 @@ class StrategySettingsBody(BaseModel):
rest_seconds: int | None = Field(default=None, ge=0, le=3600)
live_order_interval_sec: float | None = Field(default=None, ge=0.2, le=30)
skip_weekends: bool | None = None
one_expiry_per_day: bool | None = None
initial_equity: float | None = Field(default=None, ge=1000, le=10_000_000)
leverage: float | None = Field(default=None, ge=1, le=125)
perp_margin_mode: str | None = Field(default=None, pattern="^(cross|isolated)$")
@@ -144,6 +146,10 @@ def _read_settings() -> dict:
"skip_weekends": _as_bool(
db.get_setting("skip_weekends", str(s.skip_weekends)), s.skip_weekends
),
"one_expiry_per_day": _as_bool(
db.get_setting("one_expiry_per_day", str(s.one_expiry_per_day)),
s.one_expiry_per_day,
),
"initial_equity": float(
db.get_setting("initial_equity", str(s.initial_equity)) or s.initial_equity
),
+18 -1
View File
@@ -59,7 +59,8 @@ async def sim_open_group(
if ex.has_open_position():
raise HTTPException(status_code=409, detail="有未平仓,禁止开下一组")
s = get_settings()
skip_weekends = Ledger().get_setting_bool("skip_weekends", s.skip_weekends)
ledger = Ledger()
skip_weekends = ledger.get_setting_bool("skip_weekends", s.skip_weekends)
if not can_open_new(skip_weekends=skip_weekends):
raise HTTPException(
status_code=409,
@@ -72,6 +73,22 @@ async def sim_open_group(
status_code=409,
detail="无合格期权:请检查剩余时长、ATM开仓偏差(若已开启)与杠杆(现价/卖一)",
)
one_expiry = ledger.get_setting_bool("one_expiry_per_day", s.one_expiry_per_day)
if one_expiry:
from ..strategy.clock import (
expiry_blocked_by_one_per_day,
used_expiry_ymds_for_day,
)
used = used_expiry_ymds_for_day(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}"
"请等下一到期日"
),
)
force = (body.force_option_side if body else None) or None
if force in ("call", "put"):