feat(CONV-001): add GLD launch date validation, feat(DATA-DB-003): add cache CLI
CONV-001: - Add GLD_LAUNCH_DATE constant (November 18, 2004) - Validate reference_date in gld_ounces_per_share() - Raise ValueError for dates before GLD launch - Update docstring with valid date range - Add comprehensive test coverage for edge cases DATA-DB-003: - Create scripts/cache_cli.py with three commands: - vault-dash cache stats: Show cache statistics - vault-dash cache list: List cached entries - vault-dash cache clear: Clear all cache files - Add Makefile targets: cache-stats, cache-list, cache-clear - Integrate with DatabentoHistoricalPriceSource methods
This commit is contained in:
@@ -36,6 +36,7 @@ class Underlying(str, Enum):
|
||||
GLD_INITIAL_OUNCES_PER_SHARE = Decimal("0.10")
|
||||
GLD_EXPENSE_DECAY_RATE = Decimal("0.004") # 0.4% annual decay
|
||||
GLD_LAUNCH_YEAR = 2004
|
||||
GLD_LAUNCH_DATE = date(2004, 11, 18) # GLD IPO date on NYSE
|
||||
|
||||
# GC=F contract specifications
|
||||
GC_F_OUNCES_PER_CONTRACT = Decimal("100") # 100 troy oz per contract
|
||||
@@ -44,29 +45,41 @@ GC_F_QUOTE_CURRENCY = BaseCurrency.USD
|
||||
|
||||
def gld_ounces_per_share(reference_date: date | None = None) -> Decimal:
|
||||
"""
|
||||
Calculate GLD's current gold backing per share based on expense ratio decay.
|
||||
Calculate GLD's gold backing per share for a specific date.
|
||||
|
||||
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).
|
||||
decay exponentially from the initial 0.10 oz/share at launch (November 18, 2004).
|
||||
|
||||
Formula: ounces_per_share = 0.10 * e^(-0.004 * years_since_2004)
|
||||
|
||||
Args:
|
||||
reference_date: Date to calculate backing for. Defaults to today.
|
||||
reference_date: Date to calculate backing for. Must be on or after
|
||||
GLD launch date (2004-11-18). Defaults to today.
|
||||
|
||||
Returns:
|
||||
Decimal representing troy ounces of gold backing per GLD share.
|
||||
|
||||
Raises:
|
||||
ValueError: If reference_date is before GLD launch (2004-11-18).
|
||||
|
||||
Examples:
|
||||
>>> # 2026 backing should be ~0.0919 oz/share (8.1% decay)
|
||||
>>> from datetime import date
|
||||
>>> # Launch date returns initial 0.10 oz/share
|
||||
>>> gld_ounces_per_share(date(2004, 11, 18))
|
||||
Decimal('0.10')
|
||||
>>> # 2026 backing should be ~0.0916 oz/share (8.4% decay)
|
||||
>>> result = gld_ounces_per_share(date(2026, 1, 1))
|
||||
>>> float(result) # doctest: +SKIP
|
||||
0.0919...
|
||||
0.0916...
|
||||
"""
|
||||
if reference_date is None:
|
||||
reference_date = date.today()
|
||||
|
||||
if reference_date < GLD_LAUNCH_DATE:
|
||||
raise ValueError(
|
||||
f"GLD backing data unavailable before {GLD_LAUNCH_DATE}. " f"GLD launched on November 18, 2004."
|
||||
)
|
||||
|
||||
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
|
||||
|
||||
@@ -315,11 +315,13 @@ class BacktestPageService:
|
||||
source_info = self.DATA_SOURCE_INFO.get(data_source, self.DATA_SOURCE_INFO["synthetic"])
|
||||
|
||||
# Use the injected provider's identity if available (for custom providers in tests)
|
||||
if hasattr(self.backtest_service, 'provider'):
|
||||
injected_provider_id = getattr(self.backtest_service.provider, 'provider_id', None)
|
||||
injected_pricing_mode = getattr(self.backtest_service.provider, 'pricing_mode', None)
|
||||
if hasattr(self.backtest_service, "provider"):
|
||||
injected_provider_id = getattr(self.backtest_service.provider, "provider_id", None)
|
||||
injected_pricing_mode = getattr(self.backtest_service.provider, "pricing_mode", None)
|
||||
# Only use injected identity if it differs from known providers
|
||||
if injected_provider_id and injected_provider_id not in [info.provider_id for info in self.DATA_SOURCE_INFO.values()]:
|
||||
if injected_provider_id and injected_provider_id not in [
|
||||
info.provider_id for info in self.DATA_SOURCE_INFO.values()
|
||||
]:
|
||||
provider_id = injected_provider_id
|
||||
pricing_mode = injected_pricing_mode or source_info.pricing_mode
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user