Calculating Bollinger Bands with Rolling Mean and Standard Deviation
Summary
The document explains the standard construction of Bollinger Bands: calculate a rolling average of price, then place upper and lower bands a chosen number of rolling standard deviations above and below that average. It includes examples using a 20-period window with two standard deviations and another with a longer window and a different multiplier. It also recommends checking whether the rolling average aligns sensibly with the input price series when a plotted result looks wrong.
A point of disagreement concerns the standard-deviation convention. One answer argues that Bollinger Bands should use the population measure, which corresponds to a degrees-of-freedom adjustment of zero, while earlier examples use the sample measure by default. The discussion shows how modern rolling calculations can specify that adjustment. It does not establish that one parameterization is universally appropriate, and the original plotting problem is not diagnosed from the information provided. Window length and band multiplier remain user choices.
Key ideas
- Bollinger Bands combine a rolling price mean with upper and lower offsets based on rolling standard deviation.
- The window length and standard-deviation multiplier determine how the bands respond to price movement.
- Sample and population standard deviation use different degrees-of-freedom conventions and produce different band widths.
- When a plot looks wrong, checking the rolling mean against the input prices can help identify data or calculation issues.
Tags
Full text
# Calculating Bollinger Band Correctly
# Calculating Bollinger Band Correctly
My bollinger band comes out like the below, which doesn't seem right. Any idea what is wrong with my code for calculating upper and lower bollinber bands?
I obtained my data from here
```
start, end = dt.datetime(1976, 1, 1), dt.datetime(2013, 12, 31)
sp = web.DataReader('^GSPC','yahoo', start, end)
here are my bollinger calculations
```
calculation for bollinger band
```
ave = pd.stats.moments.rolling_mean(self[name], window)
std = pd.stats.moments.rolling_std(self[name], window)
self['upper'] = ave + (2 * std)
self['lower'] = ave - (2 * std)
```
## Answer by Sohel Khan (score 17)
https://quant.stackexchange.com/a/31905
In Pandas 0.19.2++:
```
def Bolinger_Bands(stock_price, window_size, num_of_std):
rolling_mean = stock_price.rolling(window=window_size).mean()
rolling_std = stock_price.rolling(window=window_size).std()
upper_band = rolling_mean + (rolling_std*num_of_std)
lower_band = rolling_mean - (rolling_std*num_of_std)
return rolling_mean, upper_band, lower_band
def main():
price_series = get_data(ticker, dates) # it is a Pandas series...
rolling_avg_price, upper_band, lower_band = Bolinger_Bands(price_series, 20, 2)
do_other_processing(rolling_avg_price, upper_band, lower_band)
...
```
## Answer by wlbsr (score 11)
https://quant.stackexchange.com/a/16813
```
def bbands(price, length=30, numsd=2):
""" returns average, upper band, and lower band"""
ave = pd.stats.moments.rolling_mean(price,length)
sd = pd.stats.moments.rolling_std(price,length)
upband = ave + (sd*numsd)
dnband = ave - (sd*numsd)
return np.round(ave,3), np.round(upband,3), np.round(dnband,3)
sp['ave'], sp['upper'], sp['lower'] = bbands(sp.Close, length=30, numsd=1)
sp= sp[-200:]
sp.plot()
```
## Answer by John (score 10)
https://quant.stackexchange.com/a/35870
I believe that the answers given here are incorrect as they return the sample standard deviation while the the population measure is the correct calculation for Bollinger Bands. The bands usign the sample calc will be too wide. Pandas does not appear to allow a choice between the sample and population calculations for either solution presented here.
```
sd = pd.stats.moments.rolling_std(price,length)
rolling_std = stock_price.rolling(window=window_size).std()
```
Numpy does allow a choice, so it should be used until a proper pandas solution is presented.
```
a = np.array([1,2,3,4,5])
print np.std(a, ddof=1) # sample
print np.std(a, ddof=0) # population
>>>
1.58113883008
1.41421356237
>>>
```
https://docs.scipy.org/doc/numpy/reference/generated/numpy.std.html
John Bollinger, CFA, CMT
Well, it appears that pandas has caught up with me. This works correctly now.
```
b = pd.DataFrame([1,2,3,4,5])
print b.rolling(window=5).std() # sample
print b.rolling(window=5).std(ddof=0) # population
```
## Answer by Onyxx (score 2)
https://quant.stackexchange.com/a/11286
Try to plot the rolling mean against your quotes for SP and see if it makes sense. Although you line of code to compute the rolling mean is correct, there might be something wrong in the data that you pass as input.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.