Include LIVE close-fee estimate in target PnL; rest after manual and emergency close.
Align docs so LIVE exit matches SIM fee buffer; manual full close now enters rest_seconds like auto/emergency. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -133,9 +133,14 @@ async def sim_close_group(_user: Annotated[str, Depends(require_user)]) -> dict:
|
||||
status_code=403,
|
||||
detail="未开启「显示手动开仓」;请在策略设置中开启后再用",
|
||||
)
|
||||
from ..strategy import get_engine
|
||||
|
||||
r = get_executor().close_group(reason="manual")
|
||||
if not r.ok and not r.liquidity_wait:
|
||||
raise HTTPException(status_code=400, detail=r.detail)
|
||||
if r.ok:
|
||||
# 与自动/紧急全平一致:成功全平后进入组间休息
|
||||
get_engine().enter_rest_after_close()
|
||||
return {
|
||||
"ok": r.ok,
|
||||
"liquidity_wait": r.liquidity_wait,
|
||||
|
||||
@@ -72,7 +72,7 @@ def enrich_live_unrealized(
|
||||
logger.warning("live unrealized exchange overlay failed: %s", e)
|
||||
|
||||
option_upl = float(base.get("option_upl") or 0.0) # 期权净盈亏(本地)
|
||||
# 保守预估平仓费:按现有名义×费率×2 腿,避免「刚达标、扣费后不够」
|
||||
# LIVE 达标口径:必须扣预估平仓手续费(与 SIM / 策略说明一致)
|
||||
try:
|
||||
from ..config import get_settings
|
||||
|
||||
@@ -89,7 +89,7 @@ def enrich_live_unrealized(
|
||||
+ abs(float(base.get("option_qty_eth") or 0.0))
|
||||
)
|
||||
est_close = max(0.0, notional_est * fr * 2.0)
|
||||
# 资金费 signed:付出为负,直接加总
|
||||
# 资金费 signed:付出为负;再减估平仓费
|
||||
net_pnl = perp_upl + option_upl - fees_paid + funding - est_close
|
||||
|
||||
out = dict(base)
|
||||
|
||||
@@ -183,7 +183,7 @@ class StrategyEngine:
|
||||
detail = r.detail
|
||||
close_data = r.data
|
||||
if r.ok:
|
||||
self._after_close()
|
||||
self.enter_rest_after_close()
|
||||
elif st in ("open", "option_closed_perp_pending"):
|
||||
# A:双腿(或续平永续)
|
||||
r = self.matcher.close_group(reason="emergency", bypass_liquidity=True)
|
||||
@@ -201,7 +201,7 @@ class StrategyEngine:
|
||||
detail = r.detail
|
||||
close_data = r.data
|
||||
if r.ok:
|
||||
self._after_close()
|
||||
self.enter_rest_after_close()
|
||||
|
||||
residuals = self.matcher.settle_all_residuals_now()
|
||||
return {
|
||||
@@ -214,6 +214,10 @@ class StrategyEngine:
|
||||
"state": self.state(),
|
||||
}
|
||||
|
||||
def enter_rest_after_close(self) -> None:
|
||||
"""全平成功后进入组间休息(自动 / 手动 / 紧急共用)。"""
|
||||
self._after_close()
|
||||
|
||||
def _after_close(self) -> None:
|
||||
s = get_settings()
|
||||
row = self.db.fetchone("SELECT * FROM strategy_state WHERE id=1")
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
|
||||
from app.models.db import Database, set_db
|
||||
from app.strategy.engine import StrategyEngine
|
||||
|
||||
|
||||
def test_enter_rest_after_close_sets_resting(tmp_path) -> None:
|
||||
db = Database(tmp_path / "rest.db")
|
||||
set_db(db)
|
||||
db.set_setting("rest_seconds", "120")
|
||||
eng = StrategyEngine()
|
||||
before = int(time.time() * 1000)
|
||||
eng.enter_rest_after_close()
|
||||
row = db.fetchone("SELECT * FROM strategy_state WHERE id=1")
|
||||
assert row is not None
|
||||
assert row["phase"] == "resting"
|
||||
assert int(row["rounds_done"] or 0) >= 1
|
||||
until = int(row["rest_until_ms"] or 0)
|
||||
assert until >= before + 100_000
|
||||
db.close()
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
| 平仓类 | **目标平仓** A 双腿 / B 只平永续(远虚残留);**到期平仓** |
|
||||
| 模式 | 设置页 SIM/LIVE;切 LIVE 输入 `LIVE`;密钥写入 `.env` |
|
||||
| 同时仓 | 最多 1 组活跃;残留期权不挡新开 |
|
||||
| **LIVE 盈亏** | 手续费/永续 UPL/已实现/资金费以**交易所**为准;期权持仓浮盈用本地买一算法(期权净盈亏);USDC **1:1** 折 USDT;达标看组净盈亏(含资金费,不含估平仓费) |
|
||||
| **LIVE 盈亏** | 手续费/永续 UPL/已实现/资金费以**交易所**为准;期权持仓浮盈用本地买一算法(期权净盈亏);USDC **1:1** 折 USDT;达标看组净盈亏(含资金费,**含估平仓手续费**,与 SIM 盯盘一致) |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -5,6 +5,19 @@
|
||||
|
||||
---
|
||||
|
||||
## 2026-07-26 — LIVE 达标含估平仓费;手动/紧急全平进休息
|
||||
|
||||
### 变更
|
||||
|
||||
1. **LIVE 达标口径**:盯盘净利继续扣预估平仓手续费(与策略说明 / SIM 一致);实盘索引改为「含估平仓费」。
|
||||
2. **组间休息**:手动全平成功后调用 `enter_rest_after_close()`;紧急全平成功路径同样进入休息(与自动全平共用)。
|
||||
|
||||
### 测试
|
||||
|
||||
- `pytest` 全量
|
||||
|
||||
---
|
||||
|
||||
## 2026-07-26 — LIVE 对账 / 手动开仓 UI / Token 自动换发
|
||||
|
||||
### 变更
|
||||
|
||||
+2
-2
@@ -91,7 +91,7 @@
|
||||
| 开仓时间窗 | **已取消**,全天可尝试(仍受选约约束) |
|
||||
| 周六/周日 | 默认 **跳过新开仓**(上海时区,`skip_weekends`);持仓仍可平 |
|
||||
| 每日轮次上限 | **不限制**;波动大可能多轮,波动小可能一轮都难 |
|
||||
| 组间休息 | 全平后默认休息 **300 秒**(`rest_seconds`)再开下一组 |
|
||||
| 组间休息 | 全平后默认休息 **300 秒**(`rest_seconds`)再开下一组;**自动达标/到期、手动全平、紧急全平**成功后均进入休息 |
|
||||
| 同时持仓 | 最多 1 组 |
|
||||
|
||||
### 3.4 费用(SIM)
|
||||
@@ -173,7 +173,7 @@
|
||||
|
||||
**4.1.B / 到期 / 紧急全平**:不适用「必须卖掉期权买一」这套闸门(到期与残留按内在价值;紧急可绕过)。
|
||||
|
||||
**紧急全平**:活跃组尽量双腿平掉;残留期权一并按内在价值结算。
|
||||
**紧急全平**:活跃组尽量双腿平掉;残留期权一并按内在价值结算;成功后进入组间休息(与手动全平相同)。
|
||||
|
||||
### 4.4 其它平仓入口 / 原因码
|
||||
|
||||
|
||||
Reference in New Issue
Block a user