- 权益曲线
- 权益=稳定币现金+现货币折U+持仓权利金U+浮盈U;后台定时采样。
+ 已实现盈亏曲线
+ 累计已实现盈亏(期权平仓真盈亏U累加);划转/提现不影响。
@@ -78,8 +78,8 @@
—
-
+
-
+
diff --git a/tests/test_instance_equity_sample.py b/tests/test_instance_equity_sample.py
index 5c6895d..289e614 100644
--- a/tests/test_instance_equity_sample.py
+++ b/tests/test_instance_equity_sample.py
@@ -1,15 +1,19 @@
-"""权益曲线采样:现金+现货币+权利金+浮盈."""
+"""权益采样辅助(曲线已改为已实现盈亏,此处仅覆盖权益计算工具)."""
from __future__ import annotations
import sqlite3
+import tempfile
import unittest
+from pathlib import Path
class EquitySampleTests(unittest.TestCase):
def test_equity_fills_open_cliff(self):
- from lib.instance.instance_cash_sample_lib import equity_usdt_from_snapshot
+ from lib.instance.instance_cash_sample_lib import (
+ cash_usdt_from_balances,
+ equity_usdt_from_snapshot,
+ )
- # 开仓后:USDT 所剩无几,BTC 缓冲 + 权利金仓位
bal = {
"trading_usdt": 50.0,
"funding_usdt": 0.0,
@@ -26,49 +30,15 @@ class EquitySampleTests(unittest.TestCase):
"mark": 0.01,
}
]
- # cash 50 + spot 84 + premium 840 = 974; 浮盈约 0
eq = equity_usdt_from_snapshot(bal, positions, btc_px=84000.0, eth_px=None)
self.assertIsNotNone(eq)
self.assertGreater(float(eq), 900.0)
- # 纯现金会只有 50
- from lib.instance.instance_cash_sample_lib import cash_usdt_from_balances
-
self.assertAlmostEqual(float(cash_usdt_from_balances(bal)), 50.0, places=2)
- def test_query_prefers_equity_column(self):
+ def test_record_writes_equity_column(self):
from lib.instance.instance_cash_sample_lib import (
init_cash_sample_table,
- query_cash_series_with_db,
record_cash_sample,
- )
-
- conn = sqlite3.connect(":memory:")
- conn.row_factory = sqlite3.Row
- init_cash_sample_table(conn)
- record_cash_sample(conn, 100.0, equity_usdt=500.0, ts_ms=1_700_000_000_000)
- record_cash_sample(conn, 120.0, equity_usdt=None, ts_ms=1_700_000_060_000)
- # 旧点无 equity 列时回退 cash:手动插一条仅 cash
- conn.execute(
- "INSERT INTO instance_cash_samples(ts_ms, cash_usdt) VALUES (?, ?)",
- (1_700_000_120_000, 130.0),
- )
- conn.commit()
- out = query_cash_series_with_db(conn, range_key="all")
- self.assertTrue(out["ok"])
- self.assertEqual(out["metric"], "equity")
- pts = out["points"]
- self.assertEqual(len(pts), 3)
- self.assertAlmostEqual(pts[0]["v"], 500.0, places=2)
- self.assertAlmostEqual(pts[1]["v"], 120.0, places=2) # equity 默认写成 cash
- self.assertAlmostEqual(pts[2]["v"], 130.0, places=2) # 历史无 equity → cash
- conn.close()
-
- def test_sample_once_dict_snapshot(self):
- import tempfile
- from pathlib import Path
-
- from lib.instance.instance_cash_sample_lib import (
- query_cash_series_with_db,
sample_once,
)
@@ -86,8 +56,19 @@ class EquitySampleTests(unittest.TestCase):
self.assertTrue(ok)
conn = get_db()
try:
- out = query_cash_series_with_db(conn, range_key="all")
- self.assertAlmostEqual(float(out["latest"]), 950.0, places=2)
+ init_cash_sample_table(conn)
+ row = conn.execute(
+ "SELECT cash_usdt, equity_usdt FROM instance_cash_samples ORDER BY ts_ms DESC LIMIT 1"
+ ).fetchone()
+ self.assertAlmostEqual(float(row["cash_usdt"]), 200.0, places=2)
+ self.assertAlmostEqual(float(row["equity_usdt"]), 950.0, places=2)
+ record_cash_sample(conn, 100.0, equity_usdt=500.0, ts_ms=1_700_000_000_000)
+ conn.commit()
+ row2 = conn.execute(
+ "SELECT equity_usdt FROM instance_cash_samples WHERE ts_ms=?",
+ (1_700_000_000_000,),
+ ).fetchone()
+ self.assertAlmostEqual(float(row2["equity_usdt"]), 500.0, places=2)
finally:
conn.close()
diff --git a/tests/test_instance_realized_pnl_curve.py b/tests/test_instance_realized_pnl_curve.py
new file mode 100644
index 0000000..ff8a1c1
--- /dev/null
+++ b/tests/test_instance_realized_pnl_curve.py
@@ -0,0 +1,75 @@
+"""已实现盈亏曲线:累计平仓真盈亏,不受划转影响."""
+from __future__ import annotations
+
+import sqlite3
+import unittest
+
+
+class RealizedPnlCurveTests(unittest.TestCase):
+ def _init(self):
+ from lib.options.options_db import init_options_tables
+
+ conn = sqlite3.connect(":memory:")
+ conn.row_factory = sqlite3.Row
+ init_options_tables(conn)
+ return conn
+
+ def test_cumulative_steps(self):
+ from lib.instance.instance_cash_sample_lib import query_realized_pnl_series_with_db
+
+ conn = self._init()
+ conn.execute(
+ """
+ INSERT INTO options_trades(
+ inst_id, underlying, opt_type, sheets, eth_amount,
+ premium_paid, premium_received, realized_pnl, premium_ccy,
+ status, realized_pnl_usdt, close_index_px,
+ created_at, closed_at
+ ) VALUES
+ ('BTC-A','BTC','P',1,0.01,0.01,0.02,0.01,'BTC','closed',100.0,80000,
+ '2026-10-01 10:00:00','2026-10-01 12:00:00'),
+ ('BTC-B','BTC','P',1,0.01,0.01,0.02,0.01,'BTC','closed',50.0,80000,
+ '2026-10-02 10:00:00','2026-10-02 12:00:00'),
+ ('BTC-C','BTC','P',1,0.01,0.01,0.02,-0.01,'BTC','closed',-20.0,80000,
+ '2026-10-03 10:00:00','2026-10-03 12:00:00')
+ """
+ )
+ conn.commit()
+ out = query_realized_pnl_series_with_db(conn, range_key="all")
+ self.assertTrue(out["ok"])
+ self.assertEqual(out["metric"], "realized_pnl")
+ self.assertEqual(out["trade_count"], 3)
+ # 点含区间起点/各笔台阶/延伸到 now;累计最终 130
+ self.assertAlmostEqual(float(out["latest"]), 130.0, places=2)
+ vals = [p["v"] for p in out["points"]]
+ self.assertIn(100.0, vals)
+ self.assertIn(150.0, vals)
+ self.assertIn(130.0, vals)
+ conn.close()
+
+ def test_range_carries_baseline(self):
+ from lib.instance.instance_cash_sample_lib import query_realized_pnl_series_with_db
+
+ conn = self._init()
+ # 一笔很早的盈利,窗口内无新单 → 水平线在 80
+ conn.execute(
+ """
+ INSERT INTO options_trades(
+ inst_id, underlying, opt_type, sheets, eth_amount,
+ premium_paid, premium_received, realized_pnl, premium_ccy,
+ status, realized_pnl_usdt, created_at, closed_at
+ ) VALUES (
+ 'BTC-OLD','BTC','P',1,0.01,0.01,0.02,0.01,'BTC',
+ 'closed', 80.0, '2020-01-01 10:00:00', '2020-01-01 12:00:00'
+ )
+ """
+ )
+ conn.commit()
+ out = query_realized_pnl_series_with_db(conn, range_key="7d")
+ self.assertAlmostEqual(float(out["latest"]), 80.0, places=2)
+ self.assertTrue(all(abs(float(p["v"]) - 80.0) < 1e-6 for p in out["points"]))
+ conn.close()
+
+
+if __name__ == "__main__":
+ unittest.main()