A stated return-to-player figure of 97% is an expected value. It describes the limit a long-run average approaches, and it says nothing about any single session. That part is well understood.
The more useful question has an exact answer: how many rounds does a measurement need before the observed average lands near the stated figure? The answer depends on one parameter, and across ordinary settings of that parameter it varies by more than two orders of magnitude.
This is a sampling problem, and the tools are the same ones used for latency percentiles, A/B tests and any other measurement of a high-variance quantity.
RTP is an expected value
Write the payout of one round as a random variable X, measured in units of the stake. Then
RTP = E[X]
An RTP of 97% means E[X] = 0.97: one unit staked returns 0.97 units on average. Nothing in that statement constrains the shape of the distribution. X can be concentrated near 0.97, or it can be zero almost always with occasional large values. Both have the same mean and behave completely differently under sampling.
The distribution, not the mean, determines how fast a measurement converges.
The model
Take a step-based multiplier game. The player places a stake, a multiplier starts at 1 and grows in discrete steps, and the player fixes the win by cashing out. Every step carries a probability that the round continues, so reaching a higher multiplier means surviving more steps.
For a fixed cash-out target m, this collapses to a two-outcome variable:
X = m with probability p, otherwise 0
Calibrating to a 97% return gives p = 0.97 / m. A target of 2× is reached 48.5% of the time, a target of 10× is reached 9.7% of the time, and a target of 100× is reached 0.97% of the time.
That is the entire model. For the round mechanics in narrative form — stake, growing multiplier, manual cash out, what each step does — the Italian-language breakdown chicken road come funziona walks through one round at a time.
Why the estimate converges slowly
The mean of n independent rounds has standard error σ/√n, where σ is the per-round standard deviation. For the two-outcome variable above:
E[X] = m·p = 0.97
E[X²] = m²·p = 0.97·m
Var(X) = 0.97·m − 0.97² = 0.97·(m − 0.97)
The variance is linear in the cash-out target. In numbers:
| Target m | p | σ |
|---|---|---|
| 1.2× | 0.808 | 0.47 |
| 2× | 0.485 | 1.00 |
| 10× | 0.097 | 2.96 |
| 100× | 0.0097 | 9.80 |
At a 100× target the per-round standard deviation is ten times the mean itself. One round carries almost no information about the mean.
A formula for the sample size
Fix a precision target: the standard error should be at most ε times the RTP. Then
n = Var(X) / (ε · RTP)²
Substituting Var(X) = 0.97(m − 0.97) and RTP = 0.97, with ε = 0.01 for a one-percent relative standard error:
n ≈ 10,309 · (m − 0.97)
The required sample size is linear in the cash-out target:
| Target | Rounds for ±1% |
|---|---|
| 1.2× | ~2,400 |
| 2× | ~10,600 |
| 10× | ~93,000 |
| 100× | ~1,021,000 |
The stated RTP is identical in every row. The cost of measuring it differs by a factor of four hundred.
That is the practical result worth carrying away. A measured return computed from a few hundred rounds at a high target carries no information — not because the arithmetic is wrong, but because the sample is three orders of magnitude short of what the variance demands.
Running it yourself
Twenty lines are enough to check the table:
import random
RTP = 0.97
def simulate(target, rounds, seed=0):
rng = random.Random(seed)
p = RTP / target # probability of reaching the target
staked = payout = 0.0
for _ in range(rounds):
staked += 1.0
if rng.random() < p:
payout += target
return payout / staked
for n in (10**2, 10**3, 10**4, 10**5, 10**6):
print(n, round(simulate(10.0, n), 4), round(simulate(1.2, n), 4))
Output with seed 0:
| Rounds | Target 10× | Target 1.2× |
|---|---|---|
| 100 | 0.5000 | 0.8640 |
| 1,000 | 1.0900 | 0.9828 |
| 10,000 | 0.9860 | 0.9707 |
| 100,000 | 0.9721 | 0.9688 |
| 1,000,000 | 0.9702 | 0.9702 |
The low-target column is inside one percent by 10,000 rounds. The high-target column is 1.6% away at the same point and needs another order of magnitude to settle. The crossover matches the sample-size table exactly.
Measuring every target at once
The binary formulation discards information. A round that ends at 7.4× and a round that ends at 1.02× are both a loss against a 10× target, yet they are very different observations.
Log the realised end multiplier c for every round. That single dataset gives the empirical survival function
Ŝ(m) = #{c ≥ m} / n
and the return for any target follows as RTP(m) = m · Ŝ(m). One data collection answers every cash-out target simultaneously instead of requiring one run per target.
The structural benefit matters more than the precision gain: you can check whether RTP(m) stays flat across m, which is exactly what the calibration asserts. A curve is a far more informative result than a single number, and it comes from the same rounds you were already going to record.
When comparing two configurations, drive both with the same random stream. Under common random numbers the difference between them has much lower variance than either estimate on its own, because the shared noise cancels.
Reporting the result
A point estimate is not a result. Report the interval:
mean ± 1.96 · σ̂ / √n
where σ̂ is the sample standard deviation. For the 10× case at n = 10,000, σ̂ ≈ 2.96, so the half-width is 1.96 · 2.96 / 100 ≈ 0.058. The interval is 0.986 ± 0.058, or [0.928, 1.044]. A stated 0.97 sits comfortably inside it — and so would 0.93 or 1.04. The measurement does not separate them.
At n = 1,000,000 the half-width falls to 0.0058 and the interval [0.964, 0.976] is narrow enough to say something.
Four ways the measurement goes wrong
Averaging ratios instead of dividing totals. RTP is total returned over total staked. Computing a per-round ratio and averaging those gives a different quantity as soon as stake sizes vary.
Stopping when the number looks right. Optional stopping pulls the estimate toward whatever value triggered the stop. Fix n before the run starts.
Dropping the weighting. Rounds with different stakes contribute differently to the total. Accumulate currency amounts, not round counts.
Accumulating in floating point. Summing a million float payouts loses precision in the low digits, and the loss grows with the run. Use integer minor units — cents — or Kahan summation. In the simulation above the effect is negligible; in a ledger spanning billions of rounds it is not.
Where the number itself is fixed
One point worth stating, because it turns up in bug reports. RTP is a property of a configuration, not of a title. The same game can be deployed with different settings, and the value that applies is the one exposed in the game's own information panel. Measurements taken against one deployment do not transfer to another, and a gap between a measured value and a published one is often a configuration difference rather than a sampling artefact.
Summary
- RTP is
E[X]. The variance, not the mean, sets the cost of measuring it. - For a two-outcome payout calibrated to 97%,
Var = 0.97(m − 0.97)— linear in the cash-out target. - Rounds needed for a one-percent relative standard error:
n ≈ 10,309 · (m − 0.97). About 2,400 at 1.2×, 93,000 at 10×, and over a million at 100×. - Logging the end multiplier instead of a win/loss flag answers every target from one dataset.
- Report an interval, fix
nin advance, divide totals rather than averaging ratios, and accumulate in integers.
