Bollinger Band Short-term Reversion Quantitative Strategy Based on Moving Average

Author: ChaoZhang, Date: 2023-12-19 16:17:47



This strategy is a short-term reversal trading strategy based on the Bollinger Band indicator. It combines moving averages, standard deviations and Bollinger bands to look for opportunities for reversal trading when prices are abnormally dispersed.

Strategy Principle

  1. Calculate moving average and standard deviation. Use sma() function to calculate sma moving average and stdev() function to calculate standard deviation.

  2. Calculate upper and lower rail of Bollinger band according to moving average and standard deviation. The upper rail is price+standard deviation1 and the lower rail is price-standard deviation1.

  3. When the price breaks through the upper or lower rail, it indicates that the price is abnormal. At this time, we determine to do reverse trading.

  4. Specifically, if the price is lower than the lower rail, we go long; if the price is higher than the upper rail, we go short.

Advantage Analysis

  1. Use Bollinger band channel to judge abnormal prices, which provides basis for reverse trading.

  2. Combined with the moving average factor, some noisy trades can be effectively filtered out.

  3. The introduction of standard deviation factor makes the Bollinger band channel more dynamic to better judge abnormal prices.

  4. This strategy has relatively small drawdowns and certain stability.

Risk Analysis

  1. The Bollinger Band indicator cannot completely determine the abnormal situation of prices. There may be false breakouts.

  2. The trading frequency may be too high. It is recommended to adjust the parameters appropriately to control the trading frequency.

  3. The breakout signals of the upper and lower Bollinger bands may last for a long time. Appropriate adjustment of parameters is needed to obtain better reversal effects.

  4. Introduce stop loss appropriately to control risks.

Optimization Directions

  1. Optimize the moving average cycle and standard deviation parameters to obtain a more reasonable Bollinger band channel.

  2. Increase auxiliary factors such as EMA and MACD to filter some signals.

  3. Introduce stop loss and position control mechanisms.

  4. Optimize position size and position control measures.


This strategy judges abnormal prices through the Bollinger Band indicator and makes reversal trades with moving averages and standard deviation parameters. It has certain stability. We need to further reduce the maximum drawdown of the strategy and improve stability through means such as parameter optimization, introduction of auxiliary factors, stop loss management and position control.

start: 2022-12-12 00:00:00
end: 2023-12-18 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]

strategy("BCE Version of EMA, SMA Mean Reversion", overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=100)
// Inputs
st_yr_inp = input(defval=2017, title='Backtest Start Year')
st_mn_inp = input(defval=01, title='Backtest Start Month')
st_dy_inp = input(defval=01, title='Backtest Start Day')
en_yr_inp = input(defval=2025, title='Backtest End Year')
en_mn_inp = input(defval=01, title='Backtest End Month')
en_dy_inp = input(defval=01, title='Backtest End Day')
sma_lookback = input(defval=100, title="Lookback Period For SMA")
ema_lookback = input(defval=10, title="Lookback Period For EMA")
long_diff_perc = input(defval=6, title="Percentage Deviation From SMA to go Long")/100
short_diff_perc = input(defval=20, title="Percentage Deviation From SMA to go Short")/100
ema_filter_bars = input(defval=4, title="The number of bars the EMA must rise/fall")
lng_allwd = input(defval=true, title="Allow Longs?")
srt_allwd = input(defval=true, title="Allow Shorts?")
use_stop = input(defval=true, title="Use Stoploss?")
stop_perc = input(defval=30, title="Stop Loss Percentage")/100
// Dates
start = timestamp(st_yr_inp, st_mn_inp, st_dy_inp,00,00)
end = timestamp(en_yr_inp, en_mn_inp, en_dy_inp,00,00)
can_trade = time >= start and time <= end
// Indicators Setup
sma = sma(close, sma_lookback)
ema = ema(close, ema_lookback)
// Strategy Calcuations
close_stdev = stdev(close, sma_lookback)
sd1_upper = close + (close_stdev * 1)
sd1_lower = close - (close_stdev * 1)
close_diff = (close - sma) / sma
// Entries and Exits
longCondition = close > sma and open > sma
if (time >= start and time <= end)
    if (longCondition)
        strategy.entry("Long", strategy.long)
    if use_stop
        stop_price = close * (1 - stop_perc)
        strategy.order("Long Stoploss", false, stop=stop_price)
shortCondition = close < sma and open < sma
if (shortCondition)
//    strategy.entry("Short", strategy.short)
//    if use_stop
//        stop_price = close * (1 + stop_perc)
//        strategy.order("Short Stoploss", true, stop=stop_price)
//if (time >= start)    
    strategy.close("Long", when=close < sma and open < sma)
//strategy.cancel("Long Stoploss", when=sma < sma[1])
//    strategy.close("Short", when=close > sma and open > sma)
//strategy.cancel("Short Stoploss", when=close_diff<=0)
// Plotting
sma_col = sma > sma[1] ? green : red
ema_fill = close_diff <= -long_diff_perc ? lime : close_diff >= short_diff_perc ? maroon : aqua
p_sma = plot(sma, color=sma_col, linewidth=3)
p_ema = plot(ema, color=black, linewidth=2)
p_sd1 = plot(sd1_upper, color=black, linewidth=1, transp=85)
p_sd2 = plot(sd1_lower, color=black, linewidth=1, transp=85)
fill(p_sd1, p_sd2, title='STDEV Fill', color=silver, transp=80)
fill(p_sma, p_ema, title='EMA > Mean Percentage', color=ema_fill, transp=80)