Series: Measuring trader behavior.
Disclosure: I work on Holdy Lab, a behavioral analysis tool for traders. The code below is open (MIT) and you do not need our product to run it. Educational only, not financial advice.*

"My win rate is 60%." Over how many trades? That single question decides whether the number means anything. Traders routinely draw conclusions from 15 or 20 trades, and the same reasoning shows up in "I trade best on Tuesdays" or "I revenge trade after losses". Here is a small way to see how much a number can be trusted before you act on it.

A win rate is a range, not a number

If you win 12 of 20 trades, your observed win rate is 60%. The true win rate of your strategy, the one you would see over thousands of trades, could be quite different. A standard way to express that is a confidence interval. I use the Wilson score interval because it behaves well for small samples and for rates near 0% or 100%, where the textbook formula misbehaves.

from math import sqrt def wilson(wins: int, n: int, z: float = 1.96) -> tuple[float, float]: """95% Wilson score interval for a win rate observed as `wins` out of `n` trades.""" if n == 0: return (0.0, 1.0) p = wins / n denom = 1 + z * z / n centre = (p + z * z / (2 * n)) / denom half = z * sqrt(p * (1 - p) / n + z * z / (4 * n * n)) / denom return (centre - half, centre + half) def streak_probability(n_trades: int, streak: int, win_rate: float) -> float: """Chance of at least one run of `streak` losses within `n_trades` independent trades.""" q = 1 - win_rate state = [1.0] + [0.0] * (streak - 1) # state[i] = current losing run has length i and never reached `streak`  for _ in range(n_trades): nxt = [0.0] * streak for i, prob in enumerate(state): nxt[0] += prob * (1 - q) if i + 1 < streak: nxt[i + 1] += prob * q state = nxt return 1 - sum(state) 

Running it on a 60% observed win rate:

 20 trades, 60% observed -> plausible true win rate 38.7% to 78.1% 50 trades, 60% observed -> plausible true win rate 46.2% to 72.4% 100 trades, 60% observed -> plausible true win rate 50.2% to 69.1% 200 trades, 60% observed -> plausible true win rate 53.1% to 66.5% 400 trades, 60% observed -> plausible true win rate 55.1% to 64.7% 

After 20 trades, a "60% strategy" could be a coin flip or an excellent system, and the data cannot tell you which. The range narrows slowly: you need roughly four times the trades to halve its width.

Streaks are normal

The same small-sample thinking applies to losing streaks. streak_probability computes the chance of at least one run of N losses somewhere in M trades, exactly, by tracking the current run length as the trades go by.

P(at least 6 losses in a row in 100 trades at 50%) = 54.6% P(at least 10 losses in a row in 100 trades at 50%) = 4.4% 

Even with a 50% win rate, a run of six losses somewhere in 100 trades is more likely than not. If six losses in a row makes you abandon a sound plan, you will keep abandoning plans that were fine.

What to do with this

  1. Report ranges, not points. Write "52% to 70%" in your journal, not "61%".
  2. Set a minimum before judging. Many people use at least 50 trades for an early look and 100 or more before changing a strategy. There is no magic number; the interval tells you how wide your uncertainty still is.
  3. Apply it to behavior, not only to strategy. "I size up after losses" is also an estimate from a sample. Eight trades in each group is a floor, not a comfortable size.
  4. Look for large, repeated effects. Small differences need big samples.

Limits

  • The interval assumes trades are independent and that the strategy does not change. Real markets have regimes, so the true uncertainty is larger than the table shows.
  • The streak calculation assumes a constant win rate and independent trades.
  • Neither tells you why a result happened.

The tests and two more checks (a prop-firm Monte Carlo and a weekday permutation test) are in the open repository. If you would rather not run code, the free Trade Analyzer labels results by sample size, and how many trades you need to evaluate a strategy explains the same idea without code.