feat: strategy builder
This commit is contained in:
@@ -43,7 +43,13 @@ class Surface:
|
||||
|
||||
|
||||
class ScenarioSurface:
|
||||
"""Shocked surface at the scenario horizon: parametric shifts + manual overrides."""
|
||||
"""Shocked surface at the scenario horizon: parametric shifts + manual overrides.
|
||||
|
||||
`iv_level_shift` is already the "parallel" component (applies to every strike/expiry
|
||||
uniformly) — `term_slope_shift` is the term-structure *slope* (zero at days=0, growing
|
||||
linearly per 30 days), so between the two the surface already has the "parallel vs.
|
||||
slope" split a term-structure model needs; a third "curvature" term is deliberately
|
||||
not modeled yet (see project memory: Strategy Builder Greeks plan, Phase 1)."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -51,14 +57,14 @@ class ScenarioSurface:
|
||||
scenario_spot: float,
|
||||
iv_level_shift: float,
|
||||
skew_tilt: float,
|
||||
term_shift: float,
|
||||
term_slope_shift: float,
|
||||
manual_overrides: Optional[Dict[Tuple[int, float], float]] = None,
|
||||
):
|
||||
self.base = base
|
||||
self.spot = scenario_spot
|
||||
self.iv_level_shift = iv_level_shift
|
||||
self.skew_tilt = skew_tilt
|
||||
self.term_shift = term_shift
|
||||
self.term_slope_shift = term_slope_shift
|
||||
self.manual_overrides = manual_overrides or {}
|
||||
|
||||
def iv_at(self, strike: float, days: float) -> float:
|
||||
@@ -71,7 +77,7 @@ class ScenarioSurface:
|
||||
base_iv
|
||||
+ self.iv_level_shift
|
||||
+ self.skew_tilt * moneyness
|
||||
+ self.term_shift * (days / 30.0)
|
||||
+ self.term_slope_shift * (days / 30.0)
|
||||
)
|
||||
return max(0.01, shocked)
|
||||
|
||||
@@ -137,7 +143,7 @@ def apply_scenario(
|
||||
spot_shock_pct: float = 0.0,
|
||||
iv_level_shift: float = 0.0,
|
||||
skew_tilt: float = 0.0,
|
||||
term_shift: float = 0.0,
|
||||
term_slope_shift: float = 0.0,
|
||||
manual_grid: Optional[List[Dict[str, Any]]] = None,
|
||||
) -> ScenarioSurface:
|
||||
"""
|
||||
@@ -149,4 +155,4 @@ def apply_scenario(
|
||||
for cell in (manual_grid or []):
|
||||
if cell.get("iv") is not None:
|
||||
overrides[(int(cell["days_to_expiry"]), float(cell["strike_pct"]))] = float(cell["iv"])
|
||||
return ScenarioSurface(surface, scenario_spot, iv_level_shift, skew_tilt, term_shift, overrides)
|
||||
return ScenarioSurface(surface, scenario_spot, iv_level_shift, skew_tilt, term_slope_shift, overrides)
|
||||
|
||||
Reference in New Issue
Block a user