Member-only story
The Strategy That Does Everything Right — And Still Loses to Doing Nothing
A quantitative post-mortem on the SPY HMA+ROC system
Kryptera11 min read·Just now--
The Setup Looks Promising
On paper, this strategy has every right to work. It enters trades using the Hull Moving Average (HMA) — one of the smoothest, lowest-lag trend-following indicators available — triggering when price crosses below the fast HMA line. It exits using the Rate of Change (ROC), waiting for momentum to recover from oversold territory before closing the position. Entry on the open of the next bar. Realistic fees (0.1%) and slippage (0.2%) baked in. Clean logic, clean code.
import pandas as pd
import numpy as np
import yfinance as yf
import vectorbt as vbt
# -------------------------
# Download Data
# -------------------------
symbol = "SPY"
start_date = "1997-01-01"
end_date = "2030-01-01"
interval = "1d"
df = yf.download(symbol, start=start_date, end=end_date, interval=interval, multi_level_index=False)
df.reset_index().to_csv("SPY_clean.csv", index=False)
# -------------------------
# Necessary Parameters
# -------------------------
HMA_FAST_LENGTH = 24
HMA_SLOW_LENGTH = 40
ROC_OVERSOLD = -5.0
ROC_PERIOD = 10
# -------------------------
# Indicator Functions
# -------------------------
def price_cross_below_hma_fast(df…