Alphas: a formula, a universe and a test of whether it worked
On this page
The indicators post ended with a warning: an indicator is a number, not a trading rule, until a threshold and a position are added. Quantitative trading has a word for the step in between. An alpha is a formula that takes today’s data and produces a forecast of future return, one number per stock per day, before anyone decides what to hold. In 2015 Zura Kakushadze published 101 of them, proprietary to WorldQuant and 80 of them in production at the time, as formulas that are also code, with the holding periods and correlations that go with them. This post reads that paper, computes two of its simplest alphas on the blog’s five tickers (SPY, AAPL, JPM, XOM, GLD, 2019 to 2023), and then does the thing the paper’s abstract keeps pointing at: tests whether they worked.
What an alpha looks like
The paper’s footnote 4 gives the trader’s definition: “a combination of mathematical expressions, computer source code, and configuration parameters that can be used, in combination with historical data, to make predictions about future movements of various financial instruments”. The word means expected return, roughly, not the academic alpha of the beta post, and the paper is explicit that the two are not the same.
Section 2 says what the 101 are made of. Almost all are price-volume: daily close-to-close returns, open, close, high, low, volume and the volume-weighted average price. A few use market cap or an industry classification. And “very coarsely”, the list is built from two opposite ideas. A mean-reversion alpha has the opposite sign to the return it is based on: the simplest example in the paper is minus the log of today’s open over yesterday’s close, the hope being that a stock that gapped up overnight gives some of it back. A momentum alpha has the same sign: the log of yesterday’s close over yesterday’s open, the hope being that a stock that ran up during the day keeps going. Complex alphas mix the two.
The paper also attaches a timing label to each formula. A delay-0 alpha is traded at the time of the latest data it uses (the open-over-close example is meant to be traded at today’s open). A delay-1 alpha is traded the day after its latest data; most of the 101 are delay-1. That label is not decoration. It says whether the forecast could actually have been acted on.
Section 3 reports what the 101 did in production between January 2010 and December 2013. Their average holding period runs from 0.6 to 6.4 days. Their average pairwise correlation is (median 14.3%): a hundred formulas, mostly saying different things. Their returns rise with their volatility and do not depend on how often they trade. And the introduction’s first paragraph names the two trends the whole list sits inside: more people mining alphas produces “ever fainter and more ephemeral alphas”, while automation produces ever more of them, so that what is actually traded is a combination of hundreds of thousands, a “mega-alpha”, not any single formula.
An alpha is a forecast, and a forecast is a tendency. It is wrong on many individual days and is only judged over a sample, at its own horizon. The question is never “did it work yesterday” but “over a thousand days, did the ones it liked do better than the ones it did not”.
Two of the 101, from closes only
The blog’s data has closes and nothing else, which rules out most of the list. Two of the
simplest survive. Alpha#9 in Appendix A reads, in the paper’s notation,
(0 < ts_min(delta(close, 1), 5)) ? delta(close, 1) : ((ts_max(delta(close, 1), 5) < 0) ? delta(close, 1) : (-1 * delta(close, 1))),
where delta(close, 1) is today’s close minus yesterday’s and ts_min(x, 5) is the smallest
value of x over the past five days. In words:
s, the signald, today's close minus yesterday's
Five rises in a row, or five falls: keep today’s move, a momentum bet. Anything mixed: flip
today’s move, a mean-reversion bet. Alpha#10 is the same expression with a four-day window,
wrapped in rank(...), the paper’s cross-sectional rank: each day, line up every stock in the
universe by its signal and replace the value with its position in the line.
Here is one day, 2022-06-17, for the inside of Alpha#10 and its rank:
| Ticker | Close | Today’s move | 4-day min | 4-day max | Signal | Rank |
|---|---|---|---|---|---|---|
| SPY | 345.95 | +0.74 | −11.82 | +5.02 | −0.74 | 0.4 |
| AAPL | 128.86 | +1.47 | −5.26 | +2.62 | −1.47 | 0.2 |
| JPM | 101.18 | −0.36 | −1.77 | +1.21 | +0.36 | 0.6 |
| XOM | 74.82 | −4.58 | −4.58 | +0.22 | +4.58 | 1.0 |
| GLD | 171.27 | −1.42 | −1.42 | +2.20 | +1.42 | 0.8 |
No ticker had four one-way days, so every row is in the “otherwise” branch and the signal is minus today’s move. XOM fell $4.58, so the alpha likes it most (it expects a bounce); AAPL rose $1.47, so the alpha likes it least. That is the usual day. Over the five years, the five-rises branch fires on about 4% of days per ticker and the five-falls branch on 1 to 3%, so Alpha#9 is a one-day reversal bet on more than 92% of days, with a momentum exception for runs.
Time-series versus cross-sectional
The two alphas differ in what their number means, and that decides how each is tested.
Alpha#9 is a time-series signal. Its value is in dollars per share and compares a stock with its own history: +4.58 for XOM says “bounce expected”, and it would say so whether or not any other stock existed. Every stock in the universe can get a positive signal on the same day, and holding all of them means being long the market.
Alpha#10 is a cross-sectional signal. The rank compares stocks with each other on one day, and the units are gone: XOM’s +4.58 becomes 1.0 and GLD’s +1.42 becomes 0.8, the same gap as between GLD and JPM’s +0.36 even though the dollar gaps are $3.16 and $1.06. A rank keeps the order and throws away the spacing. Its scale does not depend on AAPL trading at $129 and GLD at $171, as the raw signal’s does, and it is immune to one wild value. The forecast it makes is relative: “XOM will do better than AAPL”, not “XOM will go up”. A stock can have a positive raw signal and still rank at the bottom.
A ranked alpha forecasts order, not size. The top of the list is expected to beat the bottom. Whether either goes up is a separate question the rank does not answer.
The test: correlation with what came next
The paper gives the formulas and the production statistics. It does not, and cannot, say whether Alpha#9 works on five tickers in 2019 to 2023. The standard test is the information coefficient, which Romero and Balch define as the correlation between a manager’s predictions and the actual future prices: 1 for a perfect forecaster, −1 for a perfectly wrong one.
IC, the information coefficient; s, the signalr, the return over the next h days
The correlation here is the rank kind: whether the days (or stocks) the signal liked more tended to return more, regardless of units. For Alpha#9 the pairing is each ticker against its own future, five correlations averaged. For Alpha#10 it is the five tickers against each other on each day, 1,257 daily correlations averaged. The return runs from today’s close to the close h days later, which treats both alphas as if they were traded at today’s close.
| Days ahead | Alpha#9, each ticker against its own future | Alpha#10, ranked across the five |
|---|---|---|
| 1 | 0.012 | 0.008 |
| 2 | 0.023 | 0.019 |
| 3 | 0.012 | 0.004 |
| 5 | 0.008 | −0.005 |
| 10 | 0.018 | 0.009 |
| 20 | 0.010 | −0.005 |
Every number is a few hundredths from zero. The sign is right (positive) at short horizons, and the ranked version is lower and crosses zero by five days. That is the shape of a faint signal: not nothing, not much. The second question is whether even that held up:
| Year | Alpha#9, 1 day | Alpha#10, 1 day |
|---|---|---|
| 2019 | 0.024 | 0.022 |
| 2020 | 0.097 | 0.027 |
| 2021 | −0.003 | 0.021 |
| 2022 | −0.030 | −0.015 |
| 2023 | −0.017 | −0.016 |
The five-year is over 2019 to 2021 and over 2022 to 2023. One year, 2020, carried it, which is the year of the sharpest one-day moves in the sample and the year a “flip today’s move” bet pays best. The last two years went the other way. A signal with these numbers was never tradeable on five tickers, and the paper would not have expected it to be: its own example of a universe is a dollar-neutral portfolio of the 2,000 most liquid US stocks, where a tiny edge per name adds up across thousands of names and days. Five names do not give a tiny edge room to add up.
Test at the signal’s own horizon, then test again on time it has not seen. An alpha with a positive five-year number and a negative last-two-years number is a finished alpha, not a working one.
Why 101 of them, and not one
The two alphas here share their inputs, and it shows. The rank correlation between Alpha#9’s signal and the inside of Alpha#10 (the same rule with a four-day window) is , and between Alpha#9 and plain “minus today’s move” it is . Three formulas, one idea. Combining them adds almost nothing, because when one is wrong the others are wrong on the same day.
That is the point of the paper’s 15.9%. A hundred alphas with an average pairwise correlation of 0.16 are, roughly, a hundred different bets, and a combination of different bets is where the “mega-alpha” gets its edge and its smoother returns: when some go bust in a period, the others do not go with them. The introduction adds the practical bonus, that trading a combination lets opposite orders cancel inside the book before they reach the market, saving on costs. A hundred variants of one-day reversal would give none of this. The question to ask of a new alpha is not “is it good” but “what does it add to the ones I have”, and a correlation of 0.87 answers it.
Traps
| People think | Actually |
|---|---|
| A ranked score says how much a stock will return | it says which stocks are expected to beat which; order only |
| A positive forecast means buy | in a ranked signal a positive value can still sit at the bottom of the list |
| An alpha that is positive over five years works | split the years; 0.046 then −0.028 is a signal that stopped |
| A tiny IC is useless | on 2,000 names, a tiny edge per name per day is the business; on five names it is noise |
| Two formulas are two signals | if they share inputs they share mistakes; 0.87 correlation is one signal |
| Delay-0 and delay-1 are details | they say whether the forecast could have been traded at all |
The code
The snippet reproduces Alpha#9 and its 1-day information coefficient, for the five years and for the two halves. Variables:
| Variable | Holds |
|---|---|
d1 | today’s close minus yesterday’s, per ticker (delta(close, 1) in the paper) |
alpha9 | today’s move if the last five days all rose or all fell, minus it otherwise |
fwd1 | the return from today’s close to tomorrow’s |
ic(years) | the rank correlation of the signal with that return, per ticker, averaged |
import pandas as pd
url = "https://raw.githubusercontent.com/ankurtrapasiya/examples/main/data/prices.csv"
px = pd.read_csv(url, index_col="date", parse_dates=True)
d1 = px.diff() # delta(close, 1): today's close minus yesterday's
lo, hi = d1.rolling(5).min(), d1.rolling(5).max()
alpha9 = d1.where(lo > 0, d1.where(hi < 0, -d1)) # five rises or five falls: keep the move; else flip it
fwd1 = px.shift(-1) / px - 1 # the return from today's close to tomorrow's
def ic(years):
out = []
for t in px.columns: # each ticker against its own future, then average
both = pd.concat([alpha9[t], fwd1[t]], axis=1).dropna()
both = both[both.index.year.isin(years)]
out.append(both.corr(method="spearman").iloc[0, 1])
return sum(out) / len(out)
print("IC 2019-2023", round(ic(range(2019, 2024)), 3))
print("IC 2019-2021", round(ic([2019, 2020, 2021]), 3))
print("IC 2022-2023", round(ic([2022, 2023]), 3))
It prints 0.012, 0.046 and −0.028. d1.where(lo > 0, other) keeps d1 where the condition
holds and takes other elsewhere; nested twice, it is the paper’s ? : written in pandas.
The script behind the real numbers
The tables and the chart come from
examples/alphas-formula-universe-test/alphas.py,
which runs on the blog’s five tickers. To run it yourself, clone the examples repo: its README has a three-command Docker setup, or run uv run alphas-formula-universe-test/alphas.py.
Summary
| Idea | In one line | On the five tickers |
|---|---|---|
| Alpha | a formula from today’s data to a forecast of return, one number per stock per day | Alpha#9: flip today’s move unless it is a five-day run |
| Mean reversion versus momentum | opposite sign to the past move, or the same sign | the reversal branch fires on over 92% of days |
| Time-series versus cross-sectional | a stock against its own history, or against its peers today | dollars for Alpha#9, a rank of 0.2 to 1.0 for Alpha#10 |
| Rank | keeps order, drops spacing and units | XOM +4.58 and GLD +1.42 become 1.0 and 0.8 |
| Information coefficient | correlation of the forecast with what came next | 0.012 at one day |
| Test on unseen time | the number that matters is the one after the fit | 0.046 then −0.028 |
| Redundancy | signals that share inputs share mistakes | 0.87 between the two alphas; 0.16 across the paper’s 101 |
References
- Zura Kakushadze, 101 Formulaic Alphas (Quantigic Solutions and Free University of Tbilisi,
December 2015). Footnote 4 for the definition of an alpha; section 1 for “ever fainter and
more ephemeral alphas” and the mega-alpha; section 2 for the price-volume inputs, the
mean-reversion and momentum examples (equations 2 and 3) and the delay-0 / delay-1 labels;
section 3 and the abstract for the 2010 to 2013 holding periods (0.6 to 6.4 days), the average
pairwise correlation of 15.9% and the return-volatility link; section 4 for the 80 alphas in
production and the example universe of the 2,000 most liquid US stocks; Appendix A for Alpha#9, Alpha#10 and the definitions of
rank,delta,ts_minandts_max. - Philip J. Romero and Tucker Balch, What Hedge Funds Really Do (Business Expert Press, 2014). Chapter 9, “A Few Definitions”, for the information coefficient as the correlation between predictions and actual future prices.