doc+tool: CAGR-maximizer reference plan + side-by-side strategy comparison
Honest reference plan (docs/.../2026-06-08-cagr-reference-plan.md): CAGR builds wealth not Sharpe; more CAGR always = more drawdown; only free CAGR is drag reduction; book's 0.96 Sharpe was an rf=0 artifact (excess-over-financing, equities win); leverage moat = cheap financing. Recommendation: max equity + low drag + contribute + never sell, optional 1.2-1.3x futures if you survive -65%. strategy_compare.py: re-runnable side-by-side (book / SPY 1x / SPY 1.3x / 60-40 / 70-30 / overlay) with backtest stats + the P0+PMT trajectory. Configurable --p0 --pmt --fin --years. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
86
docs/superpowers/specs/2026-06-08-cagr-reference-plan.md
Normal file
86
docs/superpowers/specs/2026-06-08-cagr-reference-plan.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# CAGR-Maximizer — Honest Reference Plan
|
||||
|
||||
**Date:** 2026-06-08
|
||||
**Purpose:** the honest answer to "how do we build the most wealth?" after exhaustively testing strategies,
|
||||
the adaptive multi-strat book, leverage, and risk-management. Comparison tool: `scripts/surfer/strategy_compare.py`.
|
||||
|
||||
---
|
||||
|
||||
## The core truth (measured, not assumed)
|
||||
|
||||
1. **CAGR builds terminal wealth, not Sharpe.** Over a long horizon with contributions, the highest-CAGR
|
||||
asset wins — even at lower Sharpe. (SPY 0.64 Sharpe but 12.4% CAGR beats the book's 0.96 Sharpe / 5.1% CAGR on money.)
|
||||
2. **More CAGR = more risk. Always. No exception.** Every risk-managed variant (the book, the overlay,
|
||||
blends) gives up CAGR for lower drawdown. Risk management is *insurance you pay for*, not a free improvement.
|
||||
3. **The only "free" CAGR is drag reduction** — taxes, fees, and (biggest) not selling at the bottom.
|
||||
4. **The book's apparent Sharpe edge (0.96 vs 0.64) was an rf=0 artifact.** Measured as excess-over-financing
|
||||
(what matters for leverage), equities (0.49) actually beat the diversified book (0.40) in this era —
|
||||
so levering the book does NOT beat buy-hold equity. The institutional risk-parity edge needs the book's
|
||||
*excess* Sharpe > equity's, which it wasn't.
|
||||
5. **The leverage moat is cheap financing.** Futures/box ≈ SOFR+spread (~3%); retail margin ~6.5% destroys it.
|
||||
|
||||
---
|
||||
|
||||
## The candidates (measured 2006–2026, incl. 2008 −55%)
|
||||
|
||||
| Strategy | CAGR | vol | Sharpe | maxDD | $360k+$8k/mo → 20y |
|
||||
|---|---|---|---|---|---|
|
||||
| **SPY buy-hold (1.0x)** | ~10.6% | 19% | 0.64 | **−55%** | ~$7.8M |
|
||||
| SPY 1.2–1.3x (cheap futures) | ~12–13% | 23–25% | ~0.6 | **−63 to −67%** | ~$8.8–9.2M |
|
||||
| SPY 1.5x | ~14.5% | 28% | — | −73% | ~$10.1M |
|
||||
| 60/40 | ~8% | 14% | 0.73 | −20 to −30% | ~$6.5M |
|
||||
| 70/30 SPY+book | ~10% | 14% | 0.73 | −40% | ~$9.0M |
|
||||
| SPY + adaptive overlay | ~8% | 11% | 0.77 | −18% | ~$6.7M |
|
||||
| **Adaptive multi-strat book** | ~5–6% | 5% | **0.96** | **−10%** | ~$4.3–4.9M |
|
||||
|
||||
(SPY ≥2x: CAGR peaks ~2x then volatility-drag falls; −84%+ drawdown = ruin/margin-call territory. Not viable.)
|
||||
|
||||
---
|
||||
|
||||
## CAGR levers, ranked by sense
|
||||
|
||||
| Lever | Effect | Honesty |
|
||||
|---|---|---|
|
||||
| **Max equity allocation, held** | base ~10–11%/yr | highest-return asset; reliable |
|
||||
| **Reduce drag** (tax-advantaged account, cheap index funds, never sell, stay invested) | **+1–3%/yr** | **free + reliable — most people leave this on the table** |
|
||||
| **Time + contributions ($8k/mo)** | dominant terminal driver | your strongest card |
|
||||
| **Modest cheap leverage (~1.2–1.3x via futures)** | +~1.5–2%/yr (+$1–1.4M/20y) | amplifies drawdown to −63–67% + margin-call risk |
|
||||
| Factor tilts (small-cap value, momentum, quality) | hist. +1–2%/yr | less reliable forward |
|
||||
| ~~Risk-managed book / overlay~~ | **−4%/yr CAGR** | a risk *reducer*, not a CAGR maximizer |
|
||||
|
||||
---
|
||||
|
||||
## The leverage reality (the only knob with real upside — handle with care)
|
||||
|
||||
- 1.2–1.3x boosts CAGR ~+1.5–2%/yr (~$1–1.4M over 20y) but turns the −55% crash into **−63–67%**.
|
||||
- **−67% on a $2M pot = $660k at the 2009 bottom**, while still contributing into the abyss.
|
||||
- **Margin calls:** fixed-notional futures in a −55% crash force liquidation at the bottom → *realized* ruin
|
||||
(the backtest "survives" only because it's daily-rebalanced math). Lived experience is worse than backtest.
|
||||
- Above ~1.5x: reckless (−73%+); above ~2x: ruin.
|
||||
- **The real constraint is not the math — it's whether you survive a −65% drawdown + margin without forced/panic selling.**
|
||||
|
||||
---
|
||||
|
||||
## Recommendation
|
||||
|
||||
For a disciplined accumulator with a strong savings rate (~$8k/mo), long horizon, and stable income:
|
||||
|
||||
1. **Max equity (100%), in a tax-advantaged account, cheap index funds, contribute monthly, never sell.**
|
||||
Base case ~$7.8M over 20y. Simple, cheap, the most for the disciplined.
|
||||
2. **Optional ~1.2–1.3x via futures (cheap financing)** — only if you can survive (financially + emotionally)
|
||||
a −65% drawdown + margin calls without forced selling. Adds ~$1–1.4M over 20y.
|
||||
3. **Always: reduce drag** (tax-efficiency, low fees, stay invested) — the free CAGR.
|
||||
4. **The adaptive multi-strat book is NOT the wealth-maximizer** — it's the *capital-preservation / low-stress / withdrawal-phase* tool. Use it if you'd panic-sell equities, are near withdrawal, or value sleep over ~4%/yr.
|
||||
|
||||
**The decision hinges on one honest question: do you sell at the bottom of a crash, or hold?**
|
||||
- Hold → high equity (±1.3x), simplest, most money.
|
||||
- Unsure → 70/30 or the overlay (pay return for a tolerable ride).
|
||||
- Need capital preservation → the book.
|
||||
|
||||
---
|
||||
|
||||
## What's deployed
|
||||
|
||||
- **Adaptive multi-strat book:** live on IBKR paper via the K8s CronJob (autonomous, daily eval) — the *low-drawdown* reference.
|
||||
- **Comparison tool:** `scripts/surfer/strategy_compare.py` — re-runnable side-by-side of all candidates (backtest + trajectory).
|
||||
- **Honest bottom line:** there is no secret signal and no clever leverage trick that beats "high-return assets, cheap, held long, funded heavily." We tested them all. The wealth levers are savings rate, time, low costs, and the discipline to not sell.
|
||||
98
scripts/surfer/strategy_compare.py
Normal file
98
scripts/surfer/strategy_compare.py
Normal file
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Side-by-side comparison of the wealth candidates (the CAGR reference plan, re-runnable).
|
||||
|
||||
Backtest (2006-2026, incl 2008) + the $360k+$8k/mo 20y trajectory for: adaptive multi-strat book,
|
||||
SPY buy-hold, SPY 1.3x (cheap futures financing), 60/40, 70/30 SPY+book, SPY+adaptive overlay.
|
||||
Honest: CAGR builds wealth; more CAGR = more drawdown. See docs/.../2026-06-08-cagr-reference-plan.md.
|
||||
|
||||
python3 strategy_compare.py # full table
|
||||
python3 strategy_compare.py --p0 100000 --pmt 2000 --fin 0.03 --years 20
|
||||
"""
|
||||
import datetime
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
import sys
|
||||
import urllib.request
|
||||
|
||||
import numpy as np
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
from multistrat_paper import book_series # noqa: E402
|
||||
|
||||
|
||||
def arg(flag, default, cast=float):
|
||||
return cast(sys.argv[sys.argv.index(flag) + 1]) if flag in sys.argv else default
|
||||
|
||||
|
||||
def yh(s):
|
||||
r = json.loads(urllib.request.urlopen(urllib.request.Request(
|
||||
f"https://query1.finance.yahoo.com/v8/finance/chart/{s}?interval=1d&range=25y",
|
||||
headers={"User-Agent": "Mozilla/5.0"}), timeout=30).read())["chart"]["result"][0]
|
||||
a = r["indicators"].get("adjclose", [{}])[0].get("adjclose") or r["indicators"]["quote"][0]["close"]
|
||||
ts = r["timestamp"]
|
||||
return {datetime.datetime.utcfromtimestamp(t).strftime("%Y-%m-%d"): float(c) for t, c in zip(ts, a) if c is not None}
|
||||
|
||||
|
||||
def stats(r):
|
||||
r = np.nan_to_num(r)
|
||||
eq = np.cumprod(1 + r); cagr = eq[-1] ** (252 / len(r)) - 1
|
||||
vol = r.std() * math.sqrt(252)
|
||||
dd = float((eq / np.maximum.accumulate(eq) - 1).min())
|
||||
rf = 0.03; sharpe = (r.mean() * 252 - rf) / vol if vol > 0 else 0 # excess-over-financing Sharpe
|
||||
return cagr, vol, sharpe, dd
|
||||
|
||||
|
||||
def main():
|
||||
P0 = arg("--p0", 360000.0); PMT = arg("--pmt", 8000.0); FIN = arg("--fin", 0.03); YEARS = int(arg("--years", 20))
|
||||
syms = ["SPY", "IEF", "GLD", "DBC"]
|
||||
data = {s: yh(s) for s in syms}
|
||||
dates = sorted(set.intersection(*[set(d) for d in data.values()]))
|
||||
T = len(dates)
|
||||
Pm = np.column_stack([np.array([data[s][d] for d in dates]) for s in syms])
|
||||
R = np.zeros((T, 4)); R[1:] = Pm[1:] / Pm[:-1] - 1
|
||||
spy, ief = R[:, 0], R[:, 1]
|
||||
|
||||
# multi-strat book (proxy: SPY/IEF/GLD/DBC + DIY trend sleeve)
|
||||
lc = np.log(Pm); sg = np.zeros((T, 4)); sg[252:] = np.sign(lc[252:] - lc[:-252])
|
||||
vol = np.full((T, 4), np.nan)
|
||||
for t in range(63, T):
|
||||
vol[t] = R[t - 63:t].std(0)
|
||||
iv = 1 / np.where(vol > 0, vol, np.nan); w = np.nan_to_num(sg * iv)
|
||||
g = np.abs(w).sum(1, keepdims=True); g[g == 0] = 1; w = w / g
|
||||
trend = np.zeros(T); trend[1:] = np.sum(w[:-1] * R[1:], axis=1)
|
||||
book, _, _ = book_series(np.column_stack([R, trend]))
|
||||
|
||||
# SPY + adaptive overlay (vol-target 15% + 200d trend + drawdown de-lever)
|
||||
lp = np.log(Pm[:, 0]); ma = np.array([lp[max(0, t - 200):t].mean() if t >= 200 else lp[t] for t in range(T)])
|
||||
ovr = np.zeros(T); eqo = pk = 1.0
|
||||
for t in range(63, T - 1):
|
||||
rv = spy[t - 63:t].std() * math.sqrt(252); vs = min(1.0, 0.15 / (rv + 1e-9))
|
||||
tr = 1.0 if lp[t] > ma[t] else 0.3
|
||||
dd = eqo / pk - 1; dds = float(np.clip(1 + 3 * min(0, dd + 0.07), 0.4, 1.0))
|
||||
e = float(np.clip(vs * tr * dds, 0, 1.0)); ovr[t + 1] = e * spy[t + 1]; eqo *= (1 + ovr[t + 1]); pk = max(pk, eqo)
|
||||
|
||||
cands = {
|
||||
"SPY buy-hold (1.0x)": spy,
|
||||
"SPY 1.3x (cheap fin)": 1.3 * spy - 0.3 * FIN / 252,
|
||||
"60/40 (SPY/IEF)": 0.6 * spy + 0.4 * ief,
|
||||
"70/30 SPY+book": 0.7 * spy + 0.3 * book,
|
||||
"SPY+adaptive overlay": ovr,
|
||||
"adaptive multi-strat book": book,
|
||||
}
|
||||
|
||||
def fv(cagr):
|
||||
rm = cagr / 12; N = YEARS * 12; gg = (1 + rm) ** N
|
||||
return P0 * gg + PMT * ((gg - 1) / rm)
|
||||
|
||||
print(f"STRATEGY COMPARISON — {dates[0]}..{dates[-1]} | ${P0:,.0f} + ${PMT:,.0f}/mo, {YEARS}y, fin {100*FIN:.0f}%")
|
||||
print(f" {'strategy':>26} | CAGR | vol | Sharpe* | maxDD | {YEARS}y wealth")
|
||||
for nm, r in cands.items():
|
||||
c, v, sh, dd = stats(r)
|
||||
print(f" {nm:>26} | {100*c:>4.1f}% | {100*v:>3.0f}% | {sh:>+5.2f} | {100*dd:>+5.0f}% | ${fv(c):>13,.0f}")
|
||||
print(" *Sharpe = excess over financing (the leverage-relevant one). More CAGR ALWAYS = deeper maxDD.")
|
||||
print(" Reference plan: docs/superpowers/specs/2026-06-08-cagr-reference-plan.md")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user