feat(PRICING-003): use true GLD backing for hedge contract count

This commit is contained in:
Bu5hm4nn
2026-03-28 09:18:26 +01:00
parent 894d88f72f
commit 966cee7963
4 changed files with 176 additions and 20 deletions

View File

@@ -1,5 +1,6 @@
from __future__ import annotations
import math
from dataclasses import dataclass
from datetime import date, timedelta
@@ -7,6 +8,7 @@ from app.core.pricing.black_scholes import (
BlackScholesInputs,
black_scholes_price_and_greeks,
)
from app.domain.instruments import gld_ounces_per_share
from app.models.option import Greeks, OptionContract
from app.models.strategy import HedgingStrategy
from app.strategies.base import BaseStrategy, StrategyConfig
@@ -47,7 +49,8 @@ class ProtectivePutStrategy(BaseStrategy):
@property
def hedge_units(self) -> float:
return self.config.portfolio.gold_value / self.config.spot_price
"""Gold ounces to hedge (canonical portfolio weight)."""
return self.config.portfolio.gold_ounces
@property
def strike(self) -> float:
@@ -57,6 +60,20 @@ class ProtectivePutStrategy(BaseStrategy):
def term_years(self) -> float:
return self.spec.months / 12.0
@property
def gld_backing(self) -> float:
"""GLD ounces per share for contract count calculation."""
return float(gld_ounces_per_share())
@property
def contract_count(self) -> int:
"""Number of GLD option contracts needed.
GLD options cover 100 shares each. Each share represents ~0.0919 oz
(expense-ratio adjusted). Formula: ceil(gold_ounces / (100 * backing)).
"""
return math.ceil(self.hedge_units / (100 * self.gld_backing))
def build_contract(self) -> OptionContract:
pricing = black_scholes_price_and_greeks(
BlackScholesInputs(
@@ -73,8 +90,8 @@ class ProtectivePutStrategy(BaseStrategy):
strike=self.strike,
expiry=date.today() + timedelta(days=max(1, round(365 * self.term_years))),
premium=pricing.price,
quantity=1.0,
contract_size=self.hedge_units,
quantity=float(self.contract_count),
contract_size=100 * self.gld_backing,
underlying_price=self.config.spot_price,
greeks=Greeks(
delta=pricing.delta,
@@ -114,7 +131,7 @@ class ProtectivePutStrategy(BaseStrategy):
payoff_at_threshold = contract.payoff(threshold_price)
hedged_value_at_threshold = self.config.portfolio.gold_value_at_price(threshold_price) + payoff_at_threshold
protected_ltv = self.config.portfolio.loan_amount / hedged_value_at_threshold
floor_value = contract.strike * self.hedge_units
floor_value = contract.strike * contract.notional_units
return {
"strategy": self.name,
"threshold_price": round(threshold_price, 2),