情景测算按到期实值反推盈亏比达标现货价
达标情景现货价按权利金价值与行权价反推,便于对照到期后效果。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -58,6 +58,42 @@ def option_expiry_pnl(
|
|||||||
return value - float(premium_paid)
|
return value - float(premium_paid)
|
||||||
|
|
||||||
|
|
||||||
|
def spot_from_expiry_intrinsic_profit(
|
||||||
|
*,
|
||||||
|
opt_type: str,
|
||||||
|
strike: float,
|
||||||
|
sheets: float,
|
||||||
|
ct_mult: float,
|
||||||
|
premium_paid: float,
|
||||||
|
profit: float,
|
||||||
|
) -> float | None:
|
||||||
|
"""按到期实值反推现货价:使该腿到期盈亏 ≈ profit.
|
||||||
|
|
||||||
|
到期价值=实值×张数×乘数;盈亏=价值−权利金 → 实值/币=(profit+权利金)/(张数×乘数).
|
||||||
|
Call: spot=K+实值/币; Put: spot=K−实值/币.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
k = float(strike)
|
||||||
|
n = float(sheets or 0)
|
||||||
|
ct = float(ct_mult or 0.01)
|
||||||
|
prem = float(premium_paid or 0)
|
||||||
|
pnl = float(profit)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return None
|
||||||
|
denom = n * ct
|
||||||
|
if denom <= 0:
|
||||||
|
return None
|
||||||
|
need = (pnl + prem) / denom
|
||||||
|
if need < 0:
|
||||||
|
need = 0.0
|
||||||
|
o = (opt_type or "").strip().upper()
|
||||||
|
if o in ("C", "CALL"):
|
||||||
|
return round(k + need, 2)
|
||||||
|
if o in ("P", "PUT"):
|
||||||
|
return round(k - need, 2)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def suggest_contracts_from_notional(
|
def suggest_contracts_from_notional(
|
||||||
*,
|
*,
|
||||||
notional: float,
|
notional: float,
|
||||||
@@ -484,6 +520,23 @@ def build_options_options_preview(
|
|||||||
a_at_b_full = -prem_a
|
a_at_b_full = -prem_a
|
||||||
a_at_b_res = -prem_a * 0.8
|
a_at_b_res = -prem_a * 0.8
|
||||||
|
|
||||||
|
spot_a = spot_from_expiry_intrinsic_profit(
|
||||||
|
opt_type=str(leg_a.get("opt_type") or ""),
|
||||||
|
strike=float(leg_a["strike"]),
|
||||||
|
sheets=float(leg_a.get("sheets") or 0),
|
||||||
|
ct_mult=float(leg_a.get("ct_mult") or 0.01),
|
||||||
|
premium_paid=prem_a,
|
||||||
|
profit=win_profit,
|
||||||
|
)
|
||||||
|
spot_b = spot_from_expiry_intrinsic_profit(
|
||||||
|
opt_type=str(leg_b.get("opt_type") or ""),
|
||||||
|
strike=float(leg_b["strike"]),
|
||||||
|
sheets=float(leg_b.get("sheets") or 0),
|
||||||
|
ct_mult=float(leg_b.get("ct_mult") or 0.01),
|
||||||
|
premium_paid=prem_b,
|
||||||
|
profit=win_profit,
|
||||||
|
)
|
||||||
|
|
||||||
a_flat = _leg_pnl(leg_a, index_px)
|
a_flat = _leg_pnl(leg_a, index_px)
|
||||||
b_flat = _leg_pnl(leg_b, index_px)
|
b_flat = _leg_pnl(leg_b, index_px)
|
||||||
flat_total = a_flat + b_flat
|
flat_total = a_flat + b_flat
|
||||||
@@ -502,29 +555,29 @@ def build_options_options_preview(
|
|||||||
{
|
{
|
||||||
"id": "rr_leg_a_full",
|
"id": "rr_leg_a_full",
|
||||||
"label": f"腿A达盈亏比{rr:g}(亏腿全损)",
|
"label": f"腿A达盈亏比{rr:g}(亏腿全损)",
|
||||||
"spot": None,
|
"spot": spot_a,
|
||||||
"leg_a_pnl": round(a_at_a, 4),
|
"leg_a_pnl": round(a_at_a, 4),
|
||||||
"leg_b_pnl": round(b_at_a_full, 4),
|
"leg_b_pnl": round(b_at_a_full, 4),
|
||||||
"total": round(a_at_a + b_at_a_full, 4),
|
"total": round(a_at_a + b_at_a_full, 4),
|
||||||
"note": "盈利=总权利金×盈亏比;亏损腿本合约全亏",
|
"note": "现货=到期实值反推;盈利=总权利金×盈亏比;亏腿本合约全亏",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "rr_leg_b_full",
|
"id": "rr_leg_b_full",
|
||||||
"label": f"腿B达盈亏比{rr:g}(亏腿全损)",
|
"label": f"腿B达盈亏比{rr:g}(亏腿全损)",
|
||||||
"spot": None,
|
"spot": spot_b,
|
||||||
"leg_a_pnl": round(a_at_b_full, 4),
|
"leg_a_pnl": round(a_at_b_full, 4),
|
||||||
"leg_b_pnl": round(b_at_b, 4),
|
"leg_b_pnl": round(b_at_b, 4),
|
||||||
"total": round(a_at_b_full + b_at_b, 4),
|
"total": round(a_at_b_full + b_at_b, 4),
|
||||||
"note": "盈利=总权利金×盈亏比;亏损腿本合约全亏",
|
"note": "现货=到期实值反推;盈利=总权利金×盈亏比;亏腿本合约全亏",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "rr_leg_a_residual",
|
"id": "rr_leg_a_residual",
|
||||||
"label": f"腿A达盈亏比{rr:g}(亏腿残值20%)",
|
"label": f"腿A达盈亏比{rr:g}(亏腿残值20%)",
|
||||||
"spot": None,
|
"spot": spot_a,
|
||||||
"leg_a_pnl": round(a_at_a, 4),
|
"leg_a_pnl": round(a_at_a, 4),
|
||||||
"leg_b_pnl": round(b_at_a_res, 4),
|
"leg_b_pnl": round(b_at_a_res, 4),
|
||||||
"total": round(a_at_a + b_at_a_res, 4),
|
"total": round(a_at_a + b_at_a_res, 4),
|
||||||
"note": "亏损腿买一回收约本合约权利金20%",
|
"note": "现货同腿A达标反推;亏腿买一回收约本合约权利金20%",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "expiry_flat",
|
"id": "expiry_flat",
|
||||||
@@ -547,6 +600,8 @@ def build_options_options_preview(
|
|||||||
],
|
],
|
||||||
"summary": {
|
"summary": {
|
||||||
"profit_rr": rr,
|
"profit_rr": rr,
|
||||||
|
"spot_at_rr_a": spot_a,
|
||||||
|
"spot_at_rr_b": spot_b,
|
||||||
"at_rr_a_full_total": round(a_at_a + b_at_a_full, 4),
|
"at_rr_a_full_total": round(a_at_a + b_at_a_full, 4),
|
||||||
"at_rr_b_full_total": round(a_at_b_full + b_at_b, 4),
|
"at_rr_b_full_total": round(a_at_b_full + b_at_b, 4),
|
||||||
"at_rr_a_residual_total": round(a_at_a + b_at_a_res, 4),
|
"at_rr_a_residual_total": round(a_at_a + b_at_a_res, 4),
|
||||||
|
|||||||
@@ -114,6 +114,11 @@ class TestHedgePlanCalc(unittest.TestCase):
|
|||||||
self.assertEqual(len(p["scenarios"]), 5)
|
self.assertEqual(len(p["scenarios"]), 5)
|
||||||
self.assertEqual(p["scenarios"][0]["id"], "rr_leg_a_full")
|
self.assertEqual(p["scenarios"][0]["id"], "rr_leg_a_full")
|
||||||
self.assertEqual(p["scenarios"][1]["id"], "rr_leg_b_full")
|
self.assertEqual(p["scenarios"][1]["id"], "rr_leg_b_full")
|
||||||
|
# 到期实值反推:Call 盈利20 → 价值25 → 每币2500 → spot=3300+2500
|
||||||
|
self.assertEqual(p["scenarios"][0]["spot"], 5800.0)
|
||||||
|
# Put 盈利20 → spot=3100-2500
|
||||||
|
self.assertEqual(p["scenarios"][1]["spot"], 600.0)
|
||||||
|
self.assertEqual(p["scenarios"][2]["spot"], 5800.0) # 残值情景同腿A反推
|
||||||
|
|
||||||
def test_oo_legacy_single_target_still_works(self):
|
def test_oo_legacy_single_target_still_works(self):
|
||||||
a = {"opt_type": "C", "strike": 3300, "sheets": 1, "ct_mult": 0.01, "premium_paid": 5}
|
a = {"opt_type": "C", "strike": 3300, "sheets": 1, "ct_mult": 0.01, "premium_paid": 5}
|
||||||
|
|||||||
Reference in New Issue
Block a user