c5d3d9d6c1
将上/下破目标价替换为盈亏比(盈利金额/初始权利金,默认2);残值平需买一流动性且权利金≤初始20%。 Co-authored-by: Cursor <cursoragent@cursor.com>
119 lines
4.3 KiB
Python
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()
|