5c334a4d89
Co-authored-by: Cursor <cursoragent@cursor.com>
86 lines
2.8 KiB
Python
86 lines
2.8 KiB
Python
"""顶栏资金摘要:总交易/胜率/盈亏比按历史全部已平组。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
from datetime import datetime
|
|
from types import SimpleNamespace
|
|
from zoneinfo import ZoneInfo
|
|
|
|
from app.api import funds as funds_api
|
|
from app.models.db import Database, set_db
|
|
from app.strategy.engine import set_engine
|
|
|
|
|
|
def _insert_closed(db: Database, *, group_id: str, pnl: float) -> None:
|
|
now = 1_700_000_000_000
|
|
with db._lock:
|
|
db._conn.execute(
|
|
"""INSERT INTO groups(
|
|
group_id, status, bias, option_side, perp_side, option_inst_id,
|
|
strike, expiry_ymd, initial_premium, open_at_ms, close_at_ms,
|
|
close_reason, realized_pnl, fees, slip_cost
|
|
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)""",
|
|
(
|
|
group_id,
|
|
"closed",
|
|
"test",
|
|
"call",
|
|
"short",
|
|
"ETH-USD_UM-260801-2000-C",
|
|
2000.0,
|
|
"260801",
|
|
100.0,
|
|
now,
|
|
now + 1000,
|
|
"manual",
|
|
pnl,
|
|
1.0,
|
|
0.0,
|
|
),
|
|
)
|
|
db._conn.commit()
|
|
|
|
|
|
def test_all_time_stats_consistent(tmp_path, monkeypatch) -> None:
|
|
monkeypatch.setenv("MODE", "SIM")
|
|
db = Database(tmp_path / "funds_sum.db")
|
|
set_db(db)
|
|
try:
|
|
# 历史 3 胜 1 负 → 75%;另有当日 1 笔亏损 → 合计 5 笔、胜率 60%
|
|
_insert_closed(db, group_id="G-20260101-01", pnl=10.0)
|
|
_insert_closed(db, group_id="G-20260101-02", pnl=20.0)
|
|
_insert_closed(db, group_id="G-20260101-03", pnl=5.0)
|
|
_insert_closed(db, group_id="G-20260101-04", pnl=-10.0)
|
|
_insert_closed(db, group_id="G-20260802-01", pnl=-8.0)
|
|
|
|
class _FakeDT:
|
|
@staticmethod
|
|
def now(tz=None):
|
|
from datetime import timezone
|
|
|
|
if tz is timezone.utc:
|
|
return datetime(2026, 8, 2, 4, 0, tzinfo=timezone.utc)
|
|
return datetime(2026, 8, 2, 12, 0, tzinfo=tz or ZoneInfo("Asia/Shanghai"))
|
|
|
|
monkeypatch.setattr(funds_api, "datetime", _FakeDT)
|
|
set_engine(
|
|
SimpleNamespace(
|
|
state=lambda: {
|
|
"exchange": "okx",
|
|
"position": {"status": "flat"},
|
|
}
|
|
) # type: ignore[arg-type]
|
|
)
|
|
|
|
body = asyncio.run(funds_api.funds_summary(_user="admin"))
|
|
assert body["ok"] is True
|
|
assert body["trading_day"] == "2026-08-02"
|
|
assert body["total_trades"] == 5
|
|
assert abs(body["win_rate"] - 0.6) < 1e-9
|
|
assert body["profit_loss_ratio"] is not None
|
|
finally:
|
|
set_engine(None)
|
|
set_db(None)
|
|
db.close()
|