How to Backtest a 20-Day Breakout Strategy: Rules, Sample Size and Expectancy

To backtest a 20-day breakout strategy, write the "true breakout" down as buy and exit conditions a machine can evaluate, run those rules over several years of daily bars, and read four numbers: win rate, profit factor, maximum drawdown and expectancy per trade. Breakout systems have naturally low win rates, so whether one makes money depends almost entirely on the payoff ratio. The point of the backtest is not "how often was I right" but "how much did I make when right, and lose when wrong."

Key takeaways

  • Breakout strategies typically win 35% to 45% of the time. That is not a flaw: a few large winners cover many small losers, so expectancy hinges on the payoff ratio.
  • Read four numbers together: win rate, profit factor, maximum drawdown and expectancy per trade. Any one alone will mislead you.
  • Slippage hurts breakouts badly. Entering the next day 1.5% above the signal close can turn a thin edge into a losing system.
  • A fixed -5% stop is too tight for high-volatility names. Check stop width against atr14_pct.
  • Sample size matters: 100 trades still leave roughly a plus or minus 10 point error on the win rate. Thirty trades tell you almost nothing.

Step one: write the "true breakout" as rules

"Buy when it breaks out to a new high" cannot be backtested because it does not define what a breakout is or when you leave. A testable version:

Buy (all must be true)

  1. Close makes a new 20-day high (is_20d_breakout).
  2. Volume above 1.5 times the 20-day average (vol_vs_avg20d > 1.5), to exclude breakouts on no volume.
  3. ADX(14) > 25, so a trend is in place rather than a random new high inside a range.
  4. MA20 above MA50, so the medium-term direction is up.
  5. More than 5 days to the next earnings date, so you do not buy straight into an earnings gap.

Exit (any one triggers)

  • Floating loss > 5%: stop-loss.
  • Floating gain > 10%: take-profit.
  • Held 15 trading days or more: time stop. If it has not gone anywhere in 15 days, it is not the breakout you were buying.
  • 2 days or fewer to the next earnings date: step aside before the report.

Every line is one indicator, one operator, one number. Only at that precision can a rule be backtested and scanned daily. See turning logic into buy rules.

Why breakouts have low win rates but can still make money

A breakout buys a new high, a short-term extreme by definition. Many fall back into the range within days and hit the stop, which is why breakout systems rarely win more than half the time.

They can still profit through asymmetry: a -5% stop and a +10% target cap every loss while winners collect roughly twice what losers give up. If winners are large enough, a 40% win rate carries a positive expectancy. So read the report as four numbers, not one:

MetricQuestion it answersTypical for breakouts
Win rateShare of trades that made moneyLow, 35% to 45%
Profit factorGross profit ÷ gross lossNeeds to exceed about 1.2
Max drawdownLargest peak-to-trough equity drop5 to 7 straight losses are normal
Expectancy per tradeAverage gain or loss per tradePositive, and covers costs

Losing streaks are normal here. With a 60% loss probability, five losses in a row has probability 0.6 to the fifth power, about 7.8%; over 100 trades a streak of five to seven is near certain. That is where maximum drawdown comes from, not from the strategy "breaking."

A worked expectancy example you can check with a calculator

The numbers below are illustrative arithmetic, not measured results. Suppose the backtest produces 100 trades:

  • Win rate 40% (40 winners, 60 losers).
  • Average winner +8% (some hit the +10% target, some leave at the time stop with less).
  • Average loser -4.5% (most hit the -5% stop, a few time-stop with a small loss).

Expectancy per trade = 0.40 × 8% − 0.60 × 4.5% = 3.2% − 2.7% = +0.5%.

Profit factor = (40 × 8) ÷ (60 × 4.5) = 320 ÷ 270 ≈ 1.19.

In money: a 20,000 USD account risking 1% per trade puts 200 USD at risk. With a 5% stop, position size = 200 ÷ 5% = 4,000 USD, so expectancy is +0.5% × 4,000 ≈ +20 USD per trade, about +2,000 USD over 100 trades, before fees. A positive edge, but thin.

Sampling error: at 40% over 100 trades, the standard error of the win rate is the square root of (0.4 × 0.6 ÷ 100) ≈ 4.9 points, so the 95% interval is roughly 30% to 50%. With 30 trades it is about 8.9 points and the interval stretches to 22% to 58%, at which point "40% win rate" says almost nothing. Look at the trade count before the win rate.

Slippage: what happens if you enter 1.5% higher the next day

A breakout is confirmed at the close, so the earliest fill is the next open. Stock Compass backtests the same way: evaluate on day D, fill at the open of day D+1, no look-ahead. But the day after a breakout often gaps up. Assume the open averages 1.5% above the signal close, and as a crude approximation shift every outcome down 1.5 points: winners +8% become +6.5%, losers -4.5% become -6.0%.

New expectancy = 0.40 × 6.5% − 0.60 × 6.0% = 2.6% − 3.6% = -1.0%.

Profit factor = (40 × 6.5) ÷ (60 × 6.0) = 260 ÷ 360 ≈ 0.72.

A +0.5% edge flips to a loss on 1.5% of slippage. Reality is more nuanced (stops are measured from actual cost, so part of the damage appears as a lower win rate), but the direction holds: breakout strategies are extremely sensitive to entry price. Read next-open fills, never signal-close fills, and live, if you cannot fill near the open, skip the trade.

Why a fixed -5% stop is too tight for high-ATR names

The same -5% means different things on different stocks. Measure it against atr14_pct, the 14-day ATR as a percentage of price:

  • Stock A, atr14_pct = 1.5%: a -5% stop is about 3.3 ATRs away. Normal noise will not reach it.
  • Stock B, atr14_pct = 4%: a -5% stop is only 1.25 ATRs. One ordinary day can knock you out before the stock continues in the breakout direction without you.

On stocks like B, a -5% stop depresses the win rate with right-direction losses. Two fixes:

  1. Size the stop from ATR: stop ≈ 2 × atr14_pct, so -8% for B. To keep dollar risk at 200 USD, shrink the position to 200 ÷ 8% = 2,500 USD. Wider stop, smaller position, same risk.
  2. Filter at entry: add atr14_pct <= 2.5 so you only trade names where -5% is at least 2 ATRs, and give volatile names a separate wider-stop strategy.

The JSON below uses the second approach. See position sizing for stop width versus position size.

Market regime filter and parameter variants

Breakouts succeed more often in a rising market. The simplest filter is market_index_vs_ma50_pct > 0: only accept buys while the benchmark index is above its 50-day average. Run the backtest with the filter on and off; the trade count usually drops, and you want to see expectancy and maximum drawdown improve.

Do not run a single parameter set either. The table below is illustrative arithmetic for three volume thresholds:

Volume thresholdTradesWin rateAvg winAvg lossExpectancyProfit factor
1.3×14037%+7.5%-4.6%-0.12%0.96
1.5×10040%+8.0%-4.5%+0.50%1.19
2.0×5544%+8.5%-4.4%+1.28%1.52

A higher threshold means fewer, better signals, as expected. But 2.0× produces only 55 trades, so its win rate has a much wider error band and more capital sits idle. Smooth change across rows means the strategy is not sensitive to this parameter, which is good; one excellent row between two poor ones is probably fitted luck. Do not simply pick the best row.

How to set this up in Stock Compass

Backtesting is a Pro feature. It runs on daily bars, fills at the next open, and reports gross returns before trading costs. Stock Compass does not connect to brokers or place orders; it scans your watchlist against your own rules each day and lists the names that trigger. The complete strategy:

{
  "name": "20-Day True Breakout",
  "market": "us",
  "rules": {
    "buy": {
      "v": 2,
      "outerOp": "OR",
      "groups": [
        {
          "innerOp": "AND",
          "conditions": [
            { "indicator": "is_20d_breakout", "operator": "==", "value": 1 },
            { "indicator": "vol_vs_avg20d", "operator": ">", "value": 1.5 },
            { "indicator": "adx_14", "operator": ">", "value": 25 },
            { "indicator": "ma20_above_ma50", "operator": "==", "value": 1 },
            { "indicator": "atr14_pct", "operator": "<=", "value": 2.5 },
            { "indicator": "market_index_vs_ma50_pct", "operator": ">", "value": 0 },
            { "indicator": "days_to_next_earnings", "operator": ">", "value": 5 }
          ]
        }
      ]
    },
    "add": { "v": 2, "outerOp": "OR", "groups": [] },
    "trim": { "v": 2, "outerOp": "OR", "groups": [] },
    "exit": {
      "v": 2,
      "outerOp": "OR",
      "groups": [
        { "innerOp": "AND", "conditions": [ { "indicator": "floating_loss_pct", "operator": ">", "value": 5 } ] },
        { "innerOp": "AND", "conditions": [ { "indicator": "floating_gain_pct", "operator": ">", "value": 10 } ] },
        { "innerOp": "AND", "conditions": [ { "indicator": "holding_days", "operator": ">=", "value": 15 } ] },
        { "innerOp": "AND", "conditions": [ { "indicator": "days_to_next_earnings", "operator": "<=", "value": 2 } ] }
      ]
    }
  }
}

Buy conditions:

  • is_20d_breakout == 1: the close is a new 20-day high.
  • vol_vs_avg20d > 1.5: volume above 1.5 times the 20-day average; the unit is a multiple, not a percent.
  • adx_14 > 25: trend strength passes. See ADX in the glossary.
  • ma20_above_ma50 == 1: the 20-day average is above the 50-day average.
  • atr14_pct <= 2.5: only names where a -5% stop is at least 2 ATRs wide.
  • market_index_vs_ma50_pct > 0: the benchmark index is above its 50-day average.
  • days_to_next_earnings > 5: more than 5 days until the next earnings report.

The four exit groups are joined by OR, so any one closes the position. floating_loss_pct is positive when losing, hence "loss greater than 5%" is written as > 5.

One detail: the backtest has no historical earnings calendar, so the two days_to_next_earnings conditions are skipped and flagged as not evaluated. They work in the daily live scan, so the backtest reflects the version without the earnings filter.

Common mistakes

  • Backtesting with signal-close fills. Breakouts often gap up the next day, so close fills systematically overstate returns.
  • Looking only at win rate. A 40% breakout system can be excellent and a 70% system can lose money. Check expectancy and profit factor first.
  • Concluding from too few trades. A 30-trade backtest has a win-rate error band near plus or minus 18 points. Aim for at least 100 trades across a full up-and-down cycle.
  • Using the same -5% stop on every stock. Volatile names get shaken out by normal noise. Check stop width against atr14_pct.
  • Picking the best row in the parameter table. Large jumps between neighbouring parameters mean fitting, not a pattern. Choose a middle, robust value.

Summary

Backtesting a 20-day breakout strategy is straightforward once the "true breakout" is written as decidable conditions: run it over enough trades, fill at the next open, and read four numbers rather than one. A low win rate is normal; usability depends on payoff ratio, slippage and whether the stop width matches the stock's volatility. Once a strategy passes, the real difficulty begins: following the same rules every day. See how to use daily buy and sell signals.

FAQ

What win rate should a 20-day breakout strategy have?

Most breakout systems win somewhere between 35% and 45% of trades, and that is normal rather than a problem. They make money through asymmetry: small capped losses and larger winners. Judge the strategy by expectancy per trade and profit factor, not by win rate alone.

How many trades does a backtest need before I trust it?

At a 40% win rate, 100 trades still leave a margin of error of roughly plus or minus 10 percentage points on the win rate. Thirty trades widen that to nearly plus or minus 18 points. Aim for at least 100 trades that span both rising and falling market periods before drawing conclusions.

Why does slippage matter so much for breakout strategies?

A breakout is confirmed at the close, but you can only trade at the next open, which often gaps up. Because the edge of a breakout system is usually thin, an average entry 1.5% above the signal close can flip a small positive expectancy into a negative one. Always read backtest results based on next-open fills.

Should I use a fixed -5% stop or an ATR-based stop?

A fixed -5% stop works for stocks whose 14-day ATR is under roughly 2.5% of price, where the stop sits at least 2 ATRs away. For more volatile names it is too tight and gets hit by normal noise. Either widen the stop to about 2 times atr14_pct and shrink the position to keep dollar risk constant, or filter volatile names out at entry.

Does the Stock Compass backtest include trading costs and the earnings filter?

The backtest runs on daily bars, fills at the next open and reports gross returns before commissions and fees, so treat costs as a further haircut. It has no historical earnings calendar, so days_to_next_earnings conditions are skipped in the backtest and flagged as not evaluated; they do apply in the daily live signal scan. Stock Compass does not connect to brokers or place orders.