Skip to main content
US market 15 min read

US Momentum Strategy: Factor Analysis and a Reproducible finlab Backtest

US momentum strategy, validated factor-first: 12-1 momentum times leveraged ETFs. 2016-2026: 29.9% CAGR, -21.1% max drawdown, passes 3 robustness checks.

Does momentum still work in US stocks? CAGR 29.9% Sharpe 1.36

US momentum strategy backtest equity curve vs QQQ, SPY and naive TQQQ, 2016-2026

Reproduce it

Run this strategy

Copy the prompt to reproduce the evidence above with the article’s data, assumptions, and risk checks.

Tell your AI:

Help me set up FinLab and reproduce the U.S. momentum strategy backtest in this article. Please read: https://finlab.finance/en/setup?relatedUrl=/en/blog/us-momentum-strategy

No install, open FinLab Studio

Momentum is the most replicated anomaly in equity markets, but most articles either stop at the academic claim or show a single equity curve with no proof the underlying stock selection works. This one does both: it first checks whether 12-1 momentum actually sorts US stocks across the entire liquid universe, then turns that signal into a tradable strategy and backtests it with real, downloadable finlab code.

The result, over May 2016 to October 2026: a 29.9% CAGR at a 1.46 monthly Sharpe and a -21.1% maximum drawdown, against 20.7% / 1.09 / -35.1% for buying and holding the Nasdaq-100 (QQQ) over the same dates. The strategy also passes all three robustness checks further down: all 9 neighbouring parameter sets, both halves of the window, and a run with a 0.1% cost on every trade each beat QQQ on daily Sharpe. One important caveat up front, because it changes how you should read every number below: the tradable version does not hold the screened stocks. It holds a small basket of ETFs and adds leveraged growth ETFs only when the broad market trend and momentum participation say the regime supports them. The stock universe is the signal; the leveraged ETFs are the execution. That design has specific risks, covered in full further down. This momentum system is one of ten US strategies built on that same execution model — see how it compares in the US quant trading strategies overview.

The numbers at a glance

Metric This strategy QQQ (buy & hold) SPY (buy & hold) TQQQ (naive buy & hold)
CAGR 29.9% 20.7% 15.1% 40.6%
Monthly Sharpe 1.46 1.09 1.01 0.87
Monthly Sortino 3.99 1.75 1.45 1.46
Max drawdown -21.1% -35.1% -33.7% -81.7%
Annualized volatility 19.9% 22.0% 17.5% 65.2%

The TQQQ column is the point of the whole exercise. A 3x Nasdaq-100 ETF held blindly earned a higher CAGR than the strategy (40.6% vs 29.9%), but at an -81.7% drawdown and 65% annualized volatility, almost no one holds that through a cycle. Timing the same leverage with a regime filter keeps most of the upside while cutting the worst loss to -21%. Numbers are from a finlab backtest; the QQQ, SPY and TQQQ benchmarks use total-return (dividend-adjusted) prices. Every column covers the same dates, 2016-05-02 to 2026-10-26, and every Sharpe and Sortino ratio in this article, for the strategy and the benchmarks alike, is computed without a risk-free rate; the 1.36 monthly Sharpe in the page header and in finlab's own backtest report subtracts a 2% risk-free rate.

What "cross-sectional momentum" means here

Cross-sectional momentum ranks stocks against each other and bets that recent relative winners keep outperforming recent relative losers over the next few weeks to months. The standard academic measure, used here, is 12-1 momentum: the trailing 12-month return excluding the most recent month (the last month is skipped because very short-term returns tend to reverse). Past-winner portfolios beating past losers was documented by Jegadeesh & Titman (1993) and built into a standard factor by Carhart (1997).

This is different from trend-following or "new high" breakouts, which look at one asset's own price path. Cross-sectional momentum is a relative ranking across many names at once, which is exactly why it needs the full universe to be measured properly.

See the U.S. momentum strategy page for more details.

Copy this prompt to your AI agent

FinLab's setup path is now one prompt. Paste it into Codex app or Claude cowork, and the AI will read https://finlab.finance/en/setup, install the FinLab skill when needed, then run or modify the strategy in this article.

Show Code
Help me set up FinLab and build my first U.S. momentum strategy: https://finlab.finance/en/setup

The setup page is https://finlab.finance/en/setup.

Factor analysis: does the selection logic actually work?

Before trusting any strategy, the underlying factor should sort returns across the whole universe, not just in a hand-picked basket. The universe here is the top 500 US stocks by 60-day average dollar volume, with a 10minimumprice,a10 minimum price, a 10M minimum dollar-volume floor, and a rolling filter that removes a name for a year after any single-day move of 50% or more (a cheap guard against split and data artifacts). Dollar volume and the price floor are computed from the unadjusted close (details in the method section). Everything is point-in-time: each month uses only data that was available that day.

Sorting that universe into deciles by 12-1 momentum and measuring the next month's average return gives the cleanest test of the idea.

Average next-month return by US momentum decile, D1 laggards to D10 leaders, 2016-2026

Momentum decile Avg. next-month return
D1 (laggards) 0.53%
D5 1.01%
D8 1.06%
D9 1.28%
D10 (leaders) 2.38%

The payoff sits at the two ends. The top decile averages 2.38% a month, about 4.5 times the laggard decile's 0.53%, and a long-short spread (top decile minus bottom decile) averages 1.84% per month, roughly 22% annualized. In between, deciles D2 to D8 are almost flat, all between 0.88% and 1.10%, so the factor separates the extremes rather than ranking the middle of the market. That is a cleaner "top decile only" shape than the June 2026 version of this article showed, and part of the change comes from the universe fix described in the method section.

A second, stricter test is the Information Coefficient (IC) — the rank correlation between this month's factor value and next period's return. A positive, stable IC means the factor carries genuine predictive information.

Rolling 12-month Rank IC of US 12-1 momentum, 1-month horizon, against strategy growth

Horizon Mean Rank IC
1 month 0.012
3 months 0.016
6 months 0.022
12 months 0.009

These ICs are small. The 1-month mean of 0.012 comes with an IC information ratio of about 0.06, which says the rank relationship across all 500 names is weak and unstable from month to month; even the best horizon, 6 months, reaches only 0.022. That is the realistic picture of momentum: a low-IC, fat-tailed factor whose payoff comes from the right tail (the top decile) rather than a smooth relationship across all stocks. The rolling IC also swings well below zero during momentum reversals, with its deepest stretch in 2021, the well-documented "momentum crash" risk analyzed by Daniel & Moskowitz (2016). Since 2025 it has hovered around zero. The decile spread and the IC together say the same thing: the edge is real in the top decile but noisy across the universe, which is precisely why the tradable version adds a regime filter instead of holding the raw stock basket.

To make the stock-level edge concrete, here is an unlevered, no-timing portfolio that simply holds the top momentum decile (equal weight, rebalanced monthly) versus the equal-weight universe and QQQ:

Top-decile US momentum stocks vs equal-weight universe vs QQQ, unlevered

The top-decile names end the period well above both the broad universe and QQQ with no leverage and no market timing. The path is uneven: they trailed QQQ until 2020 and fell sharply from a mid-2026 peak. That is the alpha the strategy is built on. The factor work and the cross-sector academic evidence in Asness, Moskowitz & Pedersen (2013) are why momentum is worth expressing aggressively when conditions allow.

From factor to signal: momentum breadth as a regime gate

Holding the top-decile stocks directly works, but an unlevered basket leaves return capacity on the table and still rides the full market drawdown. The strategy instead gates leveraged exposure with two conditions: the QQQ trend, which does the regime switching, and the breadth of momentum — the share of the universe that are positive-trend, top-decile leaders — which confirms that participation is broad rather than narrow.

US momentum breadth over time vs strategy growth, with 8% risk-on threshold

When breadth is high, broad participation signals persistent institutional risk appetite, and growth-beta leadership tends to continue. The risk-on regime requires three conditions at once: momentum breadth above 8%, QQQ trading above its 200-day average, and a positive QQQ 126-day trend. Because breadth counts top-decile names that also have a positive 12-month return, it cannot rise much above 10% of the universe, and in this sample the month-end readings stayed between 9.5% and 10.2%. The 8% bar therefore never switched the strategy off in this window; it would only bind in a market where a large share of the momentum leaders themselves are down over 12 months. The QQQ trend and momentum conditions did all of the switching. When all three hold, the strategy buys the two strongest leveraged growth ETFs (TQQQ and TECL); otherwise it holds a single defensive ETF (treasuries, gold, or cash-like). In the backtest the defensive ETF usually stays in the portfolio during risk-on months as well: in 66 of the 70 months with leveraged ETFs in the trade list, TQQQ and TECL each held about 25% of the portfolio next to a defensive ETF at about 50%, so a typical risk-on month carries roughly half the portfolio in 3x products rather than all of it. Rebalancing is monthly, with an 8% touched stop on the ETF leg.

The data behind it

Everything runs on FinLab's US datasets. The single-stock screen and the ETF execution use different markets:

Show Code
from finlab import data
 
# Single-stock universe (the momentum screen / breadth signal)
data.set_market("us")
close = data.get("us_price:adj_close")   # dividend/split-adjusted: used for returns
raw_close = data.get("us_price:close")   # unadjusted: used for dollar volume and the price floor
volume = data.get("us_price:volume")     # share volume, not split-adjusted
 
# Leveraged + defensive ETFs (the tradable position)
data.set_market("us_fund")
etf_close = data.get("us_fund_price:adj_close")[["QQQ", "TQQQ", "TECL", "IEF", "GLD", "SHY"]]

us_price:adj_close is total-return adjusted, so the momentum factor is not distorted by dividends or splits. Volume is not split-adjusted, so it is paired with the unadjusted us_price:close when computing dollar volume. The benchmark used throughout is QQQ total return, with SPY as a broad-market reference. The leveraged ETF series already embed each fund's daily-reset behavior and expense ratio, so the volatility drag of 3x products is reflected in the results — it is not assumed away.

The strategy, in readable steps

The core logic is short. This is the on-page version; the full downloadable script is linked at the end.

Show Code
import finlab
from finlab import data
from finlab.backtest import sim
from finlab.dataframe import FinlabDataFrame
 
finlab.login()  # finlab guides you through login automatically
 
data.set_market("us")
close = data.get("us_price:adj_close")
raw_close = data.get("us_price:close")
volume = data.get("us_price:volume")
fund_close = data.get("us_fund_price:adj_close")[["QQQ", "TQQQ", "TECL", "IEF", "GLD", "SHY"]]
 
# 1. 12-1 momentum on a liquid, point-in-time universe
universe = liquid_universe(close, raw_close, volume, top_n=500)
ret_12m = close / close.shift(252) - 1
ret_1m = close / close.shift(21) - 1
momentum = ret_12m - ret_1m
 
# 2. Breadth: share of the universe that are positive-trend momentum leaders
leaders = (momentum[universe].rank(axis=1, pct=True) > 0.90) & (ret_12m > 0)
breadth = leaders.sum(axis=1) / universe.sum(axis=1)
 
# 3. Risk-on when breadth AND the QQQ trend agree
qqq_trend = fund_close["QQQ"] > fund_close["QQQ"].rolling(200, min_periods=100).mean()
qqq_mom = fund_close["QQQ"] / fund_close["QQQ"].shift(126) - 1
risk_on = (breadth > 0.08) & (qqq_trend & (qqq_mom > 0)).reindex(breadth.index)
 
# 4. Risk-on adds the 2 strongest leveraged ETFs; 1 defensive ETF is picked by its trend
#    and in most risk-on months stays alongside them (about 25% / 25% / 50%)
#    (full selection + weighting in the downloadable strategy.py)

The liquid_universe helper applies the dollar-volume, price, and artifact filters described above. The full position construction and the sim() call (monthly rebalance, 8% stop) are in the downloadable file.

Results and out-of-sample test

The strategy curve versus benchmarks is the chart at the top of this article. Here is the interactive finlab report — drawdowns, monthly returns, and trade list — so you can inspect it directly rather than trust a summary:

The single most important robustness question for any backtest is whether it only worked in the period it was designed on. The strategy parameters were chosen on 2016-2021 data and then left untouched on 2022-present, an unseen period that includes the 2022 bear market.

Period CAGR Monthly Sharpe Max drawdown
Research (2016-2021) 31.4% 1.47 -21.1%
Out-of-sample (2022-present) 28.1% 1.50 -19.3%

Performance held up out of sample: CAGR slipped from 31.4% to 28.1%, while the monthly Sharpe was slightly higher and the drawdown slightly smaller. The unseen period opens with 2022, when the regime filter held only defensive ETFs from the first week of January to year-end; the strategy lost 7.9% in calendar 2022 while QQQ lost 32.6%. That is a genuine point in the strategy's favor, but it is a single market cycle, not a guarantee.

Robustness checks: neighbouring parameters, two halves, trading costs

Here "beats QQQ" means a higher daily Sharpe (mean daily return divided by its standard deviation, annualized with √252, no risk-free rate) than buying and holding QQQ with dividends over exactly the same dates. On that measure the default strategy scores 1.40 against QQQ's 0.95, which is why the figures here differ from the monthly Sharpe in the summary table.

Heatmap of US momentum strategy daily Sharpe across breadth thresholds 6%, 8%, 10% and QQQ trend averages of 150, 200, 250 days, all nine above QQQ 0.95

Neighbouring parameters. The two settings varied are the momentum-breadth threshold (6%, 8%, 10%; the original is 8%) and the length of the QQQ trend average (150, 200, 250 days; the original is 200). The pass mark is 7 of 9. All 9 combinations beat QQQ. The 10% row is the weakest at 1.06 against QQQ's 0.95: a 10% bar sits inside the 9.5% to 10.2% range that breadth actually occupied, so it does bind. The 6% and 8% rows are identical (1.40, 1.40, 1.36), consistent with breadth never falling to either level at a month-end. The 150-day and 200-day columns also give identical results in this run; the 250-day column is slightly lower in the 6% and 8% rows (1.36) and the same in the 10% row.

Two halves. The full window cut in half by trading days, each half compared with QQQ on its own:

Half Dates Strategy Sharpe QQQ Sharpe
First 2016-05-02 to 2021-07-08 1.51 1.20
Second 2021-07-08 to 2026-10-26 1.29 0.71

Both halves beat QQQ. This split is by trading days, so it differs from the calendar research and out-of-sample periods above.

Trading costs. finlab's US market default commission and tax are both zero (zero-commission brokers), so the headline run carries no cost at all. Charging 0.1% on every buy and every sell as a stand-in for spread and slippage lowers the CAGR from 29.9% to 28.4% and the daily Sharpe to 1.34, still above QQQ's 0.95.

Verdict: the strategy passes all three checks. To reproduce them, run python strategy.py --validate with the downloadable script below.

Backtest method and limits

A strategy is only as trustworthy as the assumptions behind it. The relevant ones here:

Item This backtest
Transaction costs finlab's US default is zero commission and zero tax, so the headline run assumes no costs. The cost check charges 0.1% per buy and per sell for spread and slippage: CAGR 28.4%, daily Sharpe 1.34 vs QQQ 0.95.
Leverage decay Already reflected — TQQQ/TECL price series include daily-reset drag and expense ratios.
Universe / point-in-time Top 500 by 60-day dollar volume; 10priceand10 price and 10M dollar-volume floors; rolling artifact filter; each date uses only then-available data. FinLab's US volume is not split-adjusted, so dollar volume and the price floor use the unadjusted close (us_price:close) while returns use the adjusted close; multiplying adjusted close by volume had overstated dollar volume before reverse splits and let tiny reverse-split names into the top 500.
Data and engine finlab 2.2.20 on FinLab data through 2026-10-26. Since the June 2026 version of this article, FinLab added missing dividends to adjusted US prices and fixed split and spin-off adjustments, and finlab changed how a stop-loss on a rebalance day is costed, so historical figures moved too (the June headline CAGR was 35.1%).
Turnover About 4.0x per year (monthly regime switches, not daily churn).
Position rule Risk-on: TQQQ and TECL, in most months at about 25% each next to a defensive ETF at about 50%; risk-off: 1 defensive ETF. 8% touched stop.
Sample 2016-2021 in-sample calibration; 2022-present out-of-sample; plus the parameter, two-half and cost checks above.
Capacity Not estimated. Leveraged ETF AUM is large, but real impact depends on your size.

The headline gate this strategy is judged against is a risk-adjusted ratio of at least 1.5, measured without a risk-free rate: it passes on monthly Sortino (3.99), daily Sortino (1.67), and the out-of-sample monthly Sharpe (1.50), while the full-period monthly Sharpe of 1.46 sits just below it.

The leveraged-ETF risk you must understand

This is not a buy-and-hold stock strategy, and the leverage is the main thing that can hurt you:

  • Daily reset and path dependency. A 3x daily ETF compounds daily, so a choppy, sideways market erodes value even if the index ends flat. The naive TQQQ column above (-81.7% drawdown) is what unmanaged 3x exposure looks like.
  • Gaps can beat stops. The 8% stop is a touched stop in the backtest; a large overnight gap can fill worse than the stop level in live trading.
  • Monthly switching is not crash protection. The regime filter rebalances monthly. A fast crash inside a month hits the leveraged position until the stop or the next rebalance.
  • Long stretches behind the index. The filter can sit out or lag strong markets: the strategy returned -2.5% in 2019 when QQQ gained 39.0%, and 19.9% in 2023 against QQQ's 54.9%.
  • Concentration. Holding one to three ETFs means single-position and single-theme (large-cap US growth) risk.

If those risks are not acceptable to you, the unlevered top-decile stock portfolio shown earlier captures the same momentum edge without the leverage-specific risks (daily reset, gaps through stops), although its drawdowns in this sample were deeper than the strategy's.

Who this is for

It fits an investor who wants a rules-based, growth-tilted US strategy, understands leveraged ETFs, and can tolerate 20%+ drawdowns in exchange for higher compounding. It does not fit anyone who needs capital stability, cannot monitor a monthly rebalance, or is uncomfortable holding 3x products at any time.

FAQ

Does momentum still work in US stocks? The decile sort and a positive (if small) IC over 2016-2026 say yes for the top decile, consistent with the long literature from Jegadeesh & Titman (1993) onward. The edge is concentrated in the strongest names and is vulnerable to sharp reversals.

Why hold leveraged ETFs instead of the momentum stocks? The stock basket has real alpha but limited return capacity and rides the full market drawdown. Using a regime gate and expressing it through leveraged ETFs targets higher compounding while stepping aside in weak regimes. The trade-off is leverage risk.

Isn't a 30% CAGR too good to be true? It comes with a -21% drawdown, 20% volatility, and 3x-ETF exposure. The naive 3x comparison (40.6% CAGR but -82% drawdown) shows the raw return is available; the strategy's contribution is risk management, not magic.

Did the result depend on lucky parameters? Not in this test: all 9 combinations of breadth threshold (6/8/10%) and QQQ trend average (150/200/250 days) beat QQQ on daily Sharpe, both halves of the window beat QQQ, and it still beats QQQ with a 0.1% cost per trade side. Run python strategy.py --validate to check it yourself.

How often does it rebalance? Monthly. Turnover is about 4.0x per year.

What data do I need? FinLab's us_price:* for the single-stock screen and us_fund_price:* for the ETFs. Both are in a standard FinLab account.

Can I run this myself? Yes — use the AI-assisted setup flow, or download the script below and run it after setup.

Reproduce it yourself

Two files reproduce everything above:

The fastest path is to use the AI-assisted setup flow and ask your AI agent to run and modify it — change the universe size, the breadth threshold, or swap the leveraged ETFs for unlevered ones, and let the agent re-run the backtest. To see how this strategy sits among nine related US systems, read the US quant trading strategies overview. For more strategy write-ups, see the FinLab research blog. To see what teams build with finlab, browse the use cases and the team behind FinLab.


Last updated: 2026-10 | Backtest window: 2016-05 to 2026-10 | Benchmark: QQQ total return | Author: FinLab Quant Research (reviewed by a quantitative researcher)

Investing involves risk, and past performance does not represent future results. Leveraged ETFs carry additional risks including volatility decay and amplified losses. This content is for educational purposes only and is not investment advice and does not constitute investment advice; evaluate any strategy against your own risk tolerance.

FinLab AI

Want to build your own strategy?

Describe your stock-picking ideas in natural language. AI automatically validates, backtests, and gives you answers

Start Free