WorldQuant BRAIN — Deep Alpha Construction Guide
This guide covers every operator, data type, alpha pattern, and portfolio strategy needed to dominate the IQC. Based on documented winner strategies, finalist int…
WorldQuant BRAIN — Deep Alpha Construction Guide
This guide covers every operator, data type, alpha pattern, and portfolio strategy needed to dominate the IQC. Based on documented winner strategies, finalist interviews, and submitted alphas with real Sharpe metrics.
PART 1 — THE BRAIN OPERATOR REFERENCE
Preprocessing — Apply This to EVERY Raw Field First
winsorize(ts_backfill(field, 120), std=4)
ts_backfill(field, 120): fills gaps in data using backward fill over 120 dayswinsorize(..., std=4): clips extreme values at ±4 standard deviations- Apply before ANY operator. Without this, outliers destroy your alpha.
Cross-Sectional Operators
| Operator | Formula/Use | When to Use |
|---|---|---|
rank(x) | Converts to uniform [0,1] distribution | Most fundamental — apply to almost everything |
zscore(x) | (x - mean(x)) / std(x) | When magnitude matters, not just rank |
scale(x) | Scales to sum to 1 long, 1 short | Final step before submission |
group_rank(x, group) | rank within sector/industry | Far more powerful than plain rank for fundamentals |
group_neutralize(x, group) | Removes sector/industry mean | Critical: isolates true stock-level signal from sector beta |
group_zscore(x, group) | z-score within group | Best for fundamentals when you want magnitude within sector |
Neutralization groups (most common): market, sector, industry, subindustry
Time-Series Operators (The Workhorses)
| Operator | What It Does | Best Windows |
|---|---|---|
ts_rank(x, d) | Percentile rank over past d days | 5, 22, 66, 120, 240 |
ts_delta(x, d) | x[today] - x[d days ago] | 1, 5, 22, 66 |
ts_mean(x, d) | Rolling average | 5, 22, 66 |
ts_zscore(x, d) | Rolling z-score: detects recent abnormality | 20, 60, 120 |
ts_std_dev(x, d) | Rolling standard deviation (volatility) | 22, 66, 252 |
ts_corr(x, y, d) | Rolling correlation between two signals | 20, 60 |
ts_decay_linear(x, d) | Linear decay weighting (reduces turnover) | 5, 10, 22 |
ts_decay_exp_window(x, d) | Exponential decay (aggressive recency) | 5, 10 |
ts_arg_max(x, d) | Index of max in window (when was peak?) | 5, 10, 22 |
ts_arg_min(x, d) | Index of min in window | 5, 10, 22 |
ts_av_diff(x, d) | x - ts_mean(x, d) (deviation signal) | 20, 60, 120 |
ts_backfill(x, d) | Fill missing data backward | Always use 120 |
trade_when(alpha, condition) — conditional trading that dramatically reduces turnover:
trade_when(rank(-ts_delta(close, 5)), ts_arg_max(volume, 5) == 0)
# Only trade the reversion signal when volume was NOT highest in last 5 days
Vector Data Operators (for news/sentiment fields)
Before using any scl12_ or scl15_ vector fields, you MUST aggregate:
vec_avg(field) # arithmetic mean across vector
vec_sum(field) # sum across vector
vec_count(field) # count of non-null elements
vec_stddev(field) # std dev across vector
vec_max(field) # max element
vec_min(field) # min element
PART 2 — ALPHA CONSTRUCTION PATTERNS (WITH REAL METRICS)
Pattern 1 — Price Mean Reversion (Most Reliable)
Concept: Stocks that fall most in recent days tend to rebound.
rank(-ts_delta(close, 5))
- Real metrics: Sharpe ~1.80, turnover 51%, annual returns 17%, Fitness 1.03
- Neutralization: MARKET or NONE (price-volume works better without subindustry neutralization)
- Universe: TOP3000
Enhanced with intraday signal:
rank((high + low) / 2 - close)
Buys stocks that closed below their intraday average — captures daily mean reversion.
With decay to reduce turnover:
ts_decay_linear(rank(-ts_delta(close, 5)), 3)
Decay of 3 keeps most signal while cutting turnover ~30%.
Pattern 2 — Fundamental Value Signals
EBIT/CapEx ratio (appeared in 4 documented winning submissions):
-rank(winsorize(ts_backfill(ebit, 120), std=4) /
winsorize(ts_backfill(capex, 120), std=4))
- Neutralization: SUBINDUSTRY
- Short capital-intensive, low-earnings stocks
Enterprise Value/EBITDA mean reversion:
-ts_zscore(winsorize(ts_backfill(enterprise_value, 120), std=4) /
winsorize(ts_backfill(ebitda, 120), std=4), 63)
- Decay 5–10, SUBINDUSTRY neutralized
Profitability composite:
fam_roe_rank * rank(winsorize(ts_backfill(sales, 120), std=4) /
winsorize(ts_backfill(assets, 120), std=4))
Pattern 3 — Analyst Estimate Signals
Analyst EPS Rank within sector (Sharpe ~1.7–1.9):
group_rank(fam_est_eps_rank, sector)
EPS estimate revision momentum:
ts_delta(fam_est_eps_rank, 22)
Rank change in analyst EPS estimates over one month.
Pattern 4 — News / Sentiment Signals
Buzz deviation from baseline (Sharpe ~1.94):
# Step 1: aggregate the buzz vector
buzz = ts_backfill(vec_sum(scl12_alltype_buzzvec), 20)
# Step 2: compute deviation from 60-day baseline
-ts_av_diff(buzz, 60)
Negative sign: stocks with declining buzz tend to underperform.
Sentiment momentum:
ts_delta(vec_avg(scl15_d1_sentiment), 5)
Pattern 5 — Volatility × Volume × Fundamental (Best Documented: Sharpe 5.03)
rank(-mdl175_volatility * log(volume)) * (1 + group_rank(mdl175_revenuettm, gp))
- Tested on: China TOP3000, Delay-0
- Real metrics: Sharpe 5.03, Returns 29.08%, Margin 44.68‱
- Combines volatility suppression + fundamental growth weighting
Pattern 6 — Simple Intraday Decay
ts_decay_exp_window(rank(change_day), 4)
Exponentially decayed intraday price change rank — low turnover, stable signal.
Pattern 7 — Deep Nested (101 Formulaic Alphas Style, Alpha #98)
rank(decay_linear(correlation(vwap, sum(adv5, 26.4719), 4.58418), 7.18088))
- rank(decay_linear(ts_rank(ts_arg_min(correlation(rank(open), rank(adv15), 20.8187),
8.62571), 6.95668), 8.07206))
Complex nested operators from the 101 Formulaic Alphas paper. These are harder to intuit but less correlated with simpler alphas — valuable for portfolio diversification.
PART 3 — SYSTEMATIC ALPHA GENERATION (AUTOMATION)
The Three-Order Escalation System
Generate hundreds of alpha candidates automatically by crossing:
OPERATIONS = ['ts_rank', 'ts_zscore', 'ts_arg_min', 'ts_delta', 'ts_std_dev', 'ts_mean']
WINDOWS = [5, 22, 66, 120, 240]
FIELDS = [all available dataset fields]
# First order: single op on preprocessed field
for op in OPERATIONS:
for window in WINDOWS:
for field in FIELDS:
alpha = f"rank({op}(winsorize(ts_backfill({field}, 120), std=4), {window}))"
# Submit. Keep if Sharpe > 1.2.
# Second order: add neutralization to passing first-order alphas
for alpha in first_order_passing:
for group in ['sector', 'industry', 'subindustry']:
enhanced = f"group_neutralize({alpha}, {group})"
# Submit. Keep if fitness improves.
# Third order: add conditional logic to reduce turnover
for alpha in second_order_passing:
conditional = f"trade_when({alpha}, ts_arg_max(volume, 5) == 0)"
# Submit. Keep if turnover drops meaningfully.
PART 4 — NEUTRALIZATION STRATEGY
Match neutralization to data type:
| Data Type | Best Neutralization | Why |
|---|---|---|
| Price/volume | MARKET or NONE | Price signals are pan-market; sector isolation reduces signal |
| Fundamentals (P/E, EPS, ROE) | SUBINDUSTRY | Compare a stock to its closest peers |
| Analyst estimates | INDUSTRY | Analyst coverage organized by industry |
| News/sentiment | SUBINDUSTRY or INDUSTRY | News affects whole industry clusters |
| Options data (IV, put-call) | MARKET or SECTOR | Options signals are broad-market related |
| Social media | SUBINDUSTRY | Social momentum is peer-group relative |
PART 5 — TURNOVER REDUCTION (Fitness Optimization)
Turnover is penalized by the fitness formula. Reducing turnover directly improves fitness even if Sharpe stays the same.
Techniques:
-
ts_decay_linear or ts_decay_exp_window — smooth the signal over time
ts_decay_linear(rank(-ts_delta(close, 5)), 5) # 5-day linear decay -
trade_when — only trade when condition is met
trade_when(rank(signal), ts_arg_max(volume, 10) <= 2) -
Longer lookback — use
ts_delta(close, 22)instead ofts_delta(close, 5); monthly changes are smoother -
Fundamental data — quarterly updates naturally produce low-turnover signals
-
ts_rank with longer window —
ts_rank(close, 120)changes slowly
Turnover vs Decay tradeoff (documented):
| Decay | Turnover | Annual Returns | Sharpe |
|---|---|---|---|
| 0 (no decay) | High | 14%+ | 1.8+ |
| 5 | Medium | 10–12% | 1.5–1.7 |
| 30 | 8.99% | 4.29% | 1.2 |
Rule: Use decay 0–5 for high-fitness D0 alphas; use 10–30 for D1 alphas to meet lower thresholds.
PART 6 — PORTFOLIO SUBMISSION STRATEGY
Maximize Score Through Diversification
Dimension 1: Delay variants
- Submit Delay-0 AND Delay-1 versions of the same alpha
- D0 and D1 are naturally uncorrelated (different execution timing)
- D1 has lower thresholds (Fitness > 1.0, Sharpe > 1.25) — easier to pass
Dimension 2: Geographic variants
- Submit USA and China/CHN versions of same alpha
- China TOP3000 often achieves higher Sharpe (less efficient market)
- USA and CHN are uncorrelated by geography
Dimension 3: Universe size
- TOP200: highest margin (100‱+), lowest diversification
- TOP500: balance of margin and volume
- TOP1000: medium diversification
- TOP3000: most diversification, lower margin but more stable
Self-correlation rule details:
- Your new alpha is compared ONLY against YOUR OWN previously submitted alphas
- Comparison uses PnL time series correlation over 2-year rolling window
- High correlation is acceptable IF combined portfolio Sharpe improves by ≥10%
- Strategy: submit uncorrelated types (momentum alpha + reversion alpha + fundamental alpha)
Optimal Truncation Settings
0.01when you want maximum diversification contribution to portfolio0.03–0.10for standalone performance
PART 7 — LEADERBOARD & SCORING CONTEXT
| Threshold | Points | Meaning |
|---|---|---|
| Fitness > 1.0, Sharpe > 1.25 (D1) | Submittable | Passes minimum gate |
| Bronze | > 1,000 | Competitive |
| Silver | > 5,000 | Strong competitor |
| Gold | > 10,000 | Interview-eligible for WorldQuant roles |
| Finals (2025) | Top 12 teams | 0.02% of 80,000 participants |
Scale expectation: 100 simulation attempts per submittable alpha is average. One documented participant tested 1,103 alphas and submitted 28. Rejection is normal — iterate every day.
PART 8 — KEY RESOURCES
| Resource | URL |
|---|---|
| 101 Formulaic Alphas (paper) | arxiv.org/pdf/1601.00991 |
| jglazar's submitted alphas (real Sharpe metrics) | github.com/jglazar/notes/blob/main/quant_interview/submitted_alphas.md |
| jglazar's alpha ideas | github.com/jglazar/notes/blob/main/quant_interview/alpha_ideas.md |
| 50 WorldQuant alphas that pass correlation together | github.com/jingmouren/CrisperX-50_WorldQuant_Alpha_Examples_for_Alphathon |
| All 101 alphas implemented in Python | github.com/yli188/WorldQuant_alpha101_code |
| QuantJourney — combinatory alpha generation | quantjourney.substack.com |
| WorldQuant BRAIN forum | worldquant.com/brain/forum |
| IQC finalist interviews | worldquant.com/ideas (search "IQC finalist spotlight") |