Files
crypto_monitor/tests/test_hedge_plan_moneyness.py
dekun c5d3d9d6c1 期期出场改盈亏比:达目标平盈利腿,亏损腿残值20%或到期平
将上/下破目标价替换为盈亏比(盈利金额/初始权利金,默认2);残值平需买一流动性且权利金≤初始20%。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-11 16:44:45 +08:00

119 lines
4.3 KiB
Python

"""对冲计划虚实值选约与校验."""
import unittest
from lib.hedge_plan.hedge_plan_moneyness_lib import (
is_atm_or_otm,
is_itm_or_atm,
parse_strike_from_inst,
pick_itm_or_atm_contract,
recommend_oo_legs,
validate_oo_legs_moneyness,
validate_po_option_moneyness,
)
from lib.hedge_plan.hedge_plan_orders_lib import validate_start_body
class TestHedgeMoneyness(unittest.TestCase):
def test_parse_strike(self):
self.assertEqual(parse_strike_from_inst("ETH-USD-260731-1800-P"), 1800.0)
self.assertIsNone(parse_strike_from_inst("bad"))
def test_po_geometry(self):
# Call: K<=S 实/平
self.assertTrue(is_itm_or_atm(opt_type="C", strike=3500, index_px=3510))
self.assertFalse(is_itm_or_atm(opt_type="C", strike=3600, index_px=3510))
# Put: K>=S
self.assertTrue(is_itm_or_atm(opt_type="P", strike=3600, index_px=3510))
self.assertFalse(is_itm_or_atm(opt_type="P", strike=3400, index_px=3510))
def test_oo_geometry(self):
self.assertTrue(is_atm_or_otm(opt_type="C", strike=3600, index_px=3510))
self.assertFalse(is_atm_or_otm(opt_type="C", strike=3400, index_px=3510))
self.assertTrue(is_atm_or_otm(opt_type="P", strike=3400, index_px=3510))
self.assertFalse(is_atm_or_otm(opt_type="P", strike=3600, index_px=3510))
def test_validate_po_rejects_otm(self):
err = validate_po_option_moneyness(opt_type="P", strike=1700, index_px=1800)
self.assertIsNotNone(err)
self.assertIn("虚值", err)
self.assertIsNone(
validate_po_option_moneyness(opt_type="P", strike=1800, index_px=1800)
)
def test_validate_oo_rejects_itm(self):
err = validate_oo_legs_moneyness(
{"opt_type": "C", "strike": 1700},
{"opt_type": "P", "strike": 1900},
index_px=1800,
)
self.assertIsNotNone(err)
self.assertIn("实值", err)
self.assertIsNone(
validate_oo_legs_moneyness(
{"opt_type": "C", "strike": 1850},
{"opt_type": "P", "strike": 1750},
index_px=1800,
)
)
def test_pick_itm_or_atm(self):
contracts = [
{"inst_id": "E-C-3600", "opt_type": "C", "strike": 3600},
{"inst_id": "E-C-3500", "opt_type": "C", "strike": 3500},
{"inst_id": "E-C-3400", "opt_type": "C", "strike": 3400},
]
picked = pick_itm_or_atm_contract(
contracts, opt_type="C", index_px=3510, itm_max_dist=200
)
self.assertIsNotNone(picked)
self.assertEqual(picked["strike"], 3500)
def test_recommend_oo(self):
contracts = [
{"inst_id": "E-C-1800", "opt_type": "C", "strike": 1800},
{"inst_id": "E-P-1800", "opt_type": "P", "strike": 1800},
{"inst_id": "E-C-1900", "opt_type": "C", "strike": 1900},
{"inst_id": "E-P-1700", "opt_type": "P", "strike": 1700},
]
pair = recommend_oo_legs(contracts, index_px=1800, template="atm_straddle")
self.assertIsNotNone(pair)
self.assertEqual(pair[0]["opt_type"], "C")
self.assertEqual(pair[1]["opt_type"], "P")
def test_validate_start_body_po_otm(self):
err = validate_start_body(
"perp_options",
{
"direction": "long",
"entry": 1800,
"tp": 1900,
"sl": 1700,
"contracts": 1,
"opt_inst_id": "ETH-USD-260731-1700-P",
"opt_type": "P",
"strike": 1700,
"index_px": 1800,
"sheets": 1,
"exchange_symbol": "ETH/USDT:USDT",
},
)
self.assertIsNotNone(err)
self.assertIn("虚值", err)
def test_validate_start_body_oo_itm(self):
err = validate_start_body(
"options_options",
{
"profit_rr": 2,
"index_px": 1800,
"leg_a": {"inst_id": "ETH-USD-260731-1700-C", "opt_type": "C", "strike": 1700},
"leg_b": {"inst_id": "ETH-USD-260731-1900-P", "opt_type": "P", "strike": 1900},
},
)
self.assertIsNotNone(err)
self.assertIn("实值", err)
if __name__ == "__main__":
unittest.main()