Add risk-based position sizing (以损定仓) with per-open k resize.

Manual vs risk modes are exclusive; each open floors k to 1 decimal so estimated premium+fees stay within the loss budget.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-29 23:32:42 +08:00
parent 0b51aa15ff
commit 3a4c8d639c
9 changed files with 803 additions and 16 deletions
+35 -8
View File
@@ -716,6 +716,41 @@ class StrategyEngine:
self._set_state(phase="open", last_error="有未平仓,禁止开下一组")
return
self._set_state(phase="wait_signal")
pick = await get_session().pick_for_open_async()
if pick is None:
self._set_state(
last_error="无合格期权:需剩余时长、杠杆(及已开启的ATM偏差)同时满足"
)
return
# 以损定仓:每笔开仓前按指数/卖一重算 k,再写名义与出场(须在资金门前)
try:
from .risk_sizing import apply_risk_sizing_to_ledger
rs = apply_risk_sizing_to_ledger(
index_px=float(pick.underlying_px),
option_ask=float(pick.option_ask),
db=self.db,
)
if not rs.ok:
self._set_state(phase="idle", last_error=rs.detail)
try:
from ..notify import wecom
wecom.notify_fault(
title="以损定仓失败",
detail=rs.detail,
dedupe_key=f"risk_sizing:{rs.detail[:80]}",
)
except Exception:
pass
return
except Exception:
logger.exception("risk sizing failed")
self._set_state(phase="idle", last_error="以损定仓计算异常,暂不开仓")
return
try:
cap = assess_open_capacity(self.db)
if cap.get("perp_can_open") is False or cap.get("option_can_open") is False:
@@ -732,14 +767,6 @@ class StrategyEngine:
except Exception:
logger.exception("open capacity gate failed")
self._set_state(phase="wait_signal")
pick = await get_session().pick_for_open_async()
if pick is None:
self._set_state(
last_error="无合格期权:需剩余时长、杠杆(及已开启的ATM偏差)同时满足"
)
return
self._set_state(phase="opening", last_error=None)
wkey = window_key()
count = self._count_groups_for_day(wkey)