← All Articles
An abstract field of soft green and gold light drifting over a scatter of points, standing in for the 222,010 backtests behind the ranking.

NexusTrade · Research · 222,010 backtests

The best and worst trading indicators, ranked across 222,010 backtests. The top 4 are not what you expect.

I ranked all 93 indicator types on the platform by median Sharpe ratio, then went after the harder questions a corpus this size makes answerable.

Austin Starks Austin Starks ✦ Founder, NexusTrade ✦ September 7, 2026 ✦ 9 min read

In November 2025 I ranked every indicator across 114,549 backtests and published what I found. The corpus has since grown to 222,010, so I ran it again. The top of the list is not where most people would look for it.

Previously · I Analyzed 100,000 Backtests to Find the Best Trading Indicator. The Answer Was Not What I Expected

The headline result

The four best-performing indicator types are not indicators. PortfolioValue, MaxDrawdown, PositionValue and PositionPercentChange all describe the state of the position you already hold, not the shape of the price line.

Nothing in the top four is a chart pattern. The best risk-adjusted returns came from strategies that checked their own position before acting. Read that as a fact about the people who write these strategies as much as about the indicators: nobody was randomly assigned a rule, and someone reaching for MaxDrawdown is already thinking about risk. This is a survey of what worked for whoever wrote it, not an experiment.

What "enough data to rank" means

The corpus contains 93 observed built-in indicator types. Most of them are useless for ranking, because a type used in nine backtests tells you about nine people, not about the indicator.

So there is a reliability floor: a type only enters the ranking once it appears in at least 500 backtests. That cuts 93 down to 34. The other 59 are reported in the full table but never used to make a claim.

Everything is a median Sharpe ratio across traded, hand-authored backtests lasting 365 to 2,000 days. Optimizer-generated runs are excluded, because a genetic search is a population of attempts rather than strategies anyone chose to keep. That exclusion alone removes 74,518 runs.

Observed types

93

built-in indicators

Clear the floor

34

500+ backtests each

Backtests

222,010

traded, hand-authored

All 34 types that clear the floor

MEDIAN SHARPE · 34 TYPES WITH 500+ BACKTESTS · 95% BOOTSTRAP INTERVAL01PortfolioValue1.2443,15002MaxDrawdown1.1211,63703PositionValue0.92731,96904PositionPercentChange0.92714,83905Multiply0.8634,54706OptionGrossExposurePercent0.8591,52907Value0.851117,72308DaysSinceLastRebalanceOptionOrder0.7422,38509PriceRateOfChange0.7305,13210DaysSinceStrategyFired0.71393411IndicatorSimpleMovingAverage0.6731,15312ExponentialMovingAverage0.6462,13713SimpleMovingAverage0.64321,63414DaysSinceOrder0.64044,13815MinutesUntilClose0.6301,49916Price0.60216,95217OptionPositionCount0.6002,31518Index0.5294,16819Day0.45584220Divide0.41172421PriceStandardDeviation0.40868122DaysSinceOptionOrder0.4021,29423RelativeStrengthIndex0.3738,62624Plus0.35385025IndicatorRateOfChange0.34774826Minus0.3301,59827DaysSinceAgent0.26550728BollingerBand0.1981,10729Fundamental0.10161830OptionSpreadCount0.0944,36031CrossAbove0.0451,36432CrossBelow0.02791333PositionMaxDrawdown-0.09496234MinutesAfterOpen-0.571600◆ portfolio state △ operator ○ timing (unmarked) chart signal0backtests
Every type that cleared the 500-backtest floor. Whiskers are 95% bootstrap intervals on the median. Where they overlap, the ordering between those rows is not resolved by this sample. Marks separate the kinds of thing being ranked: many rows are portfolio-state readings or DSL operators rather than chart signals.

One rule is reliably bad

Two types carry a negative median Sharpe, at -0.094 for PositionMaxDrawdown and -0.571 for MinutesAfterOpen, but only one of them survives its own interval. MinutesAfterOpen sits at [-0.694, -0.348] and is genuinely below zero. PositionMaxDrawdown sits at [-0.225, 0.009], so it straddles zero and I cannot tell you it is negative. A negative Sharpe also means returns trailed the risk-free rate once volatility is accounted for, which is not the same as losing money.

MinutesAfterOpen carries one more caveat that cuts against comparing it with the rest: strategies timing entries by minutes after the open are intraday, so they face a different cost and horizon profile than the daily strategies filling most of this table. Some of that -0.571 is the timeframe rather than the rule.

The top four are portfolio state rather than chart signals. They measure how much the portfolio is worth, how far the asset has fallen from its peak, how big the position is, and how far the position is from its cost basis.

Two of those four are closer to one finding than two. PositionValue and PositionPercentChange post an identical 0.927 because they largely appear in the same strategies: 10,407 of the 14,839 backtests using PositionPercentChange also use PositionValue. PortfolioValue and MaxDrawdown are not like that, overlapping in only 72 of 3,150, and both hold their place when I count one observation per portfolio instead of per backtest, at 1.276 and 1.182 across 3,068 and 1,357 distinct portfolios. The top of this table is a top two and a pair.

Show all 93 observed indicator types

Every built-in type observed in the corpus, including the 59 that fall below the 500-backtest floor. Rows in grey are descriptive only: they are too rare to rank fairly, and no claim here rests on them.

All 93 observed built-in indicator types
#IndicatorBacktestsMedian Sharpe
1PortfolioValue3,1501.244
2SumOrderAmount41.135
3MaxDrawdown1,6371.121
4PositionValue31,9690.927
5PositionPercentChange14,8390.927
6MaxDrawup840.923
7CurrentTimeSeconds20.876
8Multiply4,5470.863
9OptionGrossExposurePercent1,5290.859
10IndicatorExponentialMovingAverage3410.852
11Value117,7230.851
12LastOrderPrice4320.769
13IndicatorStandardDeviation490.755
14Month1080.747
15DaysSinceLastRebalanceOptionOrder2,3850.742
16OptionDaysHeld170.738
17PriceRateOfChange5,1320.730
18DaysSinceStrategyFired9340.713
19IndicatorSimpleMovingAverage1,1530.673
20ExponentialMovingAverage2,1370.646
21SimpleMovingAverage21,6340.643
22DaysSinceOrder44,1380.640
23MinutesUntilClose1,4990.630
24Date2060.623
25Price16,9520.602
26OptionPositionCount2,3150.600
27BearishFairValueGap30.581
28TrailingSum130.537
29BuyingPower2130.532
30Index4,1680.529
31Day8420.455
32PreviousClosingPrice90.419
33Divide7240.411
34PriceStandardDeviation6810.408
35Log110.402
36DaysSinceOptionOrder1,2940.402
37StockReport1110.397
38PriceMeanAbsoluteDeviation250.396
39AbsoluteValue670.379
40RelativeStrengthIndex8,6260.373
41Year370.355
42Plus8500.353
43IndicatorRateOfChange7480.347
44OptionPositionValue70.344
45Minus1,5980.330
46DaysSinceEarnings50.288
47DaysSinceAgent5070.265
48PriceChangeSinceOpen2360.233
49MinutesSinceOptionOrder4410.224
50CurrentTimeHours1200.205
51BollingerBand1,1070.198
52OptionPositionPercentChange2180.179
53InitialValue460.175
54CompoundAnnualGrowthRate60.158
55ConsecutiveTrue600.145
56IndicatorMeanAbsoluteDeviation40.137
57Max230.132
58IsIndustry80.130
59Fundamental6180.101
60OptionSpreadCount4,3600.094
61MaximumPrice2430.074
62IsIndexMember150.063
63Economic320.054
64MinutesSinceAgent2480.054
65CrossAbove1,3640.045
66CrossBelow9130.027
67OptionDaysToExpiration27-0.016
68CurrentTimeMinutes152-0.091
69PositionMaxDrawdown962-0.094
70OptionUnrealizedPnL120-0.113
71MinimumPrice184-0.200
72GapPercentage49-0.210
73CountTrue60-0.336
74AverageTrueRange67-0.449
75UnderlyingMaxDrawdown129-0.536
76BullishFairValueGap22-0.541
77MinutesAfterOpen600-0.571
78PositionMaxDrawup50-0.724
79VWAP167-0.732
80DaysSinceAlert53-0.952
81DaysUntilEarnings71-0.994
82IndicatorWindowAgo146-1.148
83OptionPositionMaxDrawdown28-1.158
84IsAsset1-1.200
85IndicatorAtMinutesAfterOpen115-1.332
86Negative24-1.628
87DaysSinceTransaction4-1.858
88MinutesSinceOrder119-2.724
89SumOrderQuantity30-3.031
90HighOfDay9-4.404
91OpeningPrice10-4.650
92LowOfDay4-5.656
93Volume15-13.744

What a corpus this size is actually for

A ranking is a survey. Nobody was randomly assigned an indicator, every strategy here was written by a person who chose their own tickers and rules, and people reach for different tools on different problems. The ordering above tells you where to look, not what causes what.

222,010 outcomes is enough to stop guessing and start testing. Three things become possible here that a smaller dataset cannot support.

1. Run the experiment instead of the survey

Take one strategy, one universe, one window, one rebalance cadence, and change exactly one thing. The indicator goes in, or it comes out. Everything else is held. Run both.

That is a controlled experiment, and it is a backtest sweep the platform already knows how to run. The ranking's job is telling you where to point it. You cannot sweep everything, and 34 candidates ordered by median Sharpe is a very good prior.

2. Go down to the configuration, not the type

An indicator type is not one rule, and treating it as one rule is the weakness of every ranking including this one. A 200-day moving average used as a trend filter and a 3-day moving average used as a trigger share a name and nothing else. They belong at opposite ends of this table, and right now they sit in the same row.

I said in the last piece that I could not answer this, because the lookback column was empty across all 304,426 SimpleMovingAverage rows. The column was empty, and the reason was a bug of mine. The corpus exporter looked for a top-level lookback field. The window is stored at window.length, so the extractor found nothing and wrote a null for all 4,424,078 indicator rows. Nothing failed loudly, because the export succeeded and the column existed. It was simply always empty, and the value was sitting in the same table the whole time, one column over in the raw parameters.

Read correctly, it answers the question, and the answer is no.

THREE NEIGHBOURING TYPESExponentialMovingAverage0.646[0.599, 0.676]2,137SimpleMovingAverage0.643[0.627, 0.645]21,634DaysSinceOrder0.640[0.630, 0.645]44,138SIMPLEMOVINGAVERAGE BY WINDOW · ONE-WINDOW STRATEGIES ONLY20-day0.577[0.507, 0.616]88850-day0.558[0.520, 0.594]2,312200-day0.539[0.497, 0.575]4,6080median · 95% interval · backtests
Counting only strategies that use exactly one moving-average window, because a 50/200 crossover otherwise lands in both rows and makes one population look like two. 64% of the backtests holding a 200-day average also hold a 50-day one.

My first pass at this bucketed every backtest by every window it contained, which counted crossover strategies twice and produced a 0.261 spread I was ready to publish as a finding. Restricted to strategies using a single window, the spread is 0.038 and every pairwise difference straddles zero: a 20-day average beats a 200-day one by 0.045 with an interval of [-0.035, +0.098]. I cannot show you that window length matters.

That is a real answer rather than a failed one, and it cuts both ways. The three neighbouring types are just as unresolved, so the fine structure in the middle of the ranking is mostly noise. What survives is the top of the table, where the intervals are tight and separated, and the bottom, where MinutesAfterOpen is clearly below everything else. Between those, the honest reading is that this survey cannot tell a 50-day average from a 200-day one, and a controlled sweep can.

3. Train on the outcomes

A strategy paired with what it did is a labelled example. 222,010 of them is a training set, and a rare one: the input is structured rather than prose, the label is a number rather than a judgement, and nobody wrote any of it to be training data.

That is the shape you need to fine-tune a model to write strategies that land in the top decile instead of the middle of the distribution. Every language model can already describe what a good strategy looks like. This would be one that has seen 222,010 attempts and what each of them returned. The obvious hazard is that a model trained to maximise backtest Sharpe learns to overfit backtests, so the label has to be out-of-sample performance rather than the number the corpus already holds.

What twice the data revised

The corpus doubled, so I checked what it broke. Three conclusions from my 2025 analysis of 114,549 backtests did not survive the larger sample.

Contradicted

"More rules, worse results"

The 2025 piece showed complexity dragging Sharpe down and I published a scatter plot to prove it. The larger corpus shows a U shape instead: 1 rule 0.932, 2 rules 0.606, 3 to 4 rules 0.791, 5 to 8 rules 0.927, 9 or more 0.845. The worst place to be is two rules, not nine. The simple version of that finding was wrong.

Contradicted

"The 200-day SMA is the single most powerful indicator"

I was ready to file this one as untestable, because the lookback column was empty across all 304,426 SimpleMovingAverage rows. It was empty because of a bug of mine, described above, and the window was recoverable from the same table all along. Read correctly, it is still not testable, for a better reason. Among strategies using a single window the 200-day average medians 0.539 against 0.577 for a 20-day one, and that difference sits inside its own confidence interval. The 200-day average is not the most powerful indicator, and it is not the worst either. I cannot separate it from any other window.

Withdrawn

"Momentum for growth stocks, mean reversion for indexes"

This one depends almost entirely on how you classify a strategy. The price-versus-moving-average rule dominates the classifier and the trend-filter cutoff is arbitrary, so the finding moves when the definition moves. It needs a sensitivity sweep before anyone repeats it, including me.

The sell rule

While the ranking was running I split every backtest containing a buy action on whether it also contained a sell action. Strategies that never sold posted a median return of 36.41% against 19.50% for strategies that did. Nearly double, and it holds in both eras rather than being a 2020s bull-market artifact.

Then I restricted the same split to runs carrying a benchmark. Of the strategies that never sold, only 43.3% beat simply holding the asset, with a median alpha of -0.85. Of the strategies that did sell, 57.0% beat it, at +8.77.

What that means

Never selling produces big raw returns and still loses to buying and holding the same asset. The benchmark subset is 4,525 runs and skews recent, so treat it as directional rather than settled.

How this was measured

The source is a snapshot of the NexusTrade backtest archive taken on 6 September 2026, covering 400,203 scanned documents. Every figure above comes from that snapshot under one filter: the backtest was traded, it ran between 365 and 2,000 days, and it was authored by a person rather than the optimizer.

Each backtest counts once per indicator type, so a strategy using the same indicator in four conditions contributes one observation rather than four. Rankings are medians, not means, because a handful of leveraged outliers move a mean and tell you nothing about the typical strategy. Every median carries a 95% bootstrap interval from 4,000 resamples, and where two intervals overlap I do not claim an ordering between them. Window comparisons additionally count only strategies using a single window of that type, because a crossover strategy holds two and would otherwise be counted in both.

Only aggregate results for built-in indicator types appear anywhere in this analysis. Creator-owned custom indicators, their names, their parameters, their identifiers and their underlying strategy logic stay private, and the results-only table they live in cannot be joined back to any strategy, portfolio or user.

Ask the corpus yourself

Every table in this piece is a question I typed in English. The archive is queryable by the platform's AI agent, which writes read-only SQL against the backtest tables and hands back the rows, so "median Sharpe by moving-average window, minimum 500 backtests" is a sentence rather than a query. Ask which setting of an indicator you already use has done best, whether your rule reads better driving a buy or a sell, or how a type performs once you hold the timeframe fixed.

Ask carefully, though, because the agent answers the question you asked. Put that moving-average question to it plainly and it will bucket every backtest by every window it contains, count each 50/200 crossover twice, and handed me a spread I nearly published. Adding "only strategies that use a single window" changes the answer and is the difference between a finding and an artefact. The corpus removes the work of gathering the data. It does not remove the work of asking a clean question.

Point it at your own strategy

The sweep that turns a correlation into an experiment is queryable the same way. Hold your own strategy fixed, change one rule, and run both, without writing any code.

Ask it about a setting you use

Every number here comes from the NexusTrade backtest archive, which is why each row carries its sample size instead of a screenshot of a chart. If you want the anonymized aggregate results to run the ranking yourself, send me the word CORPUS.

Build the strategy this article describes

Create a free account to backtest ideas against market history, inspect the risk, and deploy to paper or live markets when you're ready.

or

Free to browse. No credit card required.

Discussion

Sign in or create a free account to join the discussion.

No comments yet.