Count expiry settlements as martingale losses.

Even small-profit expiry closes count toward consecutive loss days; only non-expiry profitable days break the streak.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-08-07 15:08:44 +08:00
parent 930e6c26c5
commit 04e5c11027
3 changed files with 66 additions and 5 deletions
+42
View File
@@ -242,3 +242,45 @@ def test_martingale_doubles_capped(tmp_path, monkeypatch) -> None:
assert mg["doubles"] == 3
assert abs(float(mg["effective_pct"]) - 16.0) < 1e-9
db.close()
def test_expiry_settle_counts_as_loss_even_if_profit(tmp_path, monkeypatch) -> None:
"""到期结算小盈利也按亏损计入倍投连亏日。"""
monkeypatch.setenv("MODE", "SIM")
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
from app.models.db import Database
from app.strategy.risk_sizing import consecutive_loss_days
db = Database(tmp_path / "mg_exp.db")
sh = ZoneInfo("Asia/Shanghai")
def day_ms(ymd: str) -> int:
dt = datetime.strptime(ymd, "%Y-%m-%d").replace(hour=16, tzinfo=sh)
return int(dt.astimezone(timezone.utc).timestamp() * 1000)
# 达标盈利打断;随后两天均为到期小盈利 → 仍计连亏 2
rows = [
("e0", day_ms("2026-07-28"), 20.0, "fixed_usdt"),
("e1", day_ms("2026-07-29"), 3.5, "expiry"),
("e2", day_ms("2026-07-30"), 1.2, "expiry"),
]
for gid, ms, pnl, reason in rows:
db.execute(
"""INSERT INTO groups(
group_id, status, realized_pnl, close_at_ms, open_at_ms, close_reason
) VALUES(?,?,?,?,?,?)""",
(gid, "closed", pnl, ms, ms - 3600_000, reason),
)
assert consecutive_loss_days(db) == 2
# 再来一天达标盈利 → 连亏清零
db.execute(
"""INSERT INTO groups(
group_id, status, realized_pnl, close_at_ms, open_at_ms, close_reason
) VALUES(?,?,?,?,?,?)""",
("e3", "closed", 15.0, day_ms("2026-07-31"), day_ms("2026-07-31") - 1000, "fixed_usdt"),
)
assert consecutive_loss_days(db) == 0
db.close()