How I Rank 151 US Large-Caps With a 15-Line Model

TL;DR: A momentum + quality factor screen that runs in under 30 seconds, needs no API keys, and outputs a ranked CSV you can open in Excel. The code is below. The data is free. The full pack (weekly updates, extended universe, methodology doc) is $9.

The Problem With Most Factor Screens

I've read a lot of quant posts on Dev.to. They fall into two camps:

  1. "Buy NVDA, sell TSLA" — no methodology, no reproducibility, just vibes.
  2. 40-factor black boxes — 200 lines of code, opaque weighting, and you can't tell which factor is driving the signal.

I wanted something in the middle: transparent, reproducible, and actually useful. Not a trading signal. A research tool.

So I built one.

The Model: 2 Factors, Equal Weight, 15 Lines

Momentum = 12-month total return (z-scored cross-sectionally)
Quality = negative annualized volatility (z-scored cross-sectionally)
Composite = 0.5 × Momentum + 0.5 × Quality

That's it. No ML. No black box. No "proprietary alpha."

Why these two?

  • Momentum is the most robust anomaly in academic finance (Jegadeesh & Titman, 1993). Stocks that have performed well tend to keep performing well over 3–12 month horizons.
  • Quality (proxied by low volatility) captures the "low-vol anomaly" — stocks with stable earnings and strong balance sheets tend to outperform on a risk-adjusted basis.
  • Equal weight is the most defensible starting point. You can change it, but you need a reason.

Why z-scores? Raw returns and volatility are on different scales. Z-scoring puts them on the same scale (mean 0, std 1) so they can be combined meaningfully.

The Code (15 Lines)

import yfinance as yf, pandas as pd, numpy as np, warnings warnings.filterwarnings("ignore") TICKERS = ["AAPL","MSFT","NVDA","GOOGL","AMZN","META","TSLA","AVGO","AMD","NFLX", "ORCL","CRM","ADBE","CSCO","QCOM","TXN","MU","INTC","IBM","NOW","INTU", "PLTR","SNOW","DDOG","NET","CRWD","PANW","ZS","FTNT","ANET","SMCI","ARM", "MRVL","LRCX","AMAT","KLAC","ASML","ON","MPWR","MCHP","TER","ADSK","CDNS", "SNPS","GFS","MRNA","LLY","NVO","UNH","JNJ","PFE","MRK","ABBV","BMY","TMO", "DHR","ISRG","VRTX","REGN","AMGN","GILD","BSX","CVS","CI","HUM","ABT","SYK", "ALGN","MDT","BABA","JD","PDD","SE","BIDU","UBER","ABNB","DASH","COIN","HOOD", "PYPL","V","MA","AXP","BLK","SCHW","C","BAC","WFC","JPM","GS","MS","SPGI", "ICE","CME","MCO","AIG","MET","PRU","TRV","ALL","CB","PGR","SPOT","T","VZ", "TMUS","CMCSA","DIS","WMT","COST","HD","MCD","NKE","SBUX","TGT","UPS","CAT", "DE","GE","BA","HON","UNP","CSX","NSC","LIN","APD","ECL","SHW","EMR","ETN", "PH","ROK","WM","RSG","COP","XOM","CVX","SLB","OXY","EOG","DVN","PSX","VLO", "MPC","PBR","BP","SHEL","TTE","RIO","FCX","NEM"] close = yf.download(TICKERS, period="2y", interval="1d", auto_adjust=True, progress=False)["Close"].dropna(axis=1, how="any") rets = close.pct_change().dropna() mom12 = close.iloc[-1] / close.iloc[-252] - 1 vol = rets.iloc[-252:].std() * np.sqrt(252) qual = -vol.rank(pct=True) df = pd.DataFrame({"mom12": mom12, "vol": vol, "qual": qual}) df["score"] = 0.5 * df["mom12"].rank(pct=True) + 0.5 * df["qual"] df = df.sort_values("score", ascending=False) print(df.head(20).round(4)) df.to_csv("launchtower_factor_ranking.csv") 

That's the whole thing. No API keys. No cloud. No subscription. One file.

Line-by-Line

Line What it does
1–2 Imports + suppress warnings
3–10 The universe: 151 US large-caps (tech, financials, healthcare, energy, industrials, consumer)
11 Download 2 years of split/dividend-adjusted closes via yfinance
12 Compute daily returns
13 12-month momentum: last_price / price_252_days_ago - 1
14 Annualized volatility: std(daily_returns) × √252
15 Quality proxy: invert the volatility rank (low vol = high quality)
16 Build the DataFrame
17 Composite score: 50% momentum + 50% quality
18 Sort descending
19 Print top 20
20 Save to CSV

Total runtime: ~20–30 seconds (depends on your connection and how many tickers yfinance can fetch in parallel).

The Results (2026-09-16)

Here's the top 10 and bottom 5 from the actual run:

Rank Ticker 12m Return Ann. Vol Composite
1 MS +597.7% 81.5% 2.368
2 MPC +151.5% 36.1% 0.778
3 SYK +315.6% 79.5% 0.695
4 BLK +64.4% 28.9% 0.644
5 HD +61.5% 26.7% 0.615
6 JD +61.1% 25.4% 0.611
7 TER +53.3% 29.8% 0.533
8 COP +47.6% 27.6% 0.476
9 ROK +47.2% 26.9% 0.472
10 CVX +47.1% 27.1% 0.471
... ... ... ... ...
147 BAC −10.5% 65.4% −1.050
148 CVS −10.7% 66.7% −1.073
149 NEM −41.0% 63.1% −1.075
150 AMAT −44.4% 70.7% −1.286
151 NSC −8.7% 91.4% −1.586

Observations:

  • MS (Morgan Stanley) is #1 because it has both strong momentum (+597% over 12m) and moderate volatility (81.5% is high, but not the highest in the universe).
  • MPC (Marathon Petroleum) is #2 because it has strong momentum (+151%) and low volatility (36.1%).
  • NSC (Norfolk Southern) is #151 because it has negative momentum (−8.7%) and the highest volatility in the universe (91.4%).

This is not a "buy MS, sell NSC" signal. It's a research output. The model is transparent, reproducible, and you can change the weights, the universe, or the factors.

What's Free vs. What's Paid

Free (this article + GitHub)

  • ✅ The complete 15-line Python code (above)
  • ✅ The 15-row sample CSV (top 10 + bottom 5) on GitHub
  • ✅ The full methodology explanation (this article)
  • ✅ The ability to run the code yourself and generate your own CSV

GitHub repo: launchtower-factor-dataset

Paid ($9 — one-time, no subscription)

  • ✅ Full 151-stock CSV (all 14 columns: rank, date, ticker, last_price, ret_1m, ret_3m, ret_6m, ret_12m, vol_ann, max_drawdown, from_52w_high, momentum_score, quality_score, composite_score)
  • ✅ Weekly updates (new CSV every Friday, same format)
  • ✅ Extended universe (250+ tickers, including mid-caps and international large-caps)
  • ✅ Methodology doc (PDF, 12 pages, with backtest results and factor decay analysis)
  • ✅ The full Python script (with error handling, logging, and a CLI interface)

Why $9? It's not a subscription. It's a one-time purchase for the full dataset + weekly updates. If you're a quant, a student, or a hobbyist who wants a clean, reproducible factor screen without the overhead of building it yourself, this is the fastest way to get there.

Buy the full pack: https://whop.com/checkout/ch_mzllge4nddGGKgv/

How to Use This Data

  • Screening: Filter composite_score > 0.5 for a momentum + low-vol universe.
  • Backtesting: Use the 12-month returns as a signal, then test forward returns (not included in the free sample).
  • Portfolio construction: Weight positions by composite_score or use it as a tilt within an existing portfolio.
  • Research: Compare your own factor model against this baseline. If you can't beat it, you probably don't have an edge.

Limitations (Honest)

  • No out-of-sample validation. This is a point-in-time snapshot, not a backtest.
  • No transaction costs. Real-world trading has slippage, bid-ask spreads, and market impact.
  • No fundamental data. The quality factor is a proxy (low volatility), not a true quality score (ROE, debt/equity, earnings stability).
  • Survivorship bias. The universe is hand-picked; it doesn't include delisted stocks.
  • Data quality. yfinance is free and public, but it's not a professional data feed. Prices may be slightly off or delayed.

This is a research tool, not a trading signal. Use it to inform your own analysis, not to replace it.

Disclaimer

This is research/educational output from public market data. Not personalized investment advice, not a recommendation to buy or sell any security. Past performance does not guarantee future results. No return or performance promises are made.

LaunchTower — independent research data.