Files
vault-dash/app/strategies/lease.py
Bu5hm4nn 00a68bc767 Initial commit: Vault Dashboard for options hedging
- FastAPI + NiceGUI web application
- QuantLib-based Black-Scholes pricing with Greeks
- Protective put, laddered, and LEAPS strategies
- Real-time WebSocket updates
- TradingView-style charts via Lightweight-Charts
- Docker containerization
- GitLab CI/CD pipeline for VPS deployment
- VPN-only access configuration
2026-03-21 19:21:40 +01:00

96 lines
3.5 KiB
Python

from __future__ import annotations
from dataclasses import dataclass
from app.strategies.base import BaseStrategy, StrategyConfig
from app.strategies.protective_put import ProtectivePutSpec, ProtectivePutStrategy
@dataclass(frozen=True)
class LeaseAnalysisSpec:
strike_pct: float = 1.0
durations_months: tuple[int, ...] = (3, 6, 12, 18, 24)
class LeaseStrategy(BaseStrategy):
"""LEAPS duration analysis with roll timing and annualized cost comparison."""
def __init__(self, config: StrategyConfig, spec: LeaseAnalysisSpec | None = None) -> None:
super().__init__(config)
self.spec = spec or LeaseAnalysisSpec()
@property
def name(self) -> str:
return "lease_duration_analysis"
def _protective_put(self, months: int) -> ProtectivePutStrategy:
return ProtectivePutStrategy(
self.config,
ProtectivePutSpec(label=f"LEAPS_{months}M", strike_pct=self.spec.strike_pct, months=months),
)
def _duration_rows(self) -> list[dict]:
rows: list[dict] = []
for months in self.spec.durations_months:
strategy = self._protective_put(months)
cost = strategy.calculate_cost()
rolls_per_year = 12 / months
rows.append(
{
"months": months,
"strike": cost["strike"],
"premium_per_share": cost["premium_per_share"],
"total_cost": cost["total_cost"],
"annualized_cost": cost["annualized_cost"],
"annualized_cost_pct": cost["annualized_cost_pct"],
"rolls_per_year": round(rolls_per_year, 4),
"recommended_roll_month": max(1, months - 1),
}
)
return rows
def calculate_cost(self) -> dict:
rows = self._duration_rows()
optimal = min(rows, key=lambda item: item["annualized_cost"])
return {
"strategy": self.name,
"comparison": rows,
"optimal_duration_months": optimal["months"],
"lowest_annual_cost": optimal["annualized_cost"],
"lowest_annual_cost_pct": optimal["annualized_cost_pct"],
}
def calculate_protection(self) -> dict:
threshold_price = self.config.portfolio.margin_call_price()
rows: list[dict] = []
for months in self.spec.durations_months:
strategy = self._protective_put(months)
protection = strategy.calculate_protection()
rows.append(
{
"months": months,
"payoff_at_threshold": protection["payoff_at_threshold"],
"hedged_ltv_at_threshold": protection["hedged_ltv_at_threshold"],
"maintains_margin_call_buffer": protection["maintains_margin_call_buffer"],
}
)
return {
"strategy": self.name,
"threshold_price": round(threshold_price, 2),
"durations": rows,
}
def get_scenarios(self) -> list[dict]:
scenarios: list[dict] = []
for months in self.spec.durations_months:
strategy = self._protective_put(months)
scenarios.append(
{
"months": months,
"annualized_cost": strategy.calculate_cost()["annualized_cost"],
"annualized_cost_pct": strategy.calculate_cost()["annualized_cost_pct"],
"sample_scenarios": strategy.get_scenarios(),
}
)
return scenarios