# Chapter 12: Monte Carlo: the fan chart

*The Analyst's Handbook, Sifter's textbook for student investors · By Matt Lang and Bree Lang · Models and simulations · https://sifter.finance/textbook/ch12-montecarlo*

A thousand invented futures, one fan chart, and the half-sigma-squared tax.

Where this is on Sifter: Portfolio · Simulate · Project

The Project tab draws a cone of possible portfolio values fanning out across the next year. Before we take the picture apart, take a moment to think about what a chart like this could possibly be built from, because next year has not happened yet. The answer is that behind the fan are **1,000 simulated futures**, where each future is a plausible sequence of 252 daily returns and each one finishes at a different ending value. From there, the fan's bands are percentiles taken across the thousand endings. The middle line is the median ending value, and the P5-P95 band is drawn so that nine futures out of every ten finish inside of it. In other words, when you look at the fan you are looking at a thousand possible years stacked on top of one another and summarized. (The technique is called Monte Carlo, a name coined at Los Alamos in the 1940s after the casino where a colleague's uncle liked to gamble.)[1]

Hopefully a question has been nagging at you while reading that description. Where do 252 imaginary daily returns actually come from? Sifter has two engines for producing them, and it picks between the two based on how much real history your book can offer. Let's take them one at a time.

**Engine 1: Geometric Brownian Motion (GBM)**

```
r = μ_d + σ_d × Z,   step = 1 + r,   μ_d = (R_ann − ½σ²) / 252,   σ_d = σ_ann / √252
```

Geometric Brownian Motion (GBM) is the name for a random walk in percentage terms, one where the portfolio moves by a random percentage each day rather than by a random number of dollars. In the first line, S_t is the portfolio's value on day t and S_{t+1} is its value one day later. The day's return is a drift term μ_d plus a volatility term σ_d Z, where Z is a random draw from the standard normal distribution (mean zero and standard deviation one, so it lands between −2 and +2 on about 19 days out of 20), generated by Box-Muller.[2] The next two lines scale your inputs down to a single day. R_ann and σ_ann are the annual return and annual volatility you typed in, μ_d is the daily drift (with half the variance subtracted, and the callout below explains why) and σ_d is the daily volatility. GBM is the thin-history fallback, because it needs nothing more than a return and a volatility estimate, but it assumes that returns are normal and that each day is independent of the last.

> **Why the drift subtracts half the variance** Recall from Chapter 3's compounding quiz that a portfolio that goes +10% and then −10% does not end up flat, but instead ends up down 1%. Bouncing around costs a compounding portfolio money all by itself, which means that volatility drags down geometric growth even when the average return looks fine, and the −½σ² term is exactly that drag. In the textbook version of the model (the one that steps by an exponential) subtracting it is what makes the average simulated future grow at the return you typed in, and leaving it out is the most common Monte Carlo implementation bug. Sifter steps by one plus the return instead, and with that step the subtraction leans conservative: the typical path grows a little slower than the return you gave it, by roughly a full σ² rather than half of one. At 20% volatility that extra half is two points a year, which is a rounding error next to the width of the fan, but you should know that the engine errs on the conservative side.

### Worked example: Worked example: one GBM day by hand

Let's build one simulated day by hand. The portfolio starts at $100, the inputs are a 10% annual return and 20% annual volatility, and today's random draw happens to be Z = +1 (one standard deviation of good luck).

1. **Daily drift** μ_d = (0.10 − ½ × 0.20²) / 252 = (0.10 − 0.02) / 252 = 0.08 / 252 *μ_d ≈ 0.000317 per day. Note the −0.02: half of 0.04 variance, the volatility drag.*
2. **Daily volatility** σ_d = 0.20 / √252 = 0.20 / 15.8745 *σ_d ≈ 0.0126 per day.*
3. **Apply the step** r = 0.000317 + 0.0126 × 1 = 0.012917, so the step is 1 + 0.012917 *New value = 100 × 1.0129 = $101.29. One simulated day done; a path is 252 of these, a fan is 1,000 paths.*

### Practice

Same inputs, but today's draw is Z = −1 (one standard deviation of bad luck). What is the new portfolio value in dollars, starting from $100?

**Solution.** 100 × (1 + 0.000317 − 0.0126) = 100 × 0.9877 = $98.77. Take a moment and compare this to the up-day value of $101.29. The two Z draws were equal and opposite, and the two dollar moves differ by twice the daily drift, about six cents, which is all a single day of drift is worth against a one-sigma swing.

**Engine 2: bootstrap (the default when history permits)**

```
resample L-day blocks of YOUR actual daily returns,  L ≈ ∛n, circular wrap
```

Instead of inventing normal returns, the block bootstrap re-deals chunks of the portfolio's own history in random order. Here n is the number of real trading days in the backtest window and L is the block length, the cube root of n rounded to a whole number and never shorter than five days (a year of history gives blocks of about six days). Resampling in blocks rather than one day at a time preserves volatility clustering, so calm stretches and storms travel together, and it is the standard fix for data where one day depends on the last.[3] The engine needs enough history for the blocks to mean something, which means that the platform picks the engine by the length of the record. With 60 or more days it resamples in blocks. With 20 to 59 days it resamples one day at a time, which keeps the fat tails of your history but loses the clustering. With fewer than 20 days there is not enough history to re-deal, and it falls back to GBM.

### Check yourself

Your fund's history includes a brutal three-day losing streak. Which engine can reproduce a streak like that in the simulated futures?

- GBM: it has volatility, so it has streaks. Not quite. GBM draws each day as an independent normal, which means that a bad day today tells the simulation nothing about tomorrow. It will produce plenty of down days, but it has no memory of them, and three-sigma streaks come out far rarer in GBM than real markets deliver them.
- Block bootstrap: the streak travels inside a block. **(correct)** Right. If the streak fits inside a resampled block, then the simulated futures replay the entire episode, aftermath and all, whenever that block comes up in the deal. This means that the simulation inherits the character of your actual history, and it is the reason the block bootstrap is the default when your book has enough history.
- Neither: simulations smooth out extremes. The opposite is true for the bootstrap, which re-deals your real extremes straight back into the simulated futures without smoothing anything away.

Now that we know where the futures come from, let's read the output. Beneath the fan are four tiles: the **median** ending value, the **mean**, **P(Loss)** (the share of the thousand futures that finish below the money you put in) and **P(+20%)**. The **P5 and P95** edges of the cone are read off the chart itself, where the legend labels the two shaded bands, and a badge above the fan says which engine drew it and, for the bootstrap, how many real days it re-dealt. These numbers are easy to read and easy to over-read, so we should agree on some ground rules before you quote them to anyone.

First, the fan is manufactured entirely from *your inputs*. If you feed the simulation a fantasy return assumption, it will not object, and it will paint you a beautifully precise picture of the fantasy. Second, running more paths does not narrow the band, but instead only steadies the band's edges, because extra paths pin the percentiles down without changing what the percentiles are. Many of you may look at a wide band and suspect that something has gone wrong with the simulation, but a wide band is the simulation doing its job. The width is reporting how much uncertainty your own inputs imply about the next year, which means that the only way to earn a narrower fan is to genuinely face less uncertainty. The figure below shows the fan the Project tab drew for the sample book, with the badge naming the engine and the four figures beneath it.

![The Monte Carlo simulation panel on the sample book: a badge showing block bootstrap with a block length of six resampled from 252 real days, a fan chart of a year of simulated values with the median line, the P25 to P95 bands shaded green above and red below a dashed break-even line, and four tiles for Median, Mean, P(Loss) and P(+20%).](https://sifter.finance/textbook/figures/ch11-fan.png)

*The Project tab's fan, on the sample book. The badge is the first thing to read, because it says which engine drew the fan. Here the book had a full year of history, so the block bootstrap re-dealt its own days in blocks of six. The dashed line is the money put in, the median runs through the middle of the cone, and the P5 edge staying above the dashed line for most of the year is what the tiny P(Loss) beneath it is measuring. Your numbers will differ.*

### Lab: Lab: run the fan twice

1. Go to Portfolio › Simulate › Project and run a 1,000-path, 1-year simulation on your book (or any proposed book).
2. Write down the Median, the P5 and P95 lines, and P(Loss).
3. Run it again with identical inputs. The individual squiggles are brand new, but the percentile lines should barely move, which is the law of large numbers operating on the percentiles.
4. Now switch the model to Normal (GBM), because the bootstrap re-deals your real history and ignores the return and volatility inputs, then double the volatility input and rerun. The median should barely move while the fan gets wider, and the widening is proportional, so measure the distance from P5 to P95 before and after and it should have roughly doubled. (On a calm book that is still a narrow fan.) Volatility controls how wide the fan is rather than which direction it leans.

## Sources

1. Metropolis, N. (1987). *The beginning of the Monte Carlo method*. Los Alamos Science, Special Issue, 125-130 https://mcnp.lanl.gov/pdf_files/Article_1987_LAS_Metropolis_125--130.pdf
2. Box, G. E. P., and Muller, M. E. (1958). *A note on the generation of random normal deviates*. Annals of Mathematical Statistics, 29(2), 610-611 https://projecteuclid.org/journals/annals-of-mathematical-statistics/volume-29/issue-2/A-Note-on-the-Generation-of-Random-Normal-Deviates/10.1214/aoms/1177706645.full
3. Kunsch, H. R. (1989). *The jackknife and the bootstrap for general stationary observations*. Annals of Statistics, 17(3), 1217-1241 https://projecteuclid.org/journals/annals-of-statistics/volume-17/issue-3/The-Jackknife-and-the-Bootstrap-for-General-Stationary-Observations/10.1214/aos/1176347265.full
