Any analysis of returns starts with these two numbers. Almost every measure of a fund or
strategy, including the Sharpe ratio, is built from them. The expected value post ended
with “two choices can have the same average and very different risk”. This post measures that
difference.
First: daily returns
In finance we rarely work with prices directly. We work with returns: the percentage change
from one day to the next. This is the definition in Romero and Balch’s What Hedge Funds Really
Do (chapter 2):
returns, the datathe meanthe spread: standard deviation, variance
rt=pt−1pt−1
Symbol
Meaning
pt
price on day t
pt−1
price on the day before
rt
return on day t
SPY (the S&P 500 fund) closed 2019 at $223.25 on its first trading day and $217.92 the next:
r=217.92/223.25−1=−0.0239=−2.4%. Returns let you compare a $10 stock with a
$1,000 stock on the same scale. The examples below use five years of daily closes for five
tickers: SPY, AAPL, JPM, XOM and GLD (gold), 2019 to 2023, adjusted for dividends and splits.
Daily returns compound: to get the return over many days, multiply one plus each day’s
return together and subtract one (same chapter):
cumulative return=t=1∏n(1+rt)−1
Read ∏ as “multiply together”, the way ∑ means “add together”. That’s why the two funds
later in this post end the year at different values despite the same average day, and why
$100 in AAPL became $508 over the five years while the same $100 in GLD became $158.
The mean: where the middle is
Plain meaning: add everything up, divide by how many there are.
rˉ=n1t=1∑nrt
SPY’s first five daily returns of 2019, rounded to one decimal: −2.4%, 3.3%, 0.8%, 0.9%, 0.5%.
rˉ=5−2.4+3.3+0.8+0.9+0.5=53.1=0.62%
On an average day that week, SPY made 0.62%. (A wild week: the five-year average
daily return is 0.066%.)
The standard deviation: how far things stray
Plain meaning: how far, typically, a day’s return lands from the average.
The recipe:
For each day, find how far it is from the mean (the deviation).
Square each deviation, so negatives don’t cancel positives.
Average the squares. This is the variance.
Take the square root, to get back to the original units (percent). This is the standard
deviation.
s=n−11t=1∑n(rt−rˉ)2
Worked out for the five days (mean 0.62%):
Day
Return rt (%)
Deviation rt−rˉ
Squared
1
−2.4
−3.02
9.12
2
3.3
2.68
7.18
3
0.8
0.18
0.03
4
0.9
0.28
0.08
5
0.5
−0.12
0.01
Sum
16.43
s2=5−116.43=4.11s=4.11=2.03%
A typical day that week landed about 2 percentage points away from the 0.62% average. Over the
whole five years SPY’s daily standard deviation is 1.32%; that first week of January 2019 was
twice as jumpy as normal.
Why divide by n−1, not n?
This question comes up every time. When you compute the deviations, you measure them from the sample’s
own mean, which is pulled towards the data you happen to have. So the deviations come out a
little too small on average. Bishop and Bishop’s Deep Learning: Foundations and Concepts shows
exactly how much (equation 2.60): the divide-by-n variance comes out, on average, at
E[σML2]=nn−1σ2
of the true variance σ2. Multiplying by n/(n−1) undoes that, which is the same as
dividing by n−1 instead of n (their equation 2.63). It’s called Bessel’s correction, and
the result is the sample standard deviation.
Dividing by n gives the population standard deviation, which is right only when you have
every possible value, not a sample. Romero and Balch’s What Hedge Funds Really Do (chapter 2)
writes volatility with 1/n; with years of daily data the two versions are practically
equal. Here: 2.03% (sample) versus 1.81% (population). With a year
of daily data the difference is tiny, but with five days it’s large.
A practical trap: NumPy’s np.std divides by n by default. Pandas’ .std() divides by
n−1. Use np.std(x, ddof=1) to get the sample version in NumPy.
Five years, five tickers
The same two numbers for each ticker over 2019 to 2023, daily and then annualised (the next
section explains the 252 and the square root):
Ticker
Average daily return
Daily standard deviation
Annual return
Annual standard deviation
$100 became
SPY
0.066%
1.32%
16.7%
21.0%
$206
AAPL
0.150%
2.03%
37.8%
32.2%
$508
JPM
0.075%
2.01%
18.9%
31.9%
$199
XOM
0.072%
2.16%
18.2%
34.3%
$185
GLD
0.041%
0.94%
10.2%
14.9%
$158
Two things to notice. Gold is the calm one: the smallest average and the smallest spread. And
JPM and XOM earned about the same average day as each other with the same risk, yet JPM ended
higher; the swings along the way differed, which is the next section’s point.
Same mean, different risk
To isolate that point I made up two funds with exactly the same average daily return, 0.04%, but different
standard deviations: 0.5% for the calm one, 1.5% for the wild one.
Item
Calm fund
Wild fund
Average daily return
0.04%
0.04%
Daily standard deviation
0.50%
1.50%
$100 after one year
$110.26
$107.52
Same average, but the wild fund ended lower, and not by bad luck. Losses hurt more than
equal gains help: lose 10% and then gain 10%, and you’re at 99%, not 100%. The more a fund swings,
the more this “volatility drag” eats into growth. A rough rule: the yearly growth rate is about
the average return minus half the variance.
From daily to yearly: why √252
There are about 252 trading days in a year. To turn daily numbers into yearly ones, with μ
for the mean and σ for the standard deviation:
μannual≈252×μdailyσannual≈252×σdaily
The mean grows with the number of days, but the standard deviation grows with the square root.
Why?
If days are independent, their variances add up. Over 252 days:
Good days and bad days partly cancel out, so risk grows more slowly than time. I checked it by
simulating 20,000 years of independent days with a 1% daily standard deviation. The standard
deviation of the yearly totals came out at 15.86%. The formula says
252×1%=15.87%.
For our funds: the calm one is 0.5%×252=7.94% a year, the wild one 23.81%.
The same 252 shows up in the Sharpe ratio, which has its own post later in this series.
The 68–95–99.7 rule, and why markets break it
If returns follow a normal distribution (the bell curve), the standard deviation tells you a
lot:
Within
Share of days (normal)
1 standard deviation of the mean
68.3%
2 standard deviations
95.5%
3 standard deviations
99.7%
Real market returns are not quite normal. They have fat tails: extreme days happen far
more often than the bell curve says. I simulated a million days from a fat-tailed distribution
(Student’s t with 3 degrees of freedom) with the same standard deviation:
Item
Normal
Fat-tailed
Days beyond 4 standard deviations
about 0.008%
0.62%
About 77 times more extreme days (0.62 ÷ 0.008). A risk model that assumes the bell curve will badly
underestimate how often a crash day comes. The standard deviation is a good summary of
everyday risk, and a poor guide to the worst days.
The code
import numpy as npimport pandas as pdprices = pd.read_csv("prices.csv", index_col="date", parse_dates=True) # adjusted closesreturns = prices / prices.shift(1) - 1 # r_t = p_t / p_{t-1} - 1spy = returns["SPY"].dropna()mean = spy.mean() # 0.00066 (0.066% a day)sd = spy.std() # 0.0132 (1.32%), pandas divides by n - 1sd_pop = spy.std(ddof=0) # numpy's default, divides by nannual_mean = mean * 252 # 16.7%annual_sd = sd * np.sqrt(252) # 21.0%growth = 100 * (1 + spy).prod() # $100 -> $206 over 2019-2023
Summary
Idea
Formula
Remember it as
Daily return
rt=pt/pt−1−1
Percent change (SPY: −2.4% on 2019’s second day)
Mean
rˉ=∑rt/n
Where the middle is
Sample standard deviation
s=∑(rt−rˉ)2/(n−1)
Typical distance from the middle
Annualise the mean
×252
Grows with time
Annualise the standard deviation
×252
Grows with the square root of time
Volatility drag
growth ≈ mean − variance / 2
Swings cost you, even with the same average
Next
Covariance and correlation: how two assets move together, and why combining two risky assets
can give you something less risky than either one.
References
Philip J. Romero and Tucker Balch, What Hedge Funds Really Do: An Introduction to Portfolio Management (Business Expert Press, 2014), chapter 2: returns, cumulative return, volatility
Christopher M. Bishop and Hugh Bishop, Deep Learning: Foundations and Concepts (Springer, 2024), chapter 2, section 2.3: why dividing by n underestimates variance (equation 2.60) and the n−1 correction (2.63)
Yves Hilpisch, Python for Finance: Mastering Data-Driven Finance (2nd ed., O’Reilly, 2018), chapter 8, “Financial Time Series”