Multiplying signals, and the real rules of the scoreboard
A public record of building up "submittable alphas" to raise my score on the quant trading platform WorldQuant BRAIN. In part 3, I built my first submitted alpha out of mean reversion in price-to-cash-flow (pcf) and cleared the gate. This time, I hunted for a second alpha and checked firsthand how the scoreboard actually works. And I learned the real weight behind the rule that only one look-alike alpha gets through.
0. One-line summary
Instead of adding a weak signal orthogonal to the validated one (pcf), I multiplied them, and Sharpe jumped from 1.57 to 1.91. The intersection of stocks that are "cheap while the earnings outlook is being revised upward" became my second submitted alpha. And when I opened up the scoreboard, the rumor I'd heard, that "only one alpha counts toward your score per day," turned out to be wrong; the real rule was something else entirely. My first score was Bronze, 1,854 points.
1. Starting point: I passed the gate, but the score was nowhere to be seen
In part 3, I submitted pcf. It was an alpha that had cleared all 8 gates. But once I'd actually submitted it, I had no idea what was showing up on the scoreboard or how. Each alpha gets a grade, but it wasn't even clear whether that was the same thing as the competition score or something different. Without knowing the scoring rules, I couldn't judge "which alpha to submit when for maximum advantage." So this session had two goals: find a second alpha that didn't resemble pcf, and verify how the scoreboard actually worked using real data.
First, I went alpha hunting. At the end of part 3, I had a priority queue of 34 candidates built by 17 agents. I couldn't simulate all the strong-looking candidates at once. This account can run only one simulation at a time, so I had to line the queue up and go through it serially.
2. Working through the queue serially: alone, every signal was weak
I ran the queue's candidates one by one. Here are the results, by signal axis. The key point is what data I pulled, how, and what signal I turned it into.
- Analyst estimate revisions (
analyst4): I pulled analysts' consensus EPS estimates and divided their change by the dispersion (variance) across estimates, a signal meant to capture stocks where "the outlook is being revised upward and analysts agree." Standalone Sharpe 0.4. Weak. - News sentiment (
news18): I averaged Ravenpack's composite sentiment score over several days, aiming for drift. Sharpe 0.02. Essentially zero. - Social sentiment and attention (
socialmedia12): I tried to catch stocks where buzz was cooling off, as a counter-trend play. It sometimes came out negative. - Corporate relationship lead-lag (
pv13): I targeted information diffusion where a supplier follows once its customers' average return has already risen. The sign came out reversed, putting it in loss territory.
Not a single candidate in the whole queue cleared the gates on its own. The only strong one was the option call-put implied-volatility spread I'd already met in part 3 (Sharpe 1.83), but that was a card I'd set aside because it was concentrated overfitting that collapsed in the sub-universe. Every orthogonal signal was weak on its own. This was the wall in this hunt. There were plenty of signals that didn't resemble pcf, but the ones that didn't resemble it were weak.
3. Breakthrough: don't add, multiply
I'd learned something in part 2. Adding a weak signal to a validated one at equal weight doesn't diversify, it dilutes. The strong signal got dragged down by the weak one. So this time, instead of adding, I decided to try multiplying.
Addition and multiplication mean different things. Addition means "bet if either one is strong," so the weaker side adds noise. Multiplication means "bet only when both point the same way," which creates an intersection. If you convert both signals into per-stock ranks and then multiply them, only stocks that rank high on both sides survive; a stock that's high on only one side gets suppressed.
The partner I chose to multiply by was the change in analysts' EPS estimates. pcf looks at "has the price-to-cash-flow ratio gotten cheap relative to its own history." I multiplied that by "are analysts revising the earnings outlook upward."
rank( -ts_zscore(cap / cashflow_op, 63) )
× rank( ts_delta( ts_backfill(anl4_fs_detail_estimates_basic_af_v4_nd_eps_mean, 120), 66 ) )
anl4_fs_detail_estimates_basic_af_v4_nd_eps_mean is the analyst consensus EPS estimate. Since this data updates only sporadically on a quarterly basis, there are many empty days, so I filled in the last value with ts_backfill and used ts_delta to look at the change relative to 66 trading days (about one quarter) earlier. If this is positive, it means the outlook is being revised upward.
What this multiplication targets is a value trap filter. Sometimes a stock looks cheap because it's actually going under, and analysts are cutting their outlook on names like that. Conversely, a stock that "has gotten cheap, yet the outlook is actually being revised upward" is more likely to be genuinely undervalued. The intersection of cheap and improving. Multiplication pinpointed exactly that intersection.
The result was Sharpe 1.91, Fitness 1.6. Clearly higher than pcf alone (1.57). Adding had diluted it, but multiplying made it stronger. The strategy of multiplying an orthogonal signal into a validated base hit exactly as intended.
4. Clearing the second gate
I ran the server's 8 checks again. All of them passed. Turnover was low at 11.3% (since it's a fundamental signal, it naturally changes slowly), and the sub-universe Sharpe was also solid at 1.61. This wasn't an alpha that only happened to work in the broad market.
The most important gate was self-correlation. The second alpha couldn't be too similar to the first one (threshold under 0.7). Measuring how similar it actually was to pcf gave 0.61. Even though it used the same cash flow ingredient as its base, the multiplied-in analyst signal was different enough that the whole thing moved away from pcf. Under 0.7, so it passed. The second submitted alpha (cau_pcfleg) was locked in.
rank(-ts_zscore(cap / cashflow_op, 63)) × rank(ts_delta(ts_backfill(...eps_mean, 120), 66))
USA / TOP3000 / delay 1 / decay 4 / industry neutralization / weight cap 2%
→ Sharpe 1.91, Fitness 1.6, turnover 11.3%, sub-universe 1.61, self-correlation with pcf 0.61, 8/8 passed
5. Opening the scoreboard: the rumor was wrong
Now for the second goal: how the score is actually calculated. I'd vaguely assumed that an alpha's grade was the same as the score, but querying the score directly showed that wasn't the case. The competition scoreboard was a separate thing entirely.
Here's the rule set I confirmed.
- The score is cumulative and never decreases. Once accumulated, it stays. Level is determined by cumulative score. Above 1,000 points is Bronze, above 5,000 is Silver, above 10,000 is Gold. Crossing Gold makes you eligible for a Consultant invitation.
- There's a daily cap on the score. Only about 2,000 points come in per day, updated at 3 AM US Eastern time. No matter how many good alphas you cram in above that, the excess is discarded.
- Scoring works per day, not per alpha. The rumor I'd heard, that "only one alpha counts toward your score per day," was wrong. All the alphas submitted that day jointly make up that day's score. The score rises the more alphas you submit (quantity) and the higher the average quality of that day's alphas.
This "average quality" thing is subtle. Submitting a weak alpha alongside a good day's batch drags down that day's average, a net loss. But cramming several strong alphas into a single day gets clipped by the 2,000-point cap. So the conclusion is: spread strong alphas across different days, and don't mix a weak alpha into a good day. I also confirmed that the score itself doesn't wait for future data (out-of-sample); it's applied immediately at the next update after submission.
The levers for boosting quality also became clear. The score rises the stronger the sub-universe result, the lower the self-correlation, and the higher the Fitness. Self-correlation in particular doesn't stop mattering once you clear the 0.7 pass threshold; the lower it is, the more it keeps working in your favor on the score. The upper pool (Power Pool) demands self-correlation of 0.5 or below outright. Collecting alphas that don't resemble each other wasn't just a matter of passing the gate, it was a matter of score too.
My first score posted. Bronze, 1,854 points. pcf alone had nearly filled the daily cap on its own. The second alpha's score was set to land at the next day's update.
6. Only one look-alike alpha: the trap of the cau family
Riding the momentum of the second alpha, I went after a third. Since multiplication had worked, I figured I could just make one more similar multiplication. I built a variant (cau_rev132) that multiplied EV/EBITDA mean reversion by the same analyst signal. Measuring self-correlation gave 0.42, which looked like a comfortable pass.
But there was a trap. That 0.42 had been measured before submitting the second alpha. After I formally submitted the second alpha and measured again, the third candidate's self-correlation had spiked to 0.83. A failure well past the pass threshold.
The reason was clear. The second and third alphas shared the same analyst revision signal (the revision leg) as their multiplication partner. Only the base (pcf or EV) differed; the multiplied side was the same, so the two were effectively cousins. The moment I submitted the second one, the third one that resembled it got blocked.
Here the bigger picture came into view. pcf, and the cau family formed by multiplying it with analyst revisions, were so similar to each other that alphas #1 and #2 had already saturated it. Making another one from this family runs into the self-correlation wall. The third alpha needs to be found outside this family, in a genuinely different signal that is neither price nor analyst revision. That became the homework for the next part.
7. What I learned this time
- Addition and multiplication are different weapons. Adding a weak orthogonal signal dilutes; multiplying it reinforces the intersection. Multiplying into a validated base was what raised Sharpe.
- Scoring works per day. It's not a single alpha but the quantity and average quality of the alphas submitted that day that make up the score. Split strong alphas across days, and don't dilute a good day with a weak alpha.
- Self-correlation isn't only about passing the gate. The lower it is, the more it keeps benefiting the score too. Collecting alphas that don't resemble each other is itself the path to accumulating score.
- Look-alike alphas block each other. Sharing the same multiplication partner makes them cousins even with different bases. Submitting one closes off the rest. So you submit only one per family, and go looking for the next one in a genuinely different family.
- Re-measure correlation after submitting. A candidate that looked like a pass before submission can get blocked right after submission. The baseline is "the alphas I've already submitted," which makes it a moving target.
In the next part, I hunt for a third signal outside the pcf family, one that uses neither price nor analyst revisions. It's the hardest installment yet, discovering a new alpha that's dissimilar yet strong and robust.
Technical notes (appendix)
- Submitted alpha #2 (cau_pcfleg):
rank(-ts_zscore(cap / cashflow_op, 63)) * rank(ts_delta(ts_backfill(anl4_fs_detail_estimates_basic_af_v4_nd_eps_mean, 120), 66)), USA/TOP3000/delay1/decay4/INDUSTRY/truncation0.02. Sharpe 1.91, Fitness 1.6, turnover 0.113, sub-universe 1.61, self-correlation with pcf 0.61. All 8 server checks PASS. Grade GOOD. - Multiplication vs. addition: Addition (
a + w*b) is closer to OR, so a weak signal adds noise (a Fitness ceiling of 0.96 in part 2). Multiplication (rank(a) * rank(b)) is AND, leaving only stocks strong on both sides simultaneously. pcf (1.57) × revision = 1.91. - Revision leg:
ts_delta(ts_backfill(eps_mean, 120), 66). Since it updates quarterly there are many missing values, sots_backfill(120)carries the last value forward, and the 66-trading-day change measures "being revised upward." Its turnover is low, so even after multiplying, overall turnover stays at 11.3%. - Score (Challenge) rules: Queried via leaderboard{rank, level, score, alphas} from
GET /competitions/challenge. Daily cap of about 2,000 points, updates at 3AM US Eastern, cumulative and never decreases. Per-day (quantity + average quality of that day's alphas), not per-alpha. Quality levers = sub-universe↑ / self-corr↓ / Fitness↑ / decay1>decay0. Power Pool requires self-corr ≤ 0.5. Score doesn't wait for out-of-sample; it's applied on an in-sample basis at the next update after submission. Levels = Bronze>1,000 / Silver>5,000 / Gold>10,000 (cumulative), Gold+10,000 → eligible for Consultant invitation. - Current status: BRONZE, 1,854 points, rank 35,958 (as of when only pcf had been reflected). Alpha #2 was set to be added at the next update.
- Alpha #3, cau_rev132 (rejected):
rank(-ts_zscore(enterprise_value/ebitda, 63)) * rank(<same revision leg as #2>). Sharpe 1.33, Fitness 1.1, good standalone metrics, but after submitting #2, self-corr spiked from 0.42 to 0.83, FAIL. Caused by sharing the same revision leg. The pcf/cau family was saturated by alphas #1 and #2. - Self-correlation as a moving target: since self-corr is measured against "the alphas I've submitted," the reference set changes every time a new alpha is submitted. Even if a candidate looks like a pass before submission, re-measuring right after submission is essential.