Add dual exit modes: fixed USDT or premium multiple.

Net PnL (after estimated close fees) drives auto close; Plan/Settings expose the choice.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-25 09:17:50 +08:00
parent 9fd2a842af
commit cce26e87b5
13 changed files with 282 additions and 72 deletions
+30 -8
View File
@@ -13,7 +13,7 @@ from ..models.db import get_db
from ..sim.ledger import Ledger
from ..sim.matcher import Matcher
from .clock import window_key
from .exits import check_exits
from .exits import check_exits, resolve_exit_target
from .group import next_group_id
logger = logging.getLogger(__name__)
@@ -32,7 +32,19 @@ class StrategyEngine:
assert row is not None
upl = self.matcher.unrealized()
s = get_settings()
exit_pct = self.ledger.get_setting_float("exit_move_pct", s.exit_move_pct)
exit_mode = self.ledger.get_setting_str("exit_mode", s.exit_mode)
net_target = self.ledger.get_setting_float(
"net_profit_target", s.net_profit_target
)
prem_mult = self.ledger.get_setting_float(
"premium_exit_multiple", s.premium_exit_multiple
)
exit_amt, _ = resolve_exit_target(
exit_mode=exit_mode,
net_profit_target=net_target,
premium_exit_multiple=prem_mult,
initial_premium=float(upl.get("initial_premium") or 0),
)
rest_sec = self.ledger.get_setting_int("rest_seconds", s.rest_seconds)
leverage = self.ledger.get_setting_float("leverage", s.leverage)
min_hours = self.ledger.get_setting_float("min_option_hours", s.min_option_hours)
@@ -55,7 +67,10 @@ class StrategyEngine:
"rest_until_ms": rest_until,
"rest_left_sec": rest_left,
"rest_seconds": rest_sec,
"exit_move_pct": exit_pct,
"exit_mode": exit_mode,
"net_profit_target": net_target,
"premium_exit_multiple": prem_mult,
"exit_target_usdt": exit_amt,
"leverage": leverage,
"min_option_hours": min_hours,
"min_option_leverage": min_opt_lev,
@@ -153,17 +168,24 @@ class StrategyEngine:
st = self.db.fetchone("SELECT * FROM strategy_state WHERE id=1")
assert st is not None
exit_pct = self.ledger.get_setting_float("exit_move_pct", s.exit_move_pct)
exit_mode = self.ledger.get_setting_str("exit_mode", s.exit_mode)
net_target = self.ledger.get_setting_float(
"net_profit_target", s.net_profit_target
)
prem_mult = self.ledger.get_setting_float(
"premium_exit_multiple", s.premium_exit_multiple
)
pos = self.matcher.current_position()
# 有未平仓:只盯平仓,绝不开下一组
if pos.get("status") == "open":
upl = self.matcher.unrealized()
decision = check_exits(
perp_upl=float(upl["perp_upl"]),
initial_premium=float(upl["initial_premium"] or 0),
move_pct=float(upl.get("move_pct") or 0),
exit_move_pct=exit_pct,
net_pnl=float(upl.get("net_pnl") or 0),
exit_mode=exit_mode,
net_profit_target=net_target,
premium_exit_multiple=prem_mult,
initial_premium=float(upl.get("initial_premium") or 0),
)
pending_close = st["phase"] in ("liquidity_wait", "closing")
if decision.should_close or pending_close: