Back to blog

2026.10.31

Ten strategies with zero edge, backtested for 3 years, and the winner averages a Sharpe of 0.89: how many tries were behind that backtest screenshot?

I built a random-walk market where nobody can make money and ran the 'have an AI write 10 strategies, keep the top 3' workflow in it 20,000 times. How much Sharpe luck hands you is a single division; the first number I gave was too high; and you can work backwards from someone's screenshot to how many things they tried.

quantbacktestingstatisticsoverfitting

A 56-second quant tutorial was making the rounds on a Chinese social app: 753 likes, 1,726 saves. The recipe: ask an AI to list "the 10 best quant strategies in the world," have it write the code, backtest all of them, keep the top three, then "optimize and iterate from different angles." Congratulations, that's your system.

I didn't test it on real market data. I built a market where nobody can make money, by construction: the price is a pure random walk, so tomorrow's move has nothing to do with anything that came before. Then I ran the whole recipe in it 20,000 times.

Ten strategies with zero skill, backtested over 3 years. The winner's annualized Sharpe averaged 0.89, and it beat 1.0 in 35% of runs. Take the top three into the following year of fresh data and their average Sharpe is 0.00.

Sharpe is just "how much return you get for each unit of volatility you sit through." An annualized 1.0 is the kind of number retail traders happily post screenshots of. In a market where nobody can win, you get one just by picking the best of a handful.

The fun part: the 0.89 I first quoted was too high, and section 2 explains why. If you only want the formula, read section 1; if you want a tool for picking apart other people's screenshots, read section 4.

1. How much Sharpe luck gives you: one division

A strategy with zero edge produces a backtest Sharpe that wobbles around 0. How far it wobbles depends only on how many years you backtested:

std. dev. of one zero-edge strategy's backtest Sharpe ≈ 1 ÷ √(years)

With 3 years that's about 0.58. In plain terms, a strategy with no skill at all throwing up a 0.6 over a 3-year backtest is completely unremarkable.

Try N of them and keep only the best, and what you should expect is "the expected maximum of N standard normals" times that standard deviation:

luck Sharpe ≈ E[max_N] ÷ √(years)

You don't need to derive E[max_N]. Look it up:

Total tries N E[max_N]
1 0
3 0.85
10 1.54
30 2.04
100 2.51

Now plug in: 10 strategies, 3 years, 1.54 ÷ √3 = 0.89. The 20,000-run simulation also lands on 0.89. It really is just a division.

I varied N and the number of years and put the simulation next to the formula:

N Backtest years Simulated: mean Sharpe of winner Formula Share of runs where winner > 1 Top 3's Sharpe the next year
3 3 0.49 0.49 12% 0.00
10 1 1.54 1.54 82% 0.00
10 3 0.89 0.89 35% 0.00
10 10 0.49 0.49 1% 0.00
30 3 1.18 1.18 72% -0.01
100 3 1.45 1.45 99% 0.00
100 10 0.79 0.79 8% 0.00

The last column is all zeros, which it has to be: there's nothing to earn in this market. The columns before it are the interesting ones. Two things there surprised me:

  • More tries buy you surprisingly little. Going from 10 tries to 100 only moves E[max] from 1.54 to 2.51. Flip that around and "I only tried three or four" isn't reassuring either. Three tries already hand you 0.85 ÷ √years for free.
  • A longer backtest protects you more than trying fewer things. Best of 100 over 10 years gives a luck Sharpe of 0.79. Best of 10 over 3 years gives 0.89. The first tried ten times as many strategies and is still harder to fool.

2. My first number, 0.89, was too high

When I first watched that video, the conclusion I jotted down was "best of 10 random strategies, average Sharpe 0.89." The arithmetic was fine. The model cut a corner: it assumed the 10 strategies were independent, each wobbling on its own.

The 10 strategies in the video are moving-average crossovers, momentum, turtle-style breakouts and the like, all staring at the same price chart. Two crossover rules whose windows differ by a few days give the same signal on most days. That's nowhere near 10 independent lottery tickets.

So today I added a run. On one random-walk price series I ran 10 actual rules: 4 moving-average crossovers, 3 momentum, 3 mean-reversion. The average absolute correlation between their daily returns was 0.37. Results:

  • Winner's in-sample Sharpe averaged 0.79 (the independent model said 0.89)
  • Winner beat 1.0 in 26% of runs (independent model: 35%)
  • Top three the next year: 0.00

0.79 × √3 = 1.38. Look that up in the E[max] table and it sits near N = 7 (seven tries gives 1.35). Ten rules were worth about seven draws.

Then I tried the video's "optimize and iterate" step. One moving-average crossover, 10 fast windows by 10 slow windows. Drop the combinations where the fast window isn't shorter than the slow one and you have 89 parameter sets. Run them all, keep the best in-sample. Gut feeling says that's 89 tries and should look terrifying.

The winner averaged 0.83, beat 1.0 in 34% of runs, and scored 0.00 the next year. 0.83 × √3 = 1.45, roughly the same as the best of 8 or 9 independent tries.

So one word in the formula has to change. N is the effective number of tries, which is different from how many times you hit Enter. Neighboring cells in a parameter grid are basically the same strategy, so 89 runs were worth eight or nine.

Don't celebrate yet. This also means you can't count your own effective N. I can say "about 7" or "about 8 to 9" only because I ran this in a fake market where I know the answer. A real backtest gives you no such reference. The only safe move is to count raw tries, which is guaranteed to be an upper bound.

3. One year out of sample won't save you

The video's last step is "paper trade first, go live once it's stable." Right direction. The problem is the duration.

Run the formula from section 1 backwards. With one year out of sample, a single strategy's Sharpe has a standard deviation of 1 ÷ √1 = 1. In my simulation, "the top three's average Sharpe the next year" has a standard deviation of 0.58, which is exactly 1 ÷ √3 from averaging three of them. It checks out.

To separate a strategy with real skill from luck at two standard deviations, you need roughly this many years:

years of out-of-sample needed ≈ (2 ÷ true Sharpe)²

True Sharpe of 0.5: 16 years. True Sharpe of 1: 4 years. A month or two of paper trading proves exactly one thing, which is that your order code isn't broken.

There's another layer. The 0.00 is an average over 20,000 runs. Pick any single run and the top three post a Sharpe above +0.58 the next year roughly one time in six. Whoever owns that run concludes "it held up out of sample too" and puts real money in.

4. Picking apart a screenshot: work back to the number of tries

Someone posts a screenshot: "3-year backtest, annualized Sharpe 1.0."

Multiply the Sharpe back by √years: 1.0 × √3 = 1.73. Find that in the E[max] table and you land around 15. In a market with no edge at all, trying about 15 independent strategies gets the winner this score on average.

A few more, all from the same table:

  • 1-year backtest, Sharpe 1.0 → 1.0, about 4 tries
  • 1-year backtest, Sharpe 2.0 → 2.0, about 28 tries
  • 3-year backtest, Sharpe 1.5 → 2.6, about 130 tries
  • 10-year backtest, Sharpe 1.0 → 3.16, out of reach even with 300 tries

That last line is good news: a high Sharpe over a long backtest is hard to stumble into by brute force. The combination to watch for is short backtest + high Sharpe + no word on how many things were tried.

Having an AI write strategies makes this worse. Hand-writing 10 strategies used to take a week. Getting an AI to spit out 10 takes a minute. Trying got cheap, and the luck Sharpe didn't get any discount.

So ask two questions before you look at the screenshot. How many years? How many things did you try in total, parameter combinations included? If they can't answer the second one, assume at least a few dozen.

5. Where this simulation can't be trusted

  • Returns are normally distributed, with no fat tails and no volatility clustering (big drops arriving in bunches). Real markets have fat tails, so a single strategy's Sharpe wobbles more and the luck Sharpe can only be higher. I didn't test this.
  • I tried exactly one cost level: 5 basis points per unit of turnover. With that, the 10-rule winner's in-sample Sharpe fell from 0.79 to 0.67, and the top three's next-year Sharpe went from 0.00 to -0.10. You keep the luck and you still pay the costs, so out of sample turns negative. I didn't run other cost levels.
  • The video's actual recipe is "10 strategies, then tune each one." I didn't run that combination. By the estimates above, its effective N falls somewhere between 7 and 7 × 9. I don't know where.
  • The simulation proves one thing: the "keep the top three" procedure can't tell good from bad in a world with zero edge. It does not prove those classic strategies have no edge in real markets.
  • "10 rules ≈ 7 tries" and "89 parameter sets ≈ 8 to 9 tries" were both estimated at one volatility level on one kind of random walk. On a trendier series the correlations between rules change, and so do those two numbers.

6. Next time you backtest, go in this order

  1. Count your total tries first. Parameter combinations count. Drafts the AI wrote that you threw away count too.
  2. Compute the luck Sharpe as E[max_N] ÷ √years. Only what's left after subtracting it is worth looking at.
  3. If the backtest is short, ignore the decimals. Over 3 years one standard deviation is ±0.58, and anything in that range could be wobble.
  4. Size your out-of-sample period with (2 ÷ expected Sharpe)². If you can't wait that long, admit you're only testing the plumbing.
  5. Rerun with costs charged on actual turnover. If it goes negative, drop it.
  6. To learn your own effective N, run your entire workflow unchanged on a random walk and see what the winner scores. It's ten minutes of work, and the snippet below is a starting point:
import numpy as np
rng = np.random.default_rng(1)

# 10 zero-edge strategies, 3 years of daily returns, keep the best in-sample Sharpe
trials, N, days = 20000, 10, 252 * 3
r = rng.normal(0, 0.01, (trials, N, days))
sr = r.mean(-1) / r.std(-1) * 252 ** 0.5
best = sr.max(1)
print("winner mean Sharpe", best.mean().round(2), "share above 1", (best > 1).mean().round(3))

# E[max_N] table: turns Sharpe × √years back into N
z = rng.standard_normal((100000, 300))
emax = np.maximum.accumulate(z, axis=1).mean(0)
for n in (3, 10, 30, 100, 300):
    print(n, emax[n - 1].round(2))