feat: strategy builder

This commit is contained in:
OpenSquared
2026-07-30 13:28:03 +02:00
parent 1c4d8013c4
commit 81165581d7
8 changed files with 361 additions and 69 deletions

View File

@@ -56,7 +56,10 @@ def _settle_leg(leg: BacktestLeg, strike: float, days_to_expiry: int, near_days:
"""Value one leg at the near expiry: intrinsic if it expires there too (the common
case), else a fresh Black-Scholes price for its remaining time (a 'far' leg — closed
alongside the near leg rather than held to its own later expiry, the standard way
calendar/diagonal-style structures are actually managed)."""
calendar/diagonal-style structures are actually managed). A 'stock' leg (Covered
Call/Protective Put/Collar's underlying position) is worth exactly the spot, always."""
if leg.option_type == "stock":
return S_settle
remaining_days = days_to_expiry - near_days
if remaining_days <= 0:
if leg.option_type == "call":
@@ -70,7 +73,7 @@ def _settle_leg(leg: BacktestLeg, strike: float, days_to_expiry: int, near_days:
def run_backtest(req: BacktestRequest):
try:
for leg in req.legs:
if leg.option_type not in ("call", "put") or leg.position not in ("long", "short"):
if leg.option_type not in ("call", "put", "stock") or leg.position not in ("long", "short"):
return {"error": f"Jambe invalide: {leg}"}
ticker = yf.Ticker(req.symbol)
@@ -103,7 +106,7 @@ def run_backtest(req: BacktestRequest):
leg_days = [req.expiry_days if leg.expiry != "far" else req.far_expiry_days for leg in req.legs]
entry_premiums = [
float(black_scholes(S, k, d / 365, r, sigma, leg.option_type)["price"])
S if leg.option_type == "stock" else float(black_scholes(S, k, d / 365, r, sigma, leg.option_type)["price"])
for leg, k, d in zip(req.legs, leg_strikes, leg_days)
]