修复模拟盘期权历史分批平仓盈亏:用卖平成交重算已平记录。
加载历史前按 sim_option_orders(或钱包流水)合计各批收回,纠正只记最后一笔的旧数据。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
"""模拟盘:用分批卖平成交修复已平仓漏计盈亏."""
|
||||
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()
|
||||
Reference in New Issue
Block a user