Best Bollinger Bands Strategy // 93% Win Rate

In today’s post I’ve got another great high probability strategy for you that is probably gonna blow your mind. This one doesn’t trigger a lot of signals but when it does trigger signals the win probabilities are in the 90% range for the major US indexes. So stick around because if you love winning strategies, this one is an all-time classic.

STRATEGY INTRODUCTION

Today I’m going to teach you a strategy known as the Basic Bollinger. It only requires a single indicator. An indicator is just an overlay we add to a candlestick chart to better understand the price action. The indicator we are using today is known as the Bollinger Bands. This strategy doesn’t trigger a lot of buy signals but when those signals are triggered I highly recommend that you consider taking advantage of them.

Remember though that no strategy works with all markets so its absolutely critical that you always use a back-test to determine if this strategy is viable for whatever market and period that you are trading.

This is the Bollinger Bands indicator.

It consists of a channel, basically 3 data points, or bands. The middle band is typically the 20-day simple moving average. The top band is 2 standard deviations above the middle band and the bottom band is 2 standard deviations below the middle band. When the current price is near the top band the security is said to be overbought and when its near the lower band its said to be oversold.

If the top and bottom bands are narrow this means that volatility is low, which means that we should be buying options and if the bands are very wide then that implies high volatility so we should be selling options and collecting premium. If the bands are narrowing that usually indicates a large breakout of some kind is coming soon.

BOLLINGER BASIC RULES

This one has just 4 simple rules. Well really it actually has just 2 rules if you do not change the default settings for the indicator.

Rule #1: Set the Bollinger Bands Moving Average Length to 20
Rule #2: Set the upper and lower bands to 2 standard deviations
Rule #3: Enter position when closing price crosses above the lower band
Rule #4: Exit the trade when the last price touches the upper band

BACKTEST RESULTS

Lets apply this strategy to the chart and evaluate how it performs. You aren’t going to have this strategy yet in your list of indicators on tradingview.com but don’t worry in the last part of the video we will create the strategy together and, of course the full source code is available at the end of the post if you prefer to just copy and paste in order to follow along.

I’ve set the backtest start period to January 1st 2010 and the end period to December 30th of 2030. Since this isn’t a long term investment strategy I’m not really all that concerned with how the strategy performed 31 years ago in 1990 I’m more interested in how it has done over the last 11 years or so.

We are currently looking at the S&P500 ETF $SPY and you might want to run this back-test on your own SPY chart to be sure I’m not messing with you because look at that win-rate!

I know your mother taught you that there is no such thing as a free lunch. If something is too good to be true then it isn’t true, yet here we are with an astonishing 93% win-rate. Other than March of 2020 this strategy hasn’t produced a losing trade since April of 2012. Can you imagine winning every single trade you make for 9 years in a row! That’s just amazing

Okay so what about some of the other liquide ETFs. How did they perform?

NASDAQ 100 (QQQ) – 83% win-rate
RUSSELL 2000 (IWM) – 80% Win-Rate
UTILITIES (XLU) – 83% Win-Rate
CONSUMER STAPLES (XLP) – 87% Win-Rate
SEMI-CONDUCTORS (SOXX/SMH) – 88% Win-Rate

Can we maybe use this strategy on individual stocks? Lets take a look at some of the stocks in my watchlist:

UnitedHealth (UNH) – 94% win-rate
Microsoft (MSFT) – 84% Win-Rate
Visa (V) – 82% win-rate
Apple (APPL) – 82% win-rate
Tesla (TSLA) – 81% win-rate
Adobe (ADB) – 75% win-rate

So there we have it. There is a wide range of markets where we know based on the previous 11 years this strategy has performed very, very well.

Like I said earlier, this strategy doesn’t trigger a lot but when it does if that market happens to be one of these high win rate markets, I highly recommend considering placing a trade.

CREATING THE STRATEGY

We start the strategy script, as always, with the definition of the strategy and the rules.

//@version=4
strategy(title="Basic Bollinger (Journeyman Demo)", overlay=true)

// Strategy Rules:
// 1. Set Bollinger Bands Moving Average Length to 20 
// 2. Enter trade when price crosses above the lower band
// 3. Exit trade when price touches the upper band

Next we want to define the variables that we expect the user to modify (if desired)

// User provided values
smaLength = 20 // Middle band period length (moving average)
stdLength = 20 // Range to apply bands to
ubOffset = 2.0 // Number of standard deviations above MA
lbOffset = 2.0 // Number of standard deviation below MA

Now we want to define a strategy time range. This allows us to increase or reduce the timeframe of the test to determine how well a strategy has performed over time.

We’ll add the start period, end period and a function to return whether the current bar is within that range.

// Chart Properties
testPeriodStart = timestamp(2010, 1, 1, 0, 0)
testPeriodStop = timestamp(2030, 12, 31, 0, 0)
testPeriod() =>
    time >= testPeriodStart and time <= testPeriodStop ? true : false

Next we want to get a reference to the simple moving average and standard deviation values for the current bar.

smaValue = sma(close, smaLength) // Middle band
stdDev = stdev(close, stdLength)

We need to create our own Bollinger Bands since there is no built-in bollinger function in the pinescript language so we will calculate the upper and lower band positions next.

upperBand = smaValue + stdDev * ubOffset // Top band
lowerBand = smaValue - stdDev * lbOffset // Bottom band

Now that we know the coordinates of all three data points (upper band, lower band, and middle band) for each bar on the chart we will go ahead and plot them.

// Plot bands to chart
plot(series=smaValue, title="SMA", color=color.blue)
plot(series=upperBand, title="UB", color=color.green, linewidth=2)
plot(series=lowerBand, title="LB", color=color.red, linewidth=2)

Next we need to define our entry and exit parameters. For the long condition (enter) we want to trigger a BUY signal whenever the closing price crosses up over the lower band.

longCondition = (crossover(close, lowerBand))

And to close our long position (exit) we will wait for the closing (or last) price to touch the upper band.

closeLongCondition = (close >= upperBand)

Now that we know our entery and exit we will instruct the strategy to act accordingly

if (longCondition and testPeriod())
    strategy.entry(id="CALL", long=true, qty=100)

strategy.close(id="CALL", when=closeLongCondition)
Robinhood App
Get Free Stocks!

FULL STRATEGY SOURCE CODE

//@version=4
strategy(title="Basic Bollinger (Baileysoft)", overlay=true)

// Strategy Rules:
// 1. Enter trade when price crosses above the lower band
// 2. Exit trade when price touches the upper band
// 

// Chart Properties
testStartYear = input(2010, "Backtest Start Year")
testStartMonth = input(01, "Backtest Start Month")
testStartDay = input(1, "Backtest Start Day")
testPeriodStart = timestamp(testStartYear, testStartMonth, testStartDay, 0, 0)

testStopYear = input(2030, "Backtest Stop Year")
testStopMonth = input(12, "Backtest Stop Month")
testStopDay = input(30, "Backtest Stop Day")
testPeriodStop = timestamp(testStopYear, testStopMonth, testStopDay, 0, 0)

// A switch to control background coloring of the test period
testPeriodBackground = input(title="Color Background?", type=input.bool, defval=true)
testPeriodBackgroundColor = testPeriodBackground and time >= testPeriodStart and time <= testPeriodStop ? #6c6f6c : na
bgcolor(testPeriodBackgroundColor, transp=97)

// User provided values
smaLength = input(title="SMA Length", type=input.integer, defval=20) // Middle band period length (moving average)
stdLength = input(title="StdDev Length", type=input.integer, defval=20) // Range to apply bands to
ubOffset = input(title="Upper Band Offset", type=input.float, defval=2.0, step=0.5) // Number of standard deviations above MA
lbOffset = input(title="Lower Band Offset", type=input.float, defval=2.0, step=0.5) // Number of standard deviation below MA

testPeriod() =>
    time >= testPeriodStart and time <= testPeriodStop ? true : false

smaValue = sma(close, smaLength) // Middle band
stdDev = stdev(close, stdLength)
upperBand = smaValue + stdDev * ubOffset // Top band
lowerBand = smaValue - stdDev * lbOffset // Bottom band

// Plot bands to chart
plot(series=smaValue, title="SMA", color=color.blue)
plot(series=upperBand, title="UB", color=color.green, linewidth=2)
plot(series=lowerBand, title="LB", color=color.red, linewidth=2)

longCondition = (crossover(close, lowerBand))
closeLongCondition = (close >= upperBand)

if (longCondition and testPeriod())
    strategy.entry(id="CALL", long=true, qty=100)

strategy.close(id="CALL", when=closeLongCondition)

DONATIONS

If you are finding value in my research or the YouTube content please kindly consider making a small donation to keep this project going.

   37y3Twv4QK4wJSDh2UQ4simNTNxUKq486s