# Momentum Plus Strategy Backtest Report
Symbol: SPY (S&P 500 ETF)
Period: 2015-01-01 to 2025-12-01 (~11 years)
Run Date: 2025-12-06
---
## Executive Summary
Initial Capital: $10,000
Final Capital: $23,094.57
Total Return: +130.95%
CAGR: 8.82%
Sharpe Ratio: 0.715
Sortino Ratio: 0.950
Max Drawdown: 19.56%
Win Rate: 100% (5/5 trades)
Avg Holding Period: 595 days
---
## Strategy Logic
The momentum_plus strategy is an enhanced dual-timeframe momentum system:
### Entry Conditions (ALL must be true)
1. 12-month momentum > 0% — Long-term trend is up
2. 3-month momentum > 0% — Short-term confirmation
3. 20-day annualized volatility < 30% — Avoids choppy/crash markets
### Exit Conditions (ANY triggers exit)
1. 12-month momentum < -5% — Long-term trend broken
2. 3-month momentum < -10% AND 12-month momentum < 3% — Early warning crash signal
### Key Design Choices
- Asymmetric exits: Harder to exit than enter (reduces whipsaw)
- Vol filter on entry only: Lets winners run even in rising vol
- Dual timeframe confirmation: Requires both long and short term agreement
I tried symmetric entry/exit thresholds initially. Disaster — got chopped up in every sideways market. The asymmetry feels wrong intuitively but the numbers dont lie.
---
## Data Pipeline
### How Data Was Pulled
1. MCP Tool: run_backtest called with params:
symbol: "SPY", start: "2015-01-01", end: "2025-12-01", strategy: { type: "momentum_plus" }
2. Data Provider: YahooFinanceProvider (default)
Endpoint: getHistoricalOHLCV()
Interval: Daily (1d)
Fields: timestamp, open, high, low, close, volume
3. Data Flow:
Yahoo Finance API -> OHLCV array -> Candle[] conversion -> Backtest engine
### Provider Fallback Chain
If POLYGON_API_KEY environment variable is set:
Polygon.io (primary) -> Yahoo Finance (fallback)
Otherwise: Yahoo Finance only
---
## Trade-by-Trade Analysis
### Trade 1: Post-2015 Recovery Bull Run
Entry: 2016-04-01 @ $206.92
Exit: 2018-12-14 @ $260.47
Shares: 48
P&L: +$2,557.90 (+25.60%)
Holding: 987 days (2.7 years)
Context: Entered after the early 2016 correction stabilized. Strategy correctly identified the sustained bull market and held through minor corrections. Exited during Q4 2018 selloff when 3-month momentum crashed below -10%.
---
### Trade 2: 2019 Recovery into COVID
Entry: 2019-02-06 @ $272.74
Exit: 2020-03-09 @ $274.23
Shares: 45
P&L: +$54.71 (+0.44%)
Holding: 397 days
Context: Re-entered after December 2018 crash recovery. Held through 2019's strong year but got stopped out at the start of COVID crash (March 9, 2020 - just days before the bottom). Small profit but avoided the -34% COVID drawdown.
---
### Trade 3: COVID Recovery Bull Market
Entry: 2020-05-28 @ $302.97
Exit: 2022-05-09 @ $398.17
Shares: 41
P&L: +$3,886.88 (+30.90%)
Holding: 711 days
Context: Re-entered after vol normalized post-COVID crash (Fed intervention). Captured the massive 2020-2021 bull run. Exited in early May 2022 as the bear market began, avoiding the bulk of 2022's -20%+ drawdown.
---
### Trade 4: 2023 AI Rally
Entry: 2023-05-10 @ $412.85
Exit: 2025-04-04 @ $505.28
Shares: 39
P&L: +$3,585.06 (+21.80%)
Holding: 695 days
Context: Entered as the 2023 AI-driven rally gained momentum. Held through 2024. Exited in early April 2025 when momentum conditions reversed.
---
### Trade 5: 2025 Re-entry (Active)
Entry: 2025-05-29 @ $590.05
Exit: 2025-11-28 @ $683.39 (EOY)
Shares: 33
P&L: +$3,080.22 (+15.39%)
Holding: 183 days
Context: Re-entered late May 2025. Still holding at end of backtest period.
---
## Risk Analysis
### Drawdown Periods Avoided
1. Q4 2018 (-20%): Exited Dec 14, avoided worst
2. COVID 2020 (-34%): Exited Mar 9, avoided -28% of the drop
3. 2022 Bear (-25%): Exited May 9, missed most of the drawdown
the COVID exit timing was honestly lucky - strategy happened to trigger right before the bottom. Wouldnt count on that level of precision in the future
### Time Out of Market
- Total days: ~2,744 trading days
- Days in market: ~2,973 calendar days across 5 trades
- Days flat: Significant periods in 2018-2019, 2020, 2022-2023
### Max Drawdown Experienced
19.56% — This is the strategy's max DD, NOT SPY's. The strategy avoided the worst of SPY's drawdowns.
---
## Strategy Parameters
```typescript
createMomentumPlusSignal(
longLookback: 252, // 12-month momentum lookback
shortLookback: 63, // 3-month momentum lookback
entryThreshold: 0, // min momentum to enter (0%)
exitThreshold: -0.05, // exit if 12mo < -5%
shortExitThreshold: -0.10, // exit if 3mo < -10%
maxVolThreshold: 0.30 // don't enter if vol > 30%
)
```
---
## Code Reference
Strategy implementation: packages/quant-core/src/backtest.ts lines 292-349
```typescript
// Entry logic
if (currentPosition === "flat") {
if (longMomentum > entryThreshold &&
shortMomentum > entryThreshold &&
annualizedVol < maxVolThreshold) {
return "long";
}
}
// Exit logic
if (currentPosition === "long") {
if (longMomentum < exitThreshold) return "flat";
if (shortMomentum < shortExitThreshold && longMomentum < 0.03) return "flat";
}
```
---
## Files Generated
1. momentum_plus_SPY_2015-2025.json — Full raw results
2. momentum_plus_SPY_2015-2025_trades.csv — Trade log for spreadsheets
3. momentum_plus_SPY_2015-2025_REPORT.md — This report
---
## Comparison to Buy & Hold
Momentum Plus: Total Return +130.95%, Max Drawdown 19.56%, Sharpe 0.715, 5 Trades
SPY Buy & Hold: Total Return ~180%*, Max Drawdown ~34% (COVID), Sharpe ~0.55*, 1 Trade
*Estimates for comparison
**Verdict:** Lower total return but significantly better risk-adjusted returns and much smaller drawdowns. This is a defensive momentum strategy.
---
## Notes
- should probably run this on more symbols to check if it generalizes
- the 100% win rate is misleading, its only 5 trades. not statistically significant
- need to add transaction cost modelling