diff --git a/docs/GLD_BASIS_RESEARCH.md b/docs/GLD_BASIS_RESEARCH.md new file mode 100644 index 0000000..3c98f69 --- /dev/null +++ b/docs/GLD_BASIS_RESEARCH.md @@ -0,0 +1,170 @@ +# GLD ETF vs Gold Futures Basis: Implementation Guide + +## Executive Summary + +GLD (SPDR Gold Shares ETF) does **not** track gold at a simple 10:1 ratio. Two mechanical factors affect the conversion between GLD and physical gold/futures. + +## Key Findings for Dashboard Implementation + +### 1. Expense Ratio Decay (Permanent, Predictable) + +| Metric | Launch (2004) | Current (2026) | +|--------|----------------|-----------------| +| Gold per share | 0.1000 oz | ~0.0919 oz | +| Effective ratio | 10:1 | **10.9:1** | +| Cumulative decay | — | 8.1% | + +**Formula:** +``` +ounces_per_share = 0.10 * e^(-0.004 * years_since_2004) +``` + +**Dashboard Implementation:** +```python +# Current GLD backing (as of 2026) +GLD_OUNCES_PER_SHARE = 0.0919 + +def gld_price_to_gold_spot(gld_price: float) -> float: + """Convert GLD price to implied gold spot price.""" + return gld_price / GLD_OUNCES_PER_SHARE + +def gold_spot_to_gld_price(gold_spot: float) -> float: + """Convert gold spot price to GLD equivalent.""" + return gold_spot * GLD_OUNCES_PER_SHARE + +# Example: At $4,600/oz gold +# GLD ≈ $4,600 × 0.0919 ≈ $423 (NOT $460) +``` + +### 2. Futures-Spot Basis (Variable, Market-Dependent) + +| Market State | Futures vs. Spot | GLD vs. GC=F÷10 | +|--------------|------------------|-----------------| +| **Contango** (normal) | Futures > Spot by $10-15/oz | GLD appears at "discount" | +| **Backwardation** (stress) | Spot > Futures | GLD appears at "premium" | + +**During stress events:** +- March 2020 COVID: COMEX futures $50-70 above London spot +- GLD holders benefited (physical-backed) +- Futures traders suffered negative roll yield + +### 3. After-Hours Pricing Gap + +| Instrument | Trading Hours | +|------------|---------------| +| GLD | US market hours (9:30 AM - 4 PM ET) | +| GC=F (futures) | 23 hours/day, 6 days/week | + +**Implication:** GLD opens with gaps after weekend/overnight gold moves. Dashboard should show "last regular session close" vs. "current futures indication." + +## Dashboard Recommendations + +### Data Display + +```python +class GoldPriceDisplay: + """Recommended price display for vault-dash.""" + + def __init__(self, gld_price: float, gold_futures_price: float): + self.gld_price = gld_price + self.gold_futures_price = gold_futures_price + self.ounces_per_share = 0.0919 # Current GLD backing + + @property + def implied_spot_from_gld(self) -> float: + """Gold spot implied from GLD price.""" + return self.gld_price / self.ounces_per_share + + @property + def gld_fair_value(self) -> float: + """What GLD 'should' trade at based on futures.""" + # Adjust for contango (~$10/oz typically) + spot_estimate = self.gold_futures_price - 10 + return spot_estimate * self.ounces_per_share + + @property + def basis_bps(self) -> float: + """Basis between GLD and fair value in basis points.""" + diff_bps = (self.gld_price / self.gld_fair_value - 1) * 10000 + return diff_bps +``` + +### Warning Thresholds + +```python +# Raise warnings when basis exceeds normal bounds +BASIS_WARNING_THRESHOLD = 50 # 50 bps = 0.5% + +if abs(basis_bps) > BASIS_WARNING_THRESHOLD: + # GLD trading at unusual premium/discount + # Possible causes: after-hours gap, physical stress, AP arb failure + show_warning(f"GLD basis elevated: {basis_bps:.0f} bps") +``` + +### Options Pricing + +For Lombard hedge calculations: + +```python +def calculate_hedge_strikes( + portfolio_gold_ounces: float, + margin_call_price: float, + current_gold_spot: float +) -> dict: + """ + Calculate appropriate GLD option strikes for hedge. + + IMPORTANT: Use GLD price directly, not converted from futures. + """ + # Convert gold price thresholds to GLD strikes + gld_current = current_gold_spot * GLD_OUNCES_PER_SHARE + gld_margin_call = margin_call_price * GLD_OUNCES_PER_SHARE + + # Recommended strikes + atm_strike = round(gld_current) # e.g., $423 + otm_10_strike = round(gld_current * 0.90) # 10% OTM: ~$381 + otm_5_strike = round(gld_current * 0.95) # 5% OTM: ~$402 + + return { + "current_gld": gld_current, + "margin_call_gld": gld_margin_call, + "atm_strike": atm_strike, + "otm_5pct_strike": otm_5_strike, + "otm_10pct_strike": otm_10_strike, + "contracts_needed": math.ceil(portfolio_gold_ounces / (100 * GLD_OUNCES_PER_SHARE)) + } +``` + +## Data Sources + +| Data Point | Source | Notes | +|------------|--------|-------| +| GLD NAV/ounce | spdrgoldshares.com | Daily updated | +| GLD price | Market data API | Real-time | +| GC=F price | CME/futures API | Extended hours | +| Contango estimate | Futures curve | Calculate from term structure | + +## Key Takeaways for Vault-Dash + +1. **Never use a fixed 10:1 ratio** — always use current GLD backing (~0.092 oz/share) + +2. **Display both measures:** + - GLD implied spot = GLD ÷ 0.0919 + - GC=F adjusted = GC=F ÷ 10 (naive) for comparison + +3. **Show basis indicator:** + - Green: basis within ±25 bps (normal) + - Yellow: basis ±25-50 bps (elevated) + - Red: basis > 50 bps (unusual — possible stress) + +4. **For hedging:** + - Use GLD's actual price for strike selection + - Contract count = gold ounces ÷ (100 × 0.0919) + - Don't convert from GC=F to GLD — use GLD directly + +## References + +- SEC GLD Registration Statement (2004) +- SPDR Gold Shares: GLDM methodology updates +- CME Gold Futures specifications +- Research paper: "Optimal Hedging Strategies for Gold-Backed Lombard Loans" \ No newline at end of file