Skip to content
Level 4 · Trading System ResearcherLessonPart 34 · page 4 of 528 min
28Minutes
7AFL functions
5Sources
StandardRequires
AFL functions taught here7

Drawdown and Risk of Ruin in Practice

Max. system % drawdown: −34.2% is a fact about a spreadsheet. What it describes is seventeen months during which an account fell by a third, produced signals the entire way down, and gave no indication at any point that this was the bottom rather than the middle. The statistic takes a second to read. The thing it stands for is the hardest part of running a strategy, and it is where most strategies are actually abandoned.

This lesson turns the report’s drawdown numbers into a description of an experience, computes the one figure AmiBroker does not report, and gives you a procedure for choosing a risk fraction that survives contact with the person who has to hold it.

Three drawdown figures appear in the modern portfolio report, and they are not interchangeable.

  • Max. system drawdown and Max. system % drawdown — the largest peak-to-valley decline in portfolio equity, in currency and in percent. Portfolio equity is available cash plus the value of every open position, so this includes unrealised losses on positions you were still holding. The percentage is reported as a negative number.
  • Max. trade drawdown and Max. trade % drawdown — the worst excursion inside a single trade. In the portfolio backtester the percentage is computed against the actual trade value at entry, not against total equity; the old backtester used total equity, so the same trade reports very different numbers in the two engines.
  • Ulcer Index — the square root of the sum of squared drawdowns divided by the number of bars. Because every bar spent below a previous high contributes, it penalises long drawdowns as well as deep ones, which makes it the closest thing in the report to a measure of endurance. Lower is better. Ulcer Performance Index divides an excess return by it.

Two properties of Max. system % drawdown are worth stating plainly, because a great deal of overconfidence rests on forgetting them.

It is one observation from one path. Your test produced a particular sequence of trades in a particular order. Shuffle the order and the worst drawdown changes, usually for the worse — that is what Part 33’s Monte Carlo work is for. There is no sense in which the historical maximum is a limit.

It is measured on closing equity. The portfolio backtester computes trade and system drawdowns from the close, regardless of the drawdown-basis setting, which the User’s Guide notes and marks as subject to change. Intrabar, the account was lower than the report says.

The figure that is not in the report: time underwater

Section titled “The figure that is not in the report: time underwater”

Depth is only one axis. The other is how long the account stayed below its previous high, and AmiBroker does not report it as a named metric. You have to compute it, and it is easy, because the portfolio backtester writes its equity curve to a composite symbol you can read.

Underwater, bar by bar

Two arrays, four lines of AFL. The report tells you the −11.1%; it does not tell you it lasted three bars.
Bar123456
Portfolio equity10010810496102110
Highest(equity)100108108108108110
Drawdown %0.00.0-3.7-11.1-5.60.0
equity >= peak110001
BarsSince(at new high)001230
Two arrays, four lines of AFL. The report tells you the −11.1%; it does not tell you it lasted three bars.

A chart pane showing the drawdown of the last portfolio backtest on every bar, together with how many bars had passed since the equity was last at a high, and a title line carrying the worst drawdown and the longest underwater stretch.

Complete runnable AFL

underwater-curve.afl
// underwater-curve.afl
// Part 34 - Drawdown and Risk of Ruin in Practice
//
// A chart of the thing you actually have to live through: how far below its own
// previous high the portfolio was, on every bar, and how long it stayed there.
//
// AmiBroker's report gives you Max. system % drawdown - one number, the worst
// moment in the whole test. It does not give you a "time underwater" metric.
// This formula computes it from the portfolio equity the backtester writes to
// the special composite symbol ~~~EQUITY.
//
// HOW TO USE IT:
// 1. Run a PORTFOLIO backtest. The backtester creates or updates ~~~EQUITY.
// 2. Open any chart, apply this formula to a new pane.
// 3. The pane shows the drawdown of the LAST portfolio backtest you ran,
// regardless of which symbol the chart is displaying.
//
// ASSUMPTIONS AND LIMITS:
// - ~~~EQUITY holds the equity of the most recent portfolio backtest only.
// Run a different backtest and this chart silently changes meaning. Note
// down which run you are looking at.
// - Highest() runs from the first bar in the database, not from the first bar
// of your test range. Bars before your backtest started are not meaningful;
// read the chart over the tested range only.
// - Drawdown here is measured on closing equity, bar by bar. That matches the
// basis the portfolio backtester uses for its own drawdown figures.
// - "Bars", not days. On daily data a bar is a trading day, so a year is
// roughly 250 bars, not 365.
_SECTION_BEGIN( "Underwater curve" );
PortEquity = Foreign( "~~~EQUITY", "C" );
// Running peak equity. Max() keeps the division safe on bars before the
// backtest wrote anything, where the composite is zero.
PeakEquity = Max( Highest( PortEquity ), 1 );
Underwater = 100 * ( PortEquity / PeakEquity - 1 );
// A new equity high resets the clock. BarsSince counts how long ago that was.
AtNewHigh = PortEquity >= PeakEquity;
BarsUnder = BarsSince( AtNewHigh );
WorstDD = Lowest( Underwater );
LongestUnder = Highest( BarsUnder );
Plot( Underwater, "Drawdown %", colorRed, styleArea );
Plot( 0, "", colorBlack, styleNoLabel | styleNoRescale );
// Own scale, because a bar count and a percentage do not share an axis.
Plot( BarsUnder, "Bars since equity high", colorBlueGrey,
styleLine | styleOwnScale | styleNoLabel );
Title = "Portfolio underwater curve"
+ " | now: " + WriteVal( Underwater, 1.1 ) + "%"
+ " after " + WriteVal( BarsUnder, 1.0 ) + " bars"
+ " | worst so far: " + WriteVal( WorstDD, 1.1 ) + "%"
+ " | longest stretch below a high: "
+ WriteVal( LongestUnder, 1.0 ) + " bars";
_SECTION_END();

Download underwater-curve.afl60 lines

Foreign( "~~~EQUITY", "C" ) reads the special composite symbol the portfolio backtester writes. The Equity() function is the old single-security backtester and does not model portfolio effects at all; the documented replacement for reading portfolio-level equity in a formula is exactly this composite ticker.

Highest() gives the running maximum since the first bar in the database, so PortEquity / PeakEquity − 1 is the drawdown on every bar. AtNewHigh is true whenever equity is at its own peak, and BarsSince() counts how long ago that last happened, which is the underwater duration. Lowest() and Highest() applied to those two arrays give the worst drawdown and the longest stretch for the title.

  • Foreign( ticker, datafield ) — reads another symbol’s arrays onto the current chart’s bars. ~~~EQUITY is created by the portfolio backtester and holds the equity of the most recent run only.
  • Highest( array ) and Lowest( array ) — running extremes since the first bar in the database. Not to be confused with HHV() and LLV(), which use a fixed lookback window.
  • BarsSince( array ) — bars elapsed since the condition was last true. It counts bars, not days: on daily data a year is roughly 250 bars.

Check it against the report: the worst value on this chart, over your backtest range, should match Max. system % drawdown closely. If it does not, the usual cause is that Highest() starts at the first bar in the database rather than the first bar of your test range, so bars before the backtest began — where the composite is zero or flat — are contaminating the peak. Restrict the chart’s visible range to the tested period and re-read it.

Two things go wrong routinely. The composite holds the last backtest you ran, so a chart left open after a different run silently changes meaning: note which run you are looking at. And BarsSince() counts bars, so an intraday database gives you an underwater duration in five-minute bars, which is not the number you want to quote. As an extension, add a second pane plotting the same underwater curve for a buy-and-hold benchmark and compare the two duration figures rather than the two returns.

The report presents a drawdown as a completed shape. You know where it bottomed because you can see the right-hand side of the curve. Living through one is different in exactly one respect, and the difference is everything: at no point during a drawdown can you tell it from the beginning of a permanent decline.

That is not a psychological weakness; it is an information problem. The evidence available at the bottom of the worst stretch in your backtest is: a rule that has lost money for a year and a half, and a backtest that said it would not. Every argument for continuing is an argument from prior belief. Every argument for stopping is an argument from recent data. Both are reasonable, which is why the decision has to be made in advance and written down.

Three specific failure modes are worth naming, because each converts a temporary decline into a permanent one:

  • Cutting size at the bottom. Halving position size after a 30% drawdown means the recovery arrives at half strength. The drawdown becomes a realised, structural loss of capital rather than a dip. This is the single most expensive reaction available.
  • Skipping signals. Taking eight of the next ten trades instead of all ten is no longer the system that was tested, and the two you skipped are as likely to be the recovery as the ones you took. The backtest offers no evidence about a discretionary subset of itself.
  • Switching systems after the worst stretch. The moment a strategy has performed worst is the moment its recent evidence looks weakest, which is exactly when it is most tempting to replace it with something whose recent evidence looks strongest. Repeat that a few times and you have systematically bought the top of every equity curve you own.

“Risk of ruin” is the probability that equity falls below a level you have defined as the end of the exercise. Two things about that sentence deserve emphasis: the level is yours to define — it is rarely zero, and for most people it is the point at which they stop — and the probability is a model output, entirely dependent on assumptions about trade independence and a stable distribution of outcomes, both of which are wrong in the ways this part has been describing. Part 33 covers the simulation machinery and its limits properly.

The part that needs no simulation is the compounding. Under fixed-fractional sizing, k consecutive full losses at a risk fraction r leave you with (1 − r)^k of your capital:

Risk per trade After 10 straight losses After 20 After 30
1% −9.6% −18.2% −26.0%
2% −18.3% −33.2% −45.5%
3% −26.3% −45.6% −59.9%
5% −40.1% −64.2% −78.5%

Again, arithmetic rather than evidence. Two features of the table matter.

The relationship is close to linear in r over the range anyone sensible uses — doubling the risk fraction roughly doubles the drawdown from a losing run. But the recovery requirement from the previous section is convex, so doubling the risk fraction rather more than doubles the pain. The 5% row after twenty losses needs a gain of 179% to get back to level; the 1% row needs 22%.

And twenty consecutive losses is not an exotic scenario. A rule that wins forty per cent of its trades and takes two hundred trades a year will produce runs of that length; a rule whose positions are correlated can produce them in an afternoon. "LosersMaxConsecutive" in the report tells you the longest run your test happened to contain, which is a lower bound on what the rule can do rather than an upper one.

There is no correct risk fraction, and any source offering you one has stopped describing your situation. What can be offered is a procedure that makes the choice deliberate.

  1. Read the worst stretch out of your own test — both axes. Take Max. system % drawdown from the report and the longest underwater run from the formula above. Write both down, with the universe, the period and the cost assumptions attached.
  2. Assume the future contains worse. The historical maximum is one draw. As a working convention — and it is a convention, not a result — plan for something like half again the depth and twice the duration, then check that assumption against the Monte Carlo percentiles in Part 33 rather than trusting the multiplier.
  3. Convert to currency. “−34%” is abstract; the same number in the currency of your account, next to what that sum represents to you, is not. Do this step in writing.
  4. Ask the duration question separately, and answer it honestly. Not “could I accept losing that?” but “would I still be placing these orders in month fourteen of not making money, with the rule still signalling and nothing to show for it?”
  5. Scale the risk fraction until both answers are yes. Everything in this part scales nearly linearly: halving r roughly halves the depth. It also roughly halves the returns, and that trade is the actual decision.
  6. Write down the number and the reasoning, then leave it alone. Set a review date — a calendar date, not a drawdown level. A sizing rule revised during a drawdown is a sizing rule revised by the drawdown.

Part 35 puts this into the wider research process, where the decision is recorded as an artefact alongside the strategy specification rather than carried around in your head.

Max. system % drawdown is one number from one path, measured on closing equity, and the recovery arithmetic makes its depth matter more than it appears: a third of the account gone needs nearly half again to come back. Time underwater is the other axis, AmiBroker does not report it, and four lines of AFL reading ~~~EQUITY will give it to you.

Ruin is a model output whose assumptions this part has spent four lessons undermining. The compounding underneath it is not: consecutive losses at a fixed fraction multiply, and the fraction you choose scales the depth roughly linearly while scaling the difficulty of recovery faster than that.

Which leaves position sizing doing the job it is actually for. It cannot make a weak rule work. What it can do is set the size of the worst plausible stretch at a level you will still be trading through when it ends.

Check your understanding

Question 1. A backtest reports Max. system % drawdown of −40%. What gain is required from the bottom to return to the previous equity high?
Show the answer and why

Answer: +66.7%

x/(1 − x) with x = 0.40 gives 0.667. Falling 40% leaves 60 from 100, and 100/60 − 1 = 66.7%. The asymmetry is why depth is punished harder than a percentage figure suggests, and why halving a risk fraction is not a symmetric trade.

Question 2. Which AmiBroker report metric comes closest to measuring how long an account spent below its previous high?
Show the answer and why

Answer: Ulcer Index

Ulcer Index is the square root of the sum of squared drawdowns divided by the number of bars, so every bar spent underwater contributes and long shallow drawdowns are penalised as well as short deep ones. Max. system % drawdown is depth only. Standard Error and Risk-Reward Ratio are equity-line regression statistics and say nothing about drawdown duration.

Question 3. You read portfolio equity in a chart formula with Foreign("~~~EQUITY","C"). Which statement is correct?
Show the answer and why

Answer: It holds the equity of the most recent portfolio backtest only

The composite is written by the portfolio backtester and reflects the last run. Equity() is the old single-security backtester and is documented as not modelling portfolio effects such as skipped trades, position limits or cash competition. Nothing here is edition-restricted.

Question 4. Which of these does a 2% risk-per-trade rule actually constrain? Select all that apply.
Show the answer and why

Answer: The loss on one position when the stop fills at its level

Only the first. A gap delivers whatever price the market opens at; correlated positions fail together, so ten 2% risks can be a single 20% event; and consecutive losses compound — twenty of them costs about a third of the account. Each of those needs a separate control: fill assumptions, position and sector limits, and the risk fraction itself.

Sources for this lesson

5 verified · checked 2026-08-31

  1. 01AmiBroker User's Guide — System test report window§ Max. system drawdown, Ulcer Index, known differencesamibroker.com/guide/w_report.html2026-08-31
  2. 02AmiBroker User's Guide — Portfolio-level backtesting§ Portfolio equityamibroker.com/guide/h_portfolio.html2026-08-31
  3. 03AFL Function Reference — Equity§ Reading portfolio equity via the ~~~EQUITY tickeramibroker.com/guide/afl/equity.html2026-08-31
  4. 04AFL Function Reference — Foreignamibroker.com/guide/afl/foreign.html2026-08-31
  5. 05AmiBroker User's Guide — Monte Carlo simulationamibroker.com/guide/h_montecarlo.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.