Add end-plan action; never show unfilled option legs as open.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
"""对冲计划:人工结束 + 未成交不显示 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()
|
||||
Reference in New Issue
Block a user