"""对冲计划:人工结束 + 未成交不显示 open.""" from __future__ import annotations import sqlite3 import unittest from unittest import mock from lib.hedge_plan.hedge_plan_db import ( get_plan, get_plan_legs, init_hedge_plan_tables, insert_leg, insert_plan, legs_contract_summary, ) from lib.hedge_plan.hedge_plan_orders_lib import ( execute_manual_end_plan, reconcile_unfilled_option_legs, ) def _mem(): conn = sqlite3.connect(":memory:") conn.row_factory = sqlite3.Row init_hedge_plan_tables(conn) return conn class TestHedgePlanEnd(unittest.TestCase): def test_legs_summary_marks_unfilled(self): s = legs_contract_summary( [ {"leg_role": "option_a", "inst_id": "ETH-C", "status": "pending"}, {"leg_role": "option_b", "inst_id": "ETH-P", "status": "open"}, {"leg_role": "option_a", "inst_id": "X", "status": "cancelled"}, ] ) self.assertIn("(待补)", s) self.assertIn("(未成交)", s) def test_reconcile_ghost_open_to_pending(self): conn = _mem() pid = insert_plan( conn, { "plan_type": "options_options", "status": "active", "underlying": "ETH", }, ) insert_leg( conn, { "plan_id": pid, "leg_role": "option_a", "inst_id": "ETH-USD_UM-260720-1870-C", "status": "open", "exchange_ord_id": "1", "avg_open": 0.01, }, ) insert_leg( conn, { "plan_id": pid, "leg_role": "option_b", "inst_id": "ETH-USD_UM-260720-1870-P", "status": "open", "exchange_ord_id": "2", "avg_open": 0.02, }, ) cfg = {"exchange_options": object()} with mock.patch( "lib.hedge_plan.hedge_plan_orders_lib._live_option_pos_sheets", side_effect=lambda ex, inst: 0.0 if "C" in inst else 50.0, ), mock.patch( "lib.exchange.okx_options_lib.fetch_option_order", return_value={"ok": True, "state": "canceled", "acc_fill_sz": 0}, ): notes = reconcile_unfilled_option_legs(cfg, conn, pid) self.assertTrue(notes) legs = {l["leg_role"]: l for l in get_plan_legs(conn, pid)} self.assertEqual(legs["option_a"]["status"], "pending") self.assertEqual(legs["option_b"]["status"], "open") self.assertEqual(get_plan(conn, pid)["status"], "partial") def test_manual_end_no_flat(self): conn = _mem() pid = insert_plan( conn, { "plan_type": "options_options", "status": "partial", "underlying": "ETH", }, ) insert_leg( conn, { "plan_id": pid, "leg_role": "option_a", "inst_id": "ETH-C", "status": "pending", "exchange_ord_id": "9", }, ) insert_leg( conn, { "plan_id": pid, "leg_role": "option_b", "inst_id": "ETH-P", "status": "open", "exchange_ord_id": "8", }, ) cfg = {"exchange_options": object()} with mock.patch( "lib.hedge_plan.hedge_plan_orders_lib.reconcile_unfilled_option_legs", return_value=[], ), mock.patch( "lib.exchange.okx_options_lib.cancel_option_order", return_value={"ok": True}, ) as cancel, mock.patch( "lib.hedge_plan.hedge_plan_notify_lib.notify_plan_end", return_value=True, ): out = execute_manual_end_plan(cfg, conn, pid) self.assertTrue(out.get("ok")) self.assertEqual(get_plan(conn, pid)["status"], "closed") self.assertEqual(get_plan(conn, pid)["close_reason"], "manual") legs = {l["leg_role"]: l for l in get_plan_legs(conn, pid)} self.assertEqual(legs["option_a"]["status"], "cancelled") self.assertEqual(legs["option_b"]["status"], "open") # 已有持仓不动 cancel.assert_called() if __name__ == "__main__": unittest.main()