For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

# BollingerBands Squeeze

• If anyone needs this, here is a BBSqueeze indicator.

implementation is based on this: https://www.netpicks.com/squeeze-out-the-chop/

BBSqueeze

``````from __future__ import (absolute_import, division, print_function,
unicode_literals)

from . import KeltnerChannel

class BBSqueeze(bt.Indicator):

'''
https://www.netpicks.com/squeeze-out-the-chop/

Both indicators are symmetrical, meaning that the upper and lower bands or channel lines are the same distance from the moving average. That means that we can focus on only one side in developing our indicator. In our case, we’ll just consider the upper lines.

The basic formulas we need are:

Bollinger Band = Moving Average + (Number of standard deviations X Standard Deviation)
Keltner Channel = Moving Average + (Number of ATR’s X ATR)

Or if we translate this into pseudo-code:

BBUpper = Avg(close, period) + (BBDevs X StdDev(close, period))
KCUpper = Avg(close, period) + (KCDevs X ATR(period))

The squeeze is calculated by taking the difference between these two values:

Squeeze = BBUpper – KCUpper

Which simplifies down to this:

Squeeze = (BBDevs X StdDev(close, period)) – (KCDevs X ATR(period))
'''

lines = ('squeeze',)
params = (('period', 20), ('devfactor', 2.0), ('movav', bt.ind.MovAv.Simple),)

plotinfo = dict(subplot=True)

def _plotlabel(self):
plabels = [self.p.period, self.p.devfactor]
plabels += [self.p.movav] * self.p.notdefault('movav')
return plabels

def __init__(self):
bb = bt.ind.BollingerBands(
period=self.p.period, devfactor=self.p.devfactor, movav=self.p.movav)
kc = KeltnerChannel(
period=self.p.period, devfactor=self.p.devfactor, movav=self.p.movav)
self.lines.squeeze = bb.top - kc.top
``````

KeltnerChannel

``````from __future__ import (absolute_import, division, print_function,
unicode_literals)

class KeltnerChannel(bt.Indicator):

lines = ('mid', 'top', 'bot',)
params = (('period', 20), ('devfactor', 1.5),
('movav', bt.ind.MovAv.Simple),)

plotinfo = dict(subplot=False)
plotlines = dict(
mid=dict(ls='--'),
top=dict(_samecolor=True),
bot=dict(_samecolor=True),
)

def _plotlabel(self):
plabels = [self.p.period, self.p.devfactor]
plabels += [self.p.movav] * self.p.notdefault('movav')
return plabels

def __init__(self):
self.lines.mid = ma = self.p.movav(self.data, period=self.p.period)
atr = self.p.devfactor * bt.ind.ATR(self.data, period=self.p.period)
self.lines.top = ma + atr
self.lines.bot = ma - atr
``````

• BBSqueeze with configureable multiplicators for bb and keltner

``````from __future__ import (absolute_import, division, print_function,
unicode_literals)

from . import KeltnerChannel

class BBSqueeze(bt.Indicator):

'''
https://www.netpicks.com/squeeze-out-the-chop/

Both indicators are symmetrical, meaning that the upper and lower bands or channel lines are the same distance from the moving average. That means that we can focus on only one side in developing our indicator. In our case, we’ll just consider the upper lines.

The basic formulas we need are:

Bollinger Band = Moving Average + (Number of standard deviations X Standard Deviation)
Keltner Channel = Moving Average + (Number of ATR’s X ATR)

Or if we translate this into pseudo-code:

BBUpper = Avg(close, period) + (BBDevs X StdDev(close, period))
KCUpper = Avg(close, period) + (KCDevs X ATR(period))

The squeeze is calculated by taking the difference between these two values:

Squeeze = BBUpper – KCUpper

Which simplifies down to this:

Squeeze = (BBDevs X StdDev(close, period)) – (KCDevs X ATR(period))
'''

lines = ('squeeze',)
params = (('period', 20), ('bbdevs', 2.0), ('kcdevs', 1.5), ('movav', bt.ind.MovAv.Simple),)

plotinfo = dict(subplot=True)

def _plotlabel(self):
plabels = [self.p.period, self.p.bbdevs, self.p.kcdevs]
plabels += [self.p.movav] * self.p.notdefault('movav')
return plabels

def __init__(self):
bb = bt.ind.BollingerBands(
period=self.p.period, devfactor=self.p.bbdevs, movav=self.p.movav)
kc = KeltnerChannel(
period=self.p.period, devfactor=self.p.kcdevs, movav=self.p.movav)
self.lines.squeeze = bb.top - kc.top

``````

• Thanks for sharing this @dasch.

Flipping positions between BBands is a part of my primary strategy whilst waiting for breakouts to occur. I've been using price action relative to dynamic highs and lows to identify breakouts from choppy zones.

I'll see how introducing the Keltner Channel performs.

M

});