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
This commit is contained in:
95
app/strategies/lease.py
Normal file
95
app/strategies/lease.py
Normal file
@@ -0,0 +1,95 @@
|
||||
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
|
||||
Reference in New Issue
Block a user