feat(hedge): option-primary watch entry with leverage gate
Start strategy arms a watching plan instead of opening immediately; list filters by leverage; type is a dropdown defaulting to OTM. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -9,9 +9,11 @@ from lib.hedge_plan.hedge_plan_option_primary_lib import (
|
||||
opt_type_for_view,
|
||||
option_bid_liquidity_ok,
|
||||
perp_direction_for_view,
|
||||
pick_option_primary_candidate,
|
||||
size_from_premium,
|
||||
target_hit,
|
||||
validate_option_primary_start,
|
||||
validate_option_primary_watch,
|
||||
)
|
||||
from lib.hedge_plan.hedge_plan_orders_lib import build_po_path_plan, validate_start_body
|
||||
|
||||
@@ -93,9 +95,25 @@ class TestOptionPrimary(unittest.TestCase):
|
||||
self.assertEqual(path[1]["direction"], "short")
|
||||
self.assertFalse(path[1]["attach_tpsl"])
|
||||
|
||||
def test_validate_option_primary_start(self):
|
||||
def test_validate_option_primary_watch_and_start(self):
|
||||
watch_body = {
|
||||
"option_primary": True,
|
||||
"watch_entry": 1,
|
||||
"direction": "long",
|
||||
"exchange_symbol": "ETH/USDT:USDT",
|
||||
"premium_budget": 100,
|
||||
"option_target_points": 50,
|
||||
"perp_target_points": 30,
|
||||
"option_perp_ratio": 4,
|
||||
"option_leverage": 200,
|
||||
"moneyness": "otm",
|
||||
}
|
||||
self.assertIsNone(validate_option_primary_watch(watch_body))
|
||||
self.assertIsNone(validate_start_body("perp_options", watch_body))
|
||||
|
||||
body = {
|
||||
"option_primary": True,
|
||||
"watch_entry": 0,
|
||||
"direction": "long",
|
||||
"contracts": 1,
|
||||
"opt_inst_id": "ETH-USD-260831-1900-C",
|
||||
@@ -120,6 +138,31 @@ class TestOptionPrimary(unittest.TestCase):
|
||||
bad = dict(body, opt_type="P")
|
||||
self.assertIsNotNone(validate_start_body("perp_options", bad))
|
||||
|
||||
def test_pick_candidate_respects_leverage(self):
|
||||
chain = {
|
||||
"index_px": 1900,
|
||||
"expiries": [
|
||||
{
|
||||
"exp_time": 9_999_999_999_999,
|
||||
"contracts": [
|
||||
{"inst_id": "LOW", "opt_type": "C", "strike": 1920, "ask": 20, "ct_mult": 0.01},
|
||||
{"inst_id": "OK", "opt_type": "C", "strike": 1925, "ask": 8, "ct_mult": 0.01},
|
||||
],
|
||||
}
|
||||
],
|
||||
}
|
||||
# 1900/20=95 < 200; 1900/8=237.5 ≥ 200
|
||||
picked = pick_option_primary_candidate(
|
||||
chain,
|
||||
direction="long",
|
||||
moneyness="otm",
|
||||
strike_interval=50,
|
||||
min_hours=1,
|
||||
min_opt_leverage=200,
|
||||
)
|
||||
self.assertIsNotNone(picked)
|
||||
self.assertEqual(picked["inst_id"], "OK")
|
||||
|
||||
def test_preview_builds_scenarios(self):
|
||||
body = {
|
||||
"direction": "long",
|
||||
|
||||
Reference in New Issue
Block a user