Sequence Risk and Risk of Ruin
“The same trades in a different order can end your account” is one of those statements that sounds obviously true and is, as usually explained, obviously false. Under the sizing rule most systematic traders actually use, reordering a fixed set of trades changes the terminal balance not at all. What it changes is the shape of the journey — and the journey is what decides whether you are still there for the end of it.
This lesson separates the two carefully, because getting them muddled produces both false alarms and false comfort. By the end you should be able to say precisely which quantities are order-dependent and which are not, define ruin in a way that can be computed, calculate it for the one case where a closed form exists, simulate it for the cases where none does, and explain why a positive expectancy traded at the wrong size still finishes at zero.
What reordering changes, and what it does not
Section titled “What reordering changes, and what it does not”Take four trades expressed as growth factors: a 50 per cent gain, two 30 per cent losses, and a 40 per cent gain. Size every position as the same fraction of current equity, so each trade multiplies the account by its factor. Terminal equity is 1.5 × 0.7 × 0.7 × 1.4 = 1.029, a gain of 2.9 per cent, and that product is the same however you shuffle the four numbers. Multiplication does not care about order.
The path does.
| Order | Equity after each trade | Deepest peak-to-valley fall |
|---|---|---|
| Gain, loss, loss, gain | 1.50 → 1.05 → 0.735 → 1.029 | 51 per cent, from 1.50 down to 0.735 |
| Loss, gain, loss, gain | 0.70 → 1.05 → 0.735 → 1.029 | 30 per cent, twice, from 1.00 and from 1.05 |
Identical trades. Identical ending. One arrangement asks you to sit through a 51 per cent drawdown; the other never takes more than 30 per cent off a peak. That gap is sequence risk in its purest form, and it is entirely invisible in any summary statistic computed from the completed record.
When terminal equity does depend on order
Section titled “When terminal equity does depend on order”Order starts to matter for the ending balance as soon as the account stops being a pure multiplier. Four ways that happens, all of them ordinary:
- You stop. Any absorbing barrier — a personal limit, a margin call, an investor withdrawing, or simply losing the nerve to place the next order — truncates the sequence. A path that hits the barrier never gets to compound the trades that came after it.
- The trade becomes untakeable. With a smaller account, a signal that would have been taken
is skipped for want of capital. AmiBroker models this explicitly:
SetOption( "MinShares", … )andSetOption( "MinPosValue", … )define the smallest position the backtester will open, and a signal that cannot be funded to that level is simply not entered.SetOption( "AllowPositionShrinking", … )decides whether an underfunded position is opened smaller or dropped entirely. Change the order of the wins and losses and you change which signals fell below the line. - Sizing is not proportional at the edges. Round lots, indivisible contracts and a cap on simultaneous positions all break the neat multiplication near the extremes.
- Money moves in or out on a calendar. Contributions and withdrawals happen on dates, not after trade numbers, so where the good stretch sits relative to them changes the result.
The first of those is the one this lesson is about.
The barrier AmiBroker already has
Section titled “The barrier AmiBroker already has”The backtester contains an absorbing barrier of its own. Among the exit reasons the custom
backtester reports is one called ruin, and SetOption( "DisableRuinStop", True ) turns it off.
A note from AmiBroker’s author in the comments on the official ApplyStop() page describes it as
a fixed ruin stop triggered by losing 99.96 per cent of the starting capital, and lists it as
the first stop evaluated when several fire on the same bar.
It is not a risk-management tool — by the time it fires there is nothing left to manage. It is there so that a backtest of a catastrophically over-sized system terminates rather than producing nonsense. If you ever see it in a trade list, the correct response is not to disable it.
Risk of ruin, defined so it can be computed
Section titled “Risk of ruin, defined so it can be computed”“Risk of ruin” is the probability that equity reaches a level at which you stop, at some point before the end of the horizon you care about.
Every clause in that sentence is a choice you have to make explicit:
- The level. Zero is the wrong answer for anyone using proportional sizing, because proportional sizing never reaches zero — it only approaches it. The useful level is the one at which you would actually stop: down 30 per cent, down 50 per cent, below the amount your broker requires, below the point at which the strategy no longer justifies the effort.
- Before the end of what horizon. Over an infinite horizon many systems reach any given level eventually. Over two hundred trades they may not. Ruin probability without a horizon is not a number.
- At some point, not at the end. Touching the level counts, even if the equity curve recovers afterwards, because you were not there for the recovery.
AmiBroker does not report a metric called risk of ruin. What the Monte Carlo page gives you
instead is the Lowest Eq. distribution, which is the same idea seen from the other side: the
percentile table tells you what fraction of realizations dipped below any level you care to look
up. If you want a specific probability against a specific threshold, you compute it — either from
a formula, in the one case where a formula exists, or by simulation.
The one case with a closed form
Section titled “The one case with a closed form”For a game with fixed-size bets, even money, a constant win probability p, independent trials
and an unlimited number of them, the probability of ever losing a bankroll of N units is
(q/p)^N, where q = 1 − p. It is the classical gambler’s-ruin result and it is worth working
through once because the numbers are so unforgiving.
Take a genuine edge: p = 0.55, so q/p is about 0.818.
| Bankroll, in units risked per bet | Probability of ever being wiped out |
|---|---|
| 5 units | about 37 per cent |
| 10 units | about 13 per cent |
| 20 units | about 1.8 per cent |
| 40 units | about 0.03 per cent |
The edge never changed. Only the size of each bet relative to the bankroll did, and the ruin probability fell by three orders of magnitude across the table. That relationship — ruin falling roughly geometrically as the bet shrinks — is the single most useful intuition in position sizing.
Simulating ruin when there is no formula
Section titled “Simulating ruin when there is no formula”With proportional sizing and unequal outcome sizes, no tidy closed form is available. Simulation is the practical route, and it has the advantage that every assumption is visible in the code rather than buried in a derivation.
Given a win rate, a payoff ratio and a fraction of equity risked per trade, estimate how often a sequence of a given length touches a level you would call ruin — and watch what happens to that estimate as the risked fraction increases.
The complete formula
Section titled “The complete formula”Complete runnable AFL
// ruin-laboratory.afl// Part 33 - Monte Carlo and Robustness//// A synthetic sequence simulator. It answers one question: given a win rate, a// payoff ratio and a fraction of equity risked per trade, how often does a// sequence of trades reach a level you would call ruin before it reaches the// end?//// EVERY NUMBER THIS FORMULA PRODUCES IS SYNTHETIC. There is no market data in// it. The instrument you run it on supplies nothing but somewhere to put the// output rows - change the symbol and the answers do not move. That is the// point: this is arithmetic about sequences, not evidence about any market.//// ASSUMPTIONS, all of them wrong in the friendly direction:// * Every trade is an independent draw. Real trades cluster by regime.// * The win rate and the payoff ratio never change. In a real system both// drift, and they drift together, and they get worse at the same time.// * Wins are all the same size and losses are all the same size. Real// outcome distributions have tails this model does not contain.// * Costs are already inside the win and loss figures you type in.// * Trading stops the moment equity touches the ruin level.// A real system is riskier than this simulation says, not safer.//// Run it as an Exploration in the New Analysis window, applied to the CURRENT// SYMBOL only, over any range that contains at least as many bars as there are// risk levels. One row per risk level. Expect a few seconds of work: the// default settings draw 800,000 random numbers.
// ---- Inputs (Parameters button in the Analysis window) --------------------WinRatePct = Param( "Win rate (%)", 45, 5, 95, 1 );PayoffRatio = Param( "Payoff (avg win / avg loss)", 1.8, 0.2, 10, 0.1 );RiskStepPct = Param( "Risk step per row (%)", 1, 0.25, 5, 0.25 );LevelCount = Param( "Risk levels (rows)", 8, 1, 20, 1 );TradesPerPath = Param( "Trades per path", 100, 10, 500, 10 );PathCount = Param( "Paths per risk level", 1000, 100, 5000, 100 );RuinPct = Param( "Ruin level (% of start)", 50, 5, 95, 5 );
WinProb = WinRatePct / 100;RuinLevel = RuinPct / 100; // equity is tracked as a multiple of 1.0
// ---- Where the output rows go --------------------------------------------// The last LevelCount bars of the array carry one result row each. Writing// into a zero array by index is exact; it does not depend on dates or on the// analysis range lining up with anything.if ( LevelCount > BarCount ){ LevelCount = BarCount;}FirstRow = BarCount - LevelCount;
RowFlag = Cum( 0 );RiskCol = Cum( 0 );RuinCol = Cum( 0 );BelowCol = Cum( 0 );DoubleCol = Cum( 0 );TypicalCol = Cum( 0 );WorstCol = Cum( 0 );AvgDDCol = Cum( 0 );
// ---- The simulation -------------------------------------------------------for ( level = 0; level < LevelCount; level++ ){ RiskFraction = RiskStepPct * ( level + 1 ) / 100;
// A 100 per cent risk fraction takes equity to zero in one trade and makes // the logarithms below meaningless, so cap it just short of that. if ( RiskFraction > 0.99 ) { RiskFraction = 0.99; }
WinStep = 1 + RiskFraction * PayoffRatio; LossStep = 1 - RiskFraction;
RuinedPaths = 0; BelowStart = 0; DoubledUp = 0; SumLogEnd = 0; SumMaxDD = 0; WorstEnd = 1000000000;
for ( path = 0; path < PathCount; path++ ) { PathEquity = 1; PathPeak = 1; PathMaxDD = 0; WasRuined = 0;
for ( trade = 0; trade < TradesPerPath; trade++ ) { if ( mtRandom() < WinProb ) { PathEquity = PathEquity * WinStep; } else { PathEquity = PathEquity * LossStep; }
if ( PathEquity > PathPeak ) { PathPeak = PathEquity; }
Underwater = 1 - PathEquity / PathPeak; if ( Underwater > PathMaxDD ) { PathMaxDD = Underwater; }
// Ruin is defined as touching the level at any point. Once touched // we stop trading, which is what a person or a broker would do. if ( PathEquity <= RuinLevel ) { WasRuined = 1; break; } }
RuinedPaths = RuinedPaths + WasRuined; SumMaxDD = SumMaxDD + PathMaxDD; SumLogEnd = SumLogEnd + log( PathEquity );
if ( PathEquity < 1 ) { BelowStart = BelowStart + 1; } if ( PathEquity >= 2 ) { DoubledUp = DoubledUp + 1; } if ( PathEquity < WorstEnd ) { WorstEnd = PathEquity; } }
Row = FirstRow + level; RowFlag[ Row ] = 1; RiskCol[ Row ] = RiskFraction * 100; RuinCol[ Row ] = 100 * RuinedPaths / PathCount; BelowCol[ Row ] = 100 * BelowStart / PathCount; DoubleCol[ Row ] = 100 * DoubledUp / PathCount; TypicalCol[ Row ] = exp( SumLogEnd / PathCount ); // geometric mean WorstCol[ Row ] = WorstEnd; AvgDDCol[ Row ] = 100 * SumMaxDD / PathCount;}
// ---- Output ---------------------------------------------------------------Filter = RowFlag == 1;
SetOption( "NoDefaultColumns", True );
AddColumn( RiskCol, "Risk per trade %", 1.2 );AddColumn( RuinCol, "Reached ruin %", 1.1 );AddColumn( BelowCol, "Ended below start %", 1.1 );AddColumn( DoubleCol, "Ended at 2x or better %", 1.1 );AddColumn( TypicalCol, "Typical end multiple", 1.3 );AddColumn( WorstCol, "Worst end multiple", 1.3 );AddColumn( AvgDDCol, "Average worst drawdown %", 1.1 );How it works
Section titled “How it works”Three nested loops. The outer one walks a ladder of risk levels, one per output row. The middle one runs many independent paths at each level. The inner one plays out a single path, trade by trade: draw a uniform random number, multiply equity by the winning factor or the losing factor accordingly, update the running peak and the deepest fall from it, and stop the path immediately if equity has touched the ruin threshold.
Each completed path contributes to seven running totals — whether it was ruined, its deepest drawdown, the logarithm of its ending equity, whether it finished below its start, whether it finished at twice its start or better, and whether it was the worst ending so far. Averaging the logarithms rather than the equities is deliberate: the arithmetic mean of a set of multiplicative outcomes is dragged upwards by a handful of large winners and describes no typical path at all. The exponential of the mean logarithm is the geometric mean, which is the multiple a middling path actually achieves.
Writing results into arrays by index is what lets one exploration produce a table. The last
several bars of the array carry one result row each, and Filter is set from a flag array
written by the same loop, so the rows appear whatever dates the analysis range happens to cover.
Key functions
Section titled “Key functions”Param( name, default, min, max, step )— puts every assumption on the Parameters dialog, so the experiment can be re-run without editing code. Outside a chart it still returns the default, which is what makes the file self-documenting.mtRandom()— a Mersenne Twister uniform random number in the range 0 to 1. The guide notes it is substantially better than the C runtime generator behindRandom(), and that an unseeded call is initialised from the clock.Cum( 0 )— an array of zeros, used here as writable working storage.log()andexp()— natural logarithm and its inverse, used to build the geometric mean.
Expected result
Section titled “Expected result”One row per risk level, with the fraction of paths that reached ruin, the fraction that ended below their starting point, the fraction that at least doubled, the geometric-mean ending multiple, the worst ending multiple seen, and the average of each path’s deepest drawdown.
At the defaults — a 45 per cent win rate and a payoff ratio of 1.8, which is a comfortably positive edge — you should see the ruin column rise steeply as the risked fraction grows, and the geometric-mean multiple rise, peak and then fall. Those two things happening at once is the whole point of the exercise. Every number is synthetic; the shape of the relationship is what you are being asked to look at, not the values.
Test it
Section titled “Test it”Set the payoff ratio so that the edge disappears — with a 45 per cent win rate, a payoff of
0.55 / 0.45, about 1.222, makes expectancy exactly zero — and confirm that the geometric-mean
ending multiple collapses towards or below 1.0 at every risk level. Then set the win rate to 100
per cent and check that the ruin column is zero everywhere, which it must be if the loop logic is
right. Finally, double the path count and confirm the percentages move by less than a percentage
point or so; if they jump about, you are reading noise rather than a result.
Common errors
Section titled “Common errors”- Running it on a whole watch list. The formula never touches price data, so every symbol produces the same row. Apply it to the current symbol.
- Too few bars. The output rows are written into the last bars of the array, so the analysis range must contain at least as many bars as there are risk levels.
- Reading the ruin percentage as a property of your system. It is a property of the four numbers you typed in, under a model in which trades are independent and identically sized. Your trades are neither.
- Raising trades-per-path and paths-per-level together. The work is the product of three numbers. Five thousand paths of five hundred trades across twenty levels is fifty million random draws and a long wait.
Extension
Section titled “Extension”Replace the fixed win and loss factors with a draw from your own trade record — bucket your actual percentage outcomes and sample from those buckets instead. That removes the “all wins are the same size” assumption, which is the most obviously false one in the model. It does not remove the independence assumption, and no amount of work on the outcome distribution will.
Why position size decides survival
Section titled “Why position size decides survival”There is a level of aggression at which a genuinely positive edge produces a negative long-run growth rate. It is not a subtle effect and it does not require anything to go wrong.
For a binary outcome — win a multiple b of the amount risked with probability p, lose the
amount risked with probability q — risking a fraction f of equity on each trade gives an
expected growth rate per trade of:
g(f) = p · ln(1 + f·b) + q · ln(1 − f)
Put the ruin laboratory’s defaults into it: p = 0.45, b = 1.8, so the expected profit per
unit risked is 0.45 × 1.8 − 0.55 = 0.26. That is a substantial edge. Here is what g does as
f grows:
| Fraction of equity risked per trade | Expected log growth per trade |
|---|---|
| 5 per cent | +0.0106 |
| 10 per cent | +0.0165 |
| 14.4 per cent | +0.0182, the maximum |
| 20 per cent | +0.0156 |
| 30 per cent | −0.0019 |
| 40 per cent | −0.0369 |
Past about 30 per cent, an edge worth 26 per cent of every unit risked becomes a machine for
losing money — not because the edge failed, but because losses compound against a shrinking base
while gains compound against it too. The maximum sits at (p·b − q)/b, the log-optimal fraction
usually attributed to Kelly, and it is worth knowing chiefly as an upper bound that nobody sane
approaches.
Why average return is a poor guide to survival
Section titled “Why average return is a poor guide to survival”The final piece is a piece of arithmetic that catches people out constantly.
Alternate a 50 per cent gain and a 40 per cent loss indefinitely. The average of +50 and −40 is +5 per cent, which sounds like a good business. The compounded reality is 1.5 × 0.6 = 0.9 per pair of trades, a geometric mean of about −5.1 per cent per trade. An arithmetic mean of +5 per cent and a geometric mean of −5 per cent, from the same two numbers.
The gap is variance. For returns that are not too large, the compound growth rate is approximately the arithmetic mean minus half the variance: here, 0.05 − 0.45² / 2 = 0.05 − 0.101 = −0.051, which matches the exact figure closely. Volatility does not merely add uncertainty around the average outcome; it subtracts from it.
Two practical consequences follow. First, a strategy comparison based on average trade profit is not a comparison of growth rates, and the more volatile candidate is being flattered. Second, reducing position size reduces the variance term quadratically while reducing the mean only linearly, which is why cutting size can raise compound growth even though it lowers every individual trade’s profit.
AmiBroker’s report keeps the two apart, and the vocabulary is worth being careful with.
Annual Return % — the metric string "CAR" — is a compounded figure and is therefore a growth
rate. Avg. Profit/Loss % is an arithmetic average across trades and is not. They answer
different questions, and a system with a healthy average trade and an unhealthy Annual Return %
is telling you exactly where its variance went.
Reordering a fixed set of trades under proportional sizing leaves terminal equity untouched and changes maximum drawdown a great deal. Terminal equity becomes order-dependent as soon as the account can stop, can fail to fund a signal, or takes money in and out on a calendar — and AmiBroker models the funding case explicitly through its minimum-position settings.
Risk of ruin is only a number once you have named a threshold and a horizon. The classical formula gives it in closed form for fixed-stake, even-money, independent bets and shows ruin falling geometrically as the stake shrinks relative to the bankroll; for proportional sizing with unequal outcomes you simulate, and the ruin laboratory does that with every assumption visible.
Position size, not the edge, decides survival. There is a fraction beyond which a real edge
produces negative expected growth, the peak sits at (p·b − q)/b, and the cost of being too
aggressive is far greater than the cost of being too cautious. And because volatility subtracts
from compound growth, the average trade is a poor guide to what the account actually does.
The next lesson turns the scepticism outward: everything in this part, and everything in Parts 31 and 32, is downstream of one backtest, and inherits every one of its flaws.
Check your understanding
Sources for this lesson
5 verified · checked 2026-08-31
- 01AmiBroker User's Guide — Monte Carlo simulationamibroker.com/guide/h_montecarlo.html2026-08-31
- 02AFL Function Reference — SetOption§ MinShares, MinPosValue, AllowPositionShrinking, DisableRuinStopamibroker.com/guide/afl/setoption.html2026-08-31
- 03AFL Function Reference — ApplyStop§ Author's note on stop evaluation order and the fixed ruin stopamibroker.com/guide/afl/applystop.html2026-08-31
- 04AFL Function Reference — mtRandomamibroker.com/guide/afl/mtrandom.html2026-08-31
- 05AFL Function Reference — Paramamibroker.com/guide/afl/param.html2026-08-31
Every technical claim on this page was checked against the official AmiBroker documentation on the date shown. Where the course disagrees with folklore, the source is how you can tell which one to trust.