feat(PRICING-001): add GLD expense ratio decay correction

This commit is contained in:
Bu5hm4nn
2026-03-28 09:04:35 +01:00
parent ff251b5ace
commit 894d88f72f
7 changed files with 208 additions and 26 deletions

View File

@@ -1,11 +1,49 @@
from __future__ import annotations
import math
from dataclasses import dataclass
from datetime import date
from decimal import Decimal
from app.domain.backtesting_math import AssetQuantity, PricePerAsset
from app.domain.units import BaseCurrency, PricePerWeight, Weight, WeightUnit
# GLD expense ratio decay parameters (from docs/GLD_BASIS_RESEARCH.md)
# Formula: ounces_per_share = 0.10 * e^(-0.004 * years_since_2004)
GLD_INITIAL_OUNCES_PER_SHARE = Decimal("0.10")
GLD_EXPENSE_DECAY_RATE = Decimal("0.004") # 0.4% annual decay
GLD_LAUNCH_YEAR = 2004
def gld_ounces_per_share(reference_date: date | None = None) -> Decimal:
"""
Calculate GLD's current gold backing per share based on expense ratio decay.
GLD's expense ratio (0.40% annually) causes the gold backing per share to
decay exponentially from the initial 0.10 oz/share at launch (2004).
Formula: ounces_per_share = 0.10 * e^(-0.004 * years_since_2004)
Args:
reference_date: Date to calculate backing for. Defaults to today.
Returns:
Decimal representing troy ounces of gold backing per GLD share.
Examples:
>>> # 2026 backing should be ~0.0919 oz/share (8.1% decay)
>>> from datetime import date
>>> result = gld_ounces_per_share(date(2026, 1, 1))
>>> float(result) # doctest: +SKIP
0.0919...
"""
if reference_date is None:
reference_date = date.today()
years_since_launch = Decimal(reference_date.year - GLD_LAUNCH_YEAR)
decay_factor = Decimal(str(math.exp(-float(GLD_EXPENSE_DECAY_RATE * years_since_launch))))
return GLD_INITIAL_OUNCES_PER_SHARE * decay_factor
@dataclass(frozen=True, slots=True)
class InstrumentMetadata:
@@ -64,7 +102,7 @@ class InstrumentMetadata:
_GLD = InstrumentMetadata(
symbol="GLD",
quote_currency=BaseCurrency.USD,
weight_per_share=Weight(amount=Decimal("0.1"), unit=WeightUnit.OUNCE_TROY),
weight_per_share=Weight(amount=gld_ounces_per_share(), unit=WeightUnit.OUNCE_TROY),
)
_INSTRUMENTS: dict[str, InstrumentMetadata] = {