Add GLD vs gold futures basis research for dashboard implementation
This commit is contained in:
170
docs/GLD_BASIS_RESEARCH.md
Normal file
170
docs/GLD_BASIS_RESEARCH.md
Normal file
@@ -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"
|
||||
Reference in New Issue
Block a user