Anchor semi exit to strike +/- move points; side-by-side semi cards.
Forward target is K+/-N not spot+/-N; UI shows option target and perp net lock. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -201,17 +201,18 @@ class SemiExitDecision:
|
||||
def check_semi_exits(
|
||||
*,
|
||||
net_pnl: float,
|
||||
entry_index: float | None,
|
||||
strike: float | None,
|
||||
index_px: float | None,
|
||||
view_side: str,
|
||||
option_move_points: float,
|
||||
perp_exit_unit: float,
|
||||
risk_k: float = 1.0,
|
||||
entry_index: float | None = None,
|
||||
) -> SemiExitDecision:
|
||||
"""
|
||||
顺方向:标的波动达到目标点 且 组合净利>0 → 全平。
|
||||
逆方向兑现:组合净利 ≥ 永续出场基数×k → 全平。
|
||||
流动性在 close_group 内再验;平仓顺序已是先期权后永续。
|
||||
顺方向:指数到达「行权价 ± 波动点」且组合净利>0 → 全平。
|
||||
多/Call:目标 = K + N;空/Put:目标 = K − N(N 为设置的波动点,不是现价±N)。
|
||||
逆方向兑现(永续锁定净利):组合净利 ≥ 净利基数×k → 全平。
|
||||
"""
|
||||
view = (view_side or "long").strip().lower()
|
||||
if view not in ("long", "short"):
|
||||
@@ -221,34 +222,39 @@ def check_semi_exits(
|
||||
net_tgt = max(0.0, float(perp_exit_unit)) * k
|
||||
net = float(net_pnl)
|
||||
|
||||
# 逆方向 / 对冲兑现:净利达标即可离场(不必等点位)
|
||||
# 逆方向 / 永续净利锁定:达标即可离场(不必等点位)
|
||||
if net_tgt > 0 and net + 1e-9 >= net_tgt:
|
||||
return SemiExitDecision(
|
||||
True,
|
||||
REASON_PERP_NET,
|
||||
f"半自动·净利≥{net_tgt:.2f}U(基数×k)",
|
||||
f"半自动·永续净利锁定≥{net_tgt:.2f}U(基数×k)",
|
||||
net_target=net_tgt,
|
||||
)
|
||||
|
||||
if entry_index is None or index_px is None:
|
||||
if index_px is None:
|
||||
return SemiExitDecision(False, "", "缺指数")
|
||||
entry = float(entry_index)
|
||||
idx = float(index_px)
|
||||
if entry <= 0 or idx <= 0 or move <= 0:
|
||||
# 锚定行权价;无 strike 时才回退开仓指数(兼容旧仓)
|
||||
anchor = None
|
||||
if strike is not None and float(strike) > 0:
|
||||
anchor = float(strike)
|
||||
elif entry_index is not None and float(entry_index) > 0:
|
||||
anchor = float(entry_index)
|
||||
if anchor is None or idx <= 0 or move <= 0:
|
||||
return SemiExitDecision(False, "", "点位无效")
|
||||
|
||||
if view == "long":
|
||||
target_idx = entry + move
|
||||
target_idx = anchor + move
|
||||
hit = idx + 1e-9 >= target_idx
|
||||
else:
|
||||
target_idx = entry - move
|
||||
target_idx = anchor - move
|
||||
hit = idx - 1e-9 <= target_idx
|
||||
|
||||
if hit and net > 0:
|
||||
return SemiExitDecision(
|
||||
True,
|
||||
REASON_POINTS,
|
||||
f"半自动·标的到{target_idx:.2f}且组合净利>0",
|
||||
f"半自动·指数到期权目标{target_idx:.2f}(K{anchor:g}±{move:g})且净利>0",
|
||||
target_index=target_idx,
|
||||
net_target=0.0,
|
||||
)
|
||||
@@ -256,13 +262,13 @@ def check_semi_exits(
|
||||
return SemiExitDecision(
|
||||
False,
|
||||
"",
|
||||
f"已到点位{target_idx:.2f}但组合净利≤0({net:.2f}),继续持有",
|
||||
f"已到期权目标{target_idx:.2f}但组合净利≤0({net:.2f}),继续持有",
|
||||
target_index=target_idx,
|
||||
)
|
||||
return SemiExitDecision(
|
||||
False,
|
||||
"",
|
||||
f"未到点位(目标{target_idx:.2f})",
|
||||
f"未到期权目标(K{anchor:g}→{target_idx:.2f})",
|
||||
target_index=target_idx,
|
||||
net_target=net_tgt,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user