sma200.trade
For informational and educational use only. Not investment advice. Past performance does not predict future returns. Read full disclaimer →
🟢 Research note · May 13, 2026 · Current

LETF Inception Backtest: Buy-and-Hold vs SMA200 Filter

Leveraged ETFs #sma200#tqqq#soxl#upro#drawdown

LETF Inception Backtest: Buy-and-Hold vs SMA200 Filter

Question

For SOXL, TQQQ, and UPRO, from each fund's actual inception through 2026-05-15: 1. What does pure buy-and-hold return? 2. What does a pure SMA200 trend filter (long when close > SMA200, cash otherwise) return?

How do they compare on CAGR, max drawdown, Sharpe, and the rest of the standard metric set?

Methodology

  • Harness: src/trader/backtest/engine.py
  • Strategy: src/trader/strategies/price_above_sma.py with window=200, long-only
  • Data: yfinance daily bars via src/trader/data/yfinance_src.py with auto_adjust=True (dividend-reinvested, split-adjusted total-return closes). This is the standard convention for backtest return computations and differs from the chart-standard convention used by sma200.trade itself.
  • Position sizing: 100% of stated notional when long, 100% cash when flat. No leverage beyond what the LETF provides.
  • Signal timing: Position lagged by one bar (pos.shift(1)), so a signal computed at today's close is applied to tomorrow's close-to-close return. No lookahead.
  • Reentry rule: Pure mechanical. The moment close > SMA200 condition flips true, position re-enters at next bar's close. No N-day confirmation, no buffer band, no anti-whipsaw block.
  • Transaction costs: 1 basis point per side (2bp per round-trip).
  • Risk-free rate: 0.0 for Sharpe and Sortino. Real risk-free over the window averaged ~1.5% annualized; applying a non-zero rf would lower both numerators by the same amount across both strategies without changing the ordering.
  • Tax treatment: None. All figures pre-tax. The SMA200 filter generates ~3 round-trips per year of short-term capital gains in taxable accounts.
  • SMA200 warmup: First 200 trading days have no SMA value. During this window the filter strategy is in cash by definition; buy-and-hold is fully invested from day one. This is the honest comparison: both strategies span the full life of the LETF.
  • Starting capital: $10,000.

Results

SOXL — Direxion Daily Semiconductor Bull 3X

Metric Buy-and-hold SMA200 filter
Inception 2010-03-11 2010-03-11
End date 2026-05-15 2026-05-15
Years 16.15 16.15
Final equity (from $10k) $2,732,125 $577,724
CAGR 41.52% 28.54%
Volatility (ann.) 89.27% 59.53%
Max drawdown -90.46% -69.68%
Sharpe (rf=0) 0.839 0.723
Sortino 1.182 0.794
Calmar 0.459 0.410
Round-trip trades 1 (held) 54
Trades per year 3.34
Round-trip win rate 20.37%
Time in market 100.0% 63.23%

Sharpe diff (filter − B&H): −0.116

TQQQ — ProShares UltraPro QQQ

Metric Buy-and-hold SMA200 filter
Inception 2010-02-11 2010-02-11
End date 2026-05-15 2026-05-15
Years 16.23 16.23
Final equity (from $10k) $3,655,934 $734,615
CAGR 43.85% 30.31%
Volatility (ann.) 60.96% 42.13%
Max drawdown -81.66% -50.03%
Sharpe (rf=0) 0.905 0.842
Sortino 1.165 0.923
Calmar 0.537 0.606
Round-trip trades 1 (held) 44
Trades per year 2.71
Round-trip win rate 31.82%
Time in market 100.0% 74.25%

Sharpe diff (filter − B&H): −0.063

UPRO — ProShares UltraPro S&P 500

Metric Buy-and-hold SMA200 filter
Inception 2009-06-25 2009-06-25
End date 2026-05-15 2026-05-15
Years 16.86 16.86
Final equity (from $10k) $1,233,859 $137,899
CAGR 33.06% 16.84%
Volatility (ann.) 51.27% 31.68%
Max drawdown -76.82% -56.66%
Sharpe (rf=0) 0.817 0.651
Sortino 1.009 0.706
Calmar 0.430 0.297
Round-trip trades 1 (held) 49
Trades per year 2.91
Round-trip win rate 24.49%
Time in market 100.0% 73.26%

Sharpe diff (filter − B&H): −0.166

Bonus: signal computed on the underlying ETF

For each LETF, the same SMA200 strategy but using the underlying's signal:

Strategy Final equity CAGR MDD Sharpe vs B&H vs direct
SOXL via SOXX SMA200 $372,705 25.10% -84.18% 0.674 -0.165 -0.049
TQQQ via QQQ SMA200 $1,019,548 32.97% -55.99% 0.849 -0.056 +0.007
UPRO via SPY SMA200 $428,603 24.97% -51.31% 0.801 -0.016 +0.150

UPRO via SPY meaningfully beats UPRO direct. TQQQ via QQQ is marginal. SOXL via SOXX is actively worse.

Interpretation

Over the full inception-to-2026 window for each LETF, pure SMA200 filtering underperforms buy-and-hold on Sharpe across all three:

  • SOXL: -0.116
  • TQQQ: -0.063
  • UPRO: -0.166

The filter wins meaningfully on max drawdown (TQQQ -82% → -50%, UPRO -77% → -57%, SOXL -90% → -70%) and on volatility, but at real cost in CAGR (-13 to -16 percentage points).

The case for the filter is behavioral, not mathematical. Backtests assume you hold through 90% drawdowns. Most humans don't. The filter trades CAGR for the ability to actually execute the strategy through a full cycle. See Article #1 on /learn for the full narrative.

Caveats

  1. Sample is biased. 2009-2026 contained one of the strongest equity bull runs in modern history with only two relatively V-shaped drawdowns (2020 COVID, 2022 rate shock). A different regime weighted toward extended bear markets (e.g., 2000-2012 NDX lost decade) would tilt this comparison meaningfully toward the filter. Confirmed by the synthetic TQQQ 1999 study (next file).

  2. The filter's 10-month cash warmup is included. Skipping the first 200 days (running both strategies from the first computable SMA value) would lift filter CAGR by 1.5-3 percentage points across these names without materially changing the Sharpe story.

  3. Liquidity of older bars. SOXL and TQQQ both had thin liquidity in 2010-2012. Real-world 2bp round-trip costs would have been conservative then; spreads may have been wider. We don't model time-varying costs.

  4. Pre-tax only. Filter generates ~3 short-term capital gains events per year. B&H generates zero until exit. After-tax results favor B&H by another margin in taxable accounts.

  5. Bonus underlying-SMA results assume frictionless cross-instrument execution (signal triggered by SPY close → UPRO position next day). Real implementation would have a tiny cross-symbol timing slip not modeled here.

Source

Saved output: /tmp/sma200_post2_data.md (this file is a clean rewrite of that snapshot).

Inline runner:

import sys
sys.path.insert(0, '/Volumes/Mac External/Claudes/trader/src')
from trader.data.yfinance_src import fetch_daily
from trader.backtest.engine import run_backtest
from trader.strategies.buy_and_hold import BuyAndHold
from trader.strategies.price_above_sma import PriceAboveSma

for letf in ["SOXL", "TQQQ", "UPRO"]:
    df = fetch_daily(letf)
    bh = run_backtest(f"{letf} B&H", df, BuyAndHold().generate_positions(df),
                      cost_bps=1.0, starting_equity=10_000.0)
    sma = run_backtest(f"{letf} SMA200", df, PriceAboveSma(window=200).generate_positions(df),
                       cost_bps=1.0, starting_equity=10_000.0)
    print(f"{letf}: BH Sharpe {bh.metrics['sharpe']:.3f}, SMA Sharpe {sma.metrics['sharpe']:.3f}")

This is research output, not investment advice. Backtest results do not predict future returns. Specific portfolio compositions discussed here are illustrative test cases, not allocation recommendations. Do your own research and consult a licensed advisor for personalized advice. Full disclaimer →