Estimating Historical Volatility from Close Prices
Summary
The question concerns calculating historical volatility from a sequence of closing prices using a close-to-close method. The proposed implementation forms price ratios, takes logarithmic returns, and combines the sum of squared returns with a correction based on the squared sum of returns to estimate variance before taking its square root. The author reports that this calculation sometimes produces negative variance and asks whether the implementation or formula is at fault.
The answer offers a different sketch: compute percentage changes, calculate their average, find squared deviations from that average, and take the square root of their mean. It does not explain the discrepancy with the original formula or fully validate either method. In particular, the answer's percentage-return approach differs from a log-return estimator, and its handling of the first price observation merits care. The exchange is a starting point for distinguishing return definitions and variance calculations, rather than a complete treatment of volatility estimation or debugging.
Key ideas
- Close-to-close volatility estimation begins by converting prices into returns.
- Log returns and percentage changes are different inputs to a volatility calculation.
- Variance is based on squared deviations from a return mean in the answer's alternative sketch.
- The exchange does not diagnose why the proposed formula produced negative variance.
Tags
Full text
# Historical volatility from close prices (Haug pg 166)
# Historical volatility from close prices (Haug pg 166)
I have implemented a function for calculating historical volatility using close the close method as described by Haug on page 166.
When I implemented the formula given by Haug, it resulted in some negative values for the variance. The data I am using is not suspect, so the fault must lie in either:
- my implementation or
- the formula itself.
Here is a rough sketch of my implementation function (in Python)
```
# close_prices is a time sorted list of pricedata objects
# returns a list of calculated volatilities
def calc_volatility(close_prices, period):
startpos, stoppos, raw_vols = (0, period, [])
while True:
subset = close_prices[startpos:stoppos+1]
period_returns = [ subset[i].close_price/subset[i-1].close_price for i in range(1,len(subset)) ]
log_returns = [ math.log(x) for x in period_returns ]
log_squared_returns = [ math.log(pow(x,2)) for x in period_returns ]
sum_squares_1 = sum( log_squared_returns ) / (period-1)
sum_squares_2 = pow( sum( log_returns ), 2) / (period * (period -1))
variance = sum_squares_1 - sum_squares_2
print "ss1: {0} - ss2: {1}. Variance: {2}".format(sum_squares_1, sum_squares_2, variance)
volatility = math.sqrt(variance)
raw_vols.append (volatility)
startpos += period
stoppos += period
if stoppos >= len(close_prices):
break
return raw_vols
```
Is there something wrong in my implementation, or is the formula I am using, incorrect?
## Answer by mike (score 4)
https://quant.stackexchange.com/a/14347
I have a different solution, which calculates the vol for a list of prices.
```
import math
#workout volatility
def perc_change(price_list):
return [(v / price_list[abs(i-1)])-1 for i, v in enumerate(price_list)]
def variance(price_list):
perc = perc_change(price_list)
avg = average(perc)
return [(x - avg)**2 for x in perc]
def average(x):
return sum(x)/len(x)
var = variance(list_of_prices)
volatility = math.sqrt(average(var))
```Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.