Overall top-100 hits
22.11
average across horizons
Predicted top-100 avg actual rank
231.54
lower is better
Horizon Breakdown
top 100 only| Horizon | Average Top-100 Hits | Predicted Top-100 Avg Actual Rank |
|---|---|---|
| 3m | 21.60 | 236.45 |
| 6m | 21.89 | 231.25 |
| 12m | 22.85 | 226.91 |
Run Details
strategy_test_results #4| id | 4 |
|---|---|
| strategy_id | strategy_000002 |
| strategy_hash | ef391fadad9015157ba27926babe52697cb506f3e13d354850eb04c607d7c01b |
| evaluator_version | v3_top100_monthly |
| start_date | 2015-01-01 |
| end_date | 2025-06-01 |
| created_at | 2026-07-24 20:49:22 |
| updated_at | 2026-07-24 20:49:22 |
Sample Top-100 Lists
2020-03-31 / 6m / 21 hitsPredicted top 100
A, AAL, AAP, AAPL, ABBV, ABC, ABMD, ABT, ACN, ADBE, ADI, ADM, ADP, ADSK, AEE, AEP, AES, AFL, AIG, AIZ, AJG, AKAM, ALB, ALGN, ALK, ALL, ALLE, ALXN, AMAT, AMCR, AMD, AME, AMGN, AMP, AMT, AMZN, ANET, ANSS, AON, AOS, APD, APH, APTV, ARE, ATO, ATVI, AVB, AVGO, AVY, AWK, AXP, AZO, BA, BAC, BAX, BBY, BDX, BEN, BF-B, BIIB, BIO, BK, BKNG, BKR, BLK, BLL, BMY, BR, BRK-B, BSX, BWA, BXP, C, CAG, CAH, CARR, CAT, CB, CBOE, CBRE, CCI, CCL, CDNS, CDW, CE, FTNT, GILD, GIS, HRL, INTC, K, LLY, MSFT, NEE, NEM, NFLX, NVDA, REGN, TMUS, VRTX
Actual top 100
AAP, AAPL, ABMD, ADBE, ADSK, ALB, ALGN, AMD, AMP, AMZN, APD, APH, APTV, ATVI, AVGO, BBY, BWA, CARR, CDNS, CE, CHRW, CMG, CMI, CPRT, CRM, CTAS, CTLT, CTSH, DD, DE, DHI, DHR, DRI, DXCM, EBAY, EMN, ETSY, EXPE, FCX, FDX, GLW, GPS, HAL, HD, IDXX, IPGP, JCI, KMX, LEG, LEN, LH, LOW, MAS, MCHP, MGM, MOS, NCLH, NKE, NOW, NSC, NVDA, NWS, NWSA, ORLY, PAYC, PH, PHM, PNR, POOL, PVH, PWR, PYPL, QCOM, QRVO, RCL, ROK, ROL, SHW, SIVB, SNPS, SWK, SWKS, SYF, TDG, TEL, TER, TGT, TMO, TSCO, TSLA, TT, UPS, URI, VAR, VIAC, VTR, WHR, WMB, WST, WY
Matched tickers
AAP, AAPL, ABMD, ADBE, ADSK, ALB, ALGN, AMD, AMP, AMZN, APD, APH, APTV, ATVI, AVGO, BBY, BWA, CARR, CDNS, CE, NVDA
Strategy Script
ef391fadad"""Generated V3 stock-ranking strategy."""
from __future__ import annotations
import numpy as np
STRATEGY_ID = "strategy_000002"
DESCRIPTION = """
Ranks S&P 500 candidates using medium-term momentum, quality growth, valuation,
and a short-term risk adjustment. It rewards constructive pullbacks from 52-week highs
only when 6-month momentum is positive.
"""
FACTORS_USED = [
"return_6m_pct",
"momentum_12_1_pct",
"eps_growth_pct",
"revenue_growth_pct",
"forward_pe",
"vol_63d",
"from_52w_high_pct",
"from_200d_ma_pct",
"market_cap",
]
PARAMETERS = {
"momentum_weight": 0.445689778810,
"quality_weight": 0.110943830910,
"value_weight": 0.054005917375,
"risk_penalty": 0.309803145628,
"drawdown_bonus": 0.118071457138,
"market_cap_penalty": 0.017976418416,
"min_price_sma": -0.059713236509,
}
COMPLEXITY = 5
PARENT_STRATEGY_ID = None
GENERATION = 1
RANDOM_SEED = 43
CREATED_AT = "2026-07-25T03:47:27+00:00"
def _zscore(series):
clean = series.replace([np.inf, -np.inf], np.nan)
std = clean.std()
if not np.isfinite(std) or std == 0:
return clean * 0.0
return (clean - clean.mean()) / std
def eligibility_filter(df):
# Avoid severely broken trends; the evaluator already applies price/volume
# filters, so this strategy-level filter is deliberately narrow.
return df["from_200d_ma_pct"].fillna(0) >= PARAMETERS["min_price_sma"]
def calculate_score(df):
# Momentum combines raw 6-month return with 12-minus-1 momentum so the score
# favors both recent leadership and sustained prior trend.
momentum = 0.65 * _zscore(df["return_6m_pct"]) + 0.35 * _zscore(df["momentum_12_1_pct"])
# Quality growth rewards companies where revenue and EPS are both improving.
quality = 0.55 * _zscore(df["eps_growth_pct"]) + 0.45 * _zscore(df["revenue_growth_pct"])
# Lower forward P/E is better, but missing valuation data is neutralized by
# the evaluator's rank fill below rather than treated as automatically cheap.
value = -_zscore(df["forward_pe"])
# Penalize short-term instability; jumpier names need more momentum/quality
# to stay highly ranked.
risk = _zscore(df["vol_63d"])
# Interaction: constructive pullbacks receive a bonus only when momentum is
# positive. Deep drawdowns without momentum do not get rewarded.
pullback = (-df["from_52w_high_pct"]).clip(lower=0, upper=0.35)
constructive_pullback = pullback.where(df["return_6m_pct"].fillna(0) > 0, 0)
# Mild size penalty keeps mega-cap stability from dominating a gain forecast.
size_penalty = _zscore(np.log1p(df["market_cap"].clip(lower=0)))
score = (
PARAMETERS["momentum_weight"] * momentum
+ PARAMETERS["quality_weight"] * quality
+ PARAMETERS["value_weight"] * value
- PARAMETERS["risk_penalty"] * risk
+ PARAMETERS["drawdown_bonus"] * constructive_pullback
- PARAMETERS["market_cap_penalty"] * size_penalty
)
score = score.where(eligibility_filter(df), -1e9)
return score.replace([np.inf, -np.inf], np.nan).fillna(score.median()).fillna(0.0)