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

@@ -146,6 +146,38 @@ def chain(
raise HTTPException(status_code=404, detail=str(e))
@router.get("/presets")
def presets(
symbol: str = Query(...),
horizon_days: int = Query(8),
dte_min: Optional[int] = Query(None),
dte_max: Optional[int] = Query(None),
):
"""The full strategy catalog (services.backtest_strategies.STRATEGIES) built from the
REAL current chain instead of Backtest's synthetic grid — so a preset click here seeds
the leg editor with actually-quoted strikes/expiries, ready to price or replay as-is.
n_expiries=5 (vs. Strategy Builder's own default of 3) so calendar/diagonal presets,
which need two distinct expiries, reliably have a second one to draw from."""
from services.backtest_strategies import STRATEGIES, build_legs
try:
chain_slice = get_chain_slice(symbol, horizon_days, 5, dte_min=dte_min, dte_max=dte_max)
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
expiries = chain_slice["expiries"]
if not expiries:
raise HTTPException(status_code=404, detail=f"Aucune échéance exploitable pour '{symbol}'.")
near, far = expiries[0], expiries[1] if len(expiries) > 1 else None
out = []
for key, label, n_legs in STRATEGIES:
legs = build_legs(key, chain_slice["spot"], 0.05, near, far)
if not legs:
continue # e.g. calendar/diagonal with only one real expiry available right now
out.append({"key": key, "label": label, "n_legs": n_legs, "legs": legs})
return out
@router.post("/price")
def price(req: PriceRequest):
if not req.legs: