"""模拟盘:用分批卖平成交修复已平仓漏计盈亏.""" from __future__ import annotations import sqlite3 import unittest from lib.options.options_db import init_options_tables from lib.sim.broker_lib import SimBroker from lib.sim.db_lib import init_sim_tables class RepairSimPartialClosePnlTests(unittest.TestCase): def test_repair_sums_two_sell_orders(self): conn = sqlite3.connect(":memory:") conn.row_factory = sqlite3.Row init_options_tables(conn) init_sim_tables(conn) inst = "ETH-USD-260927-2700-P" # 开仓 228 张,权利金 0.399;旧逻辑只记了第二笔收回 0.2449 → pnl=-0.1541 conn.execute( """ INSERT INTO options_trades( inst_id, underlying, opt_type, strike, sheets, eth_amount, open_quote, premium_paid, premium_received, realized_pnl, status, premium_ccy, created_at, closed_at ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?) """, ( inst, "ETH", "P", 2700, 228, 2.28, 0.175, 0.399, 0.2449, -0.1541, "closed", "ETH", "2026-09-24 07:09:19", "2026-09-24 20:59:20", ), ) # 两笔卖平各 114 张 conn.execute( """ INSERT INTO sim_option_orders( ord_id, inst_id, side, sheets, avg_px, state, acc_fill_sz, created_at ) VALUES (?,?,?,?,?,'filled',?,?) """, ("sim-a", inst, "sell", 114, 0.12, 114, "2026-09-24 15:00:00"), ) conn.execute( """ INSERT INTO sim_option_orders( ord_id, inst_id, side, sheets, avg_px, state, acc_fill_sz, created_at ) VALUES (?,?,?,?,?,'filled',?,?) """, ("sim-b", inst, "sell", 114, 0.1074, 114, "2026-09-24 20:59:10"), ) conn.commit() def get_db(): return conn # SimBroker 每次 close 自己的连接;测试里复用同一 :memory: 需禁止 close class _Proxy: def __getattr__(self, name): return getattr(conn, name) def close(self): return None broker = SimBroker(lambda: _Proxy()) # type: ignore[arg-type] n = broker.repair_closed_options_pnl_from_sim_orders() self.assertEqual(n, 1) row = conn.execute( "SELECT premium_received, realized_pnl, close_ord_id FROM options_trades WHERE inst_id=?", (inst,), ).fetchone() # ct_mult=2.28/228=0.01; recv=114*0.12*0.01 + 114*0.1074*0.01 = 0.1368+0.122436=0.259236 self.assertAlmostEqual(float(row["premium_received"]), 0.259236, places=6) self.assertAlmostEqual(float(row["realized_pnl"]), 0.259236 - 0.399, places=6) self.assertIn("sim-a", str(row["close_ord_id"])) self.assertIn("sim-b", str(row["close_ord_id"])) # 历史合成应读到修复后的盈亏 hist = broker.option_positions_history_okx_rows(limit=10) self.assertEqual(len(hist), 1) self.assertAlmostEqual(float(hist[0]["realizedPnl"]), 0.259236 - 0.399, places=6) if __name__ == "__main__": unittest.main()