Stratégie de rupture des bandes de Bollinger

Auteur:ChaoZhang est là., Date: le 13 novembre 2023 à 11 h 26: 50
Les étiquettes:

img

Résumé

Cette stratégie utilise les bandes supérieures et inférieures dynamiques des bandes de Bollinger pour aller long lorsque le prix dépasse la bande supérieure et fermer la position lorsque le prix tombe en dessous de la bande inférieure.

La logique de la stratégie

La stratégie repose principalement sur l'indicateur Bollinger Bands pour identifier les ruptures.

  1. Ligne médiane: moyenne mobile de n périodes
  2. Bandes supérieures: ligne médiane + déviation type k * n périodes
  3. Bande inférieure: ligne médiane - déviation type k * n périodes

Lorsque le prix dépasse la fourchette supérieure, le marché est considéré comme suracheté et une position longue peut être ouverte.

La stratégie permet de personnaliser les paramètres des bandes de Bollinger: la moyenne mobile de la période n et le multiplicateur d'écart type k. Les valeurs par défaut sont de 20 périodes pour la moyenne mobile et de 2 pour le multiplicateur d'écart type.

La stratégie vérifie si le prix de clôture dépasse la bande supérieure après chaque journée de négociation. Si c'est le cas, un signal long est déclenché à l'ouverture du jour suivant. Une fois long, la stratégie surveille si le prix dépasse la bande inférieure en temps réel et ferme la position si c'est le cas.

La stratégie intègre également un filtre de moyenne mobile qui ne génère des signaux d'achat que lorsque le prix est au-dessus de la ligne de moyenne mobile.

Deux options de stop loss sont fournies: pourcentage fixe de stop loss ou suivi de la bande inférieure.

Les avantages de la stratégie

  • Utiliser les bandes de Bollinger pour juger des niveaux de surachat/survente
  • Filtre des moyennes mobiles pour éviter les transactions contre la tendance
  • Paramètres de Bollinger Bands personnalisables adaptés à différentes périodes
  • Choix entre deux méthodes d'arrêt des pertes
  • Le backtesting permet une optimisation des paramètres et une vérification hors échantillon

Risques liés à la stratégie

  • Les bandes de Bollinger ne permettent pas de déterminer complètement le taux de surachat/de survente
  • Le filtre à moyenne mobile peut manquer des sorties plus rapides
  • Le stop-loss fixe peut être trop conservateur, le stop-trailing peut être trop agressif
  • Les paramètres doivent être optimisés pour différents produits et délais
  • Incapacité de limiter la taille des pertes, besoin d'envisager la gestion de l'argent

Directions d'optimisation

  • Tester différentes combinaisons de paramètres de moyenne mobile
  • Essayez différents paramètres des bandes de Bollinger
  • Comparer le pourcentage fixe de stop loss par rapport à la bande inférieure en termes de rendement
  • Ajouter le module de gestion de l'argent à la perte limite par transaction
  • Incorporer d'autres indicateurs pour confirmer le signal des bandes de Bollinger

Conclusion

La stratégie identifie les conditions de surachat/survente à l'aide de bandes dynamiques de Bollinger Bands, se réfère aux filtres de moyenne mobile et utilise des arrêts pour protéger le capital. Par rapport aux ruptures de niveau fixe traditionnelles, elle s'adapte mieux aux fluctuations du marché. Avec une optimisation des paramètres et des contrôles de risque supplémentaires, la stratégie peut atteindre une plus grande stabilité et des rendements.


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

//@version=5

// Revision:        1
// Author:          @millerrh
// Strategy:  
//      Entry: Buy when price breaks out of upper Bollinger Band
//      Exit: Trail a stop with the lower Bollinger Band 
// Conditions/Variables:
//    1. Can add a filter to only take setups that are above a user-defined moving average on current timeframe and/or longer timeframe (helps avoid trading counter trend) 
//    2. Manually configure which dates to back test
//    3. User-Configurable Bollinger Band Settings
//    4. Optionally use a tighter initial stop level.  Once Bollinger Band catches up, trail with lower Bollinger Band to give more breathing room.

// strategy('Donchian Breakout', overlay=true, initial_capital=100000, currency='USD', default_qty_type=strategy.percent_of_equity, calc_on_every_tick = true,
//   default_qty_value=100, commission_type=strategy.commission.percent, commission_value=0.1)

strategy('Bollinger Breakout', overlay=true, initial_capital=100000, currency='USD', default_qty_type=strategy.percent_of_equity,
  default_qty_value=100, commission_type=strategy.commission.percent, commission_value=0.0, calc_on_order_fills=true)

// === BACKTEST RANGE ===
Start = input(defval = timestamp("01 Jan 2019 06:00 +0000"), title = "Backtest Start Date", group = "backtest window")
Finish = input(defval = timestamp("01 Jan 2100 00:00 +0000"), title = "Backtest End Date", group = "backtest window")

// == INPUTS ==
// Bollinger Band Inputs
bbLength = input.int(20, minval=1, group = "Bollinger Band Settings", title="Bollinger Band Length",
  tooltip = "Bollinger Band moving average length.")
bbMultTop = input.float(2.0, minval=0.001, maxval=50, title="Standard Deviation (Top)")
bbMultBot = input.float(2.0, minval=0.001, maxval=50, title="Standard Deviation (Bottom)")

useTightStop = input.bool(title='Use Fixed Percentage for Initial Stop?', defval=false, group = "order entry",
  tooltip = "'Keep your losers small and let winners run' is the saying.  This will allow you to use a tight initial stop
  until the lower Bollinger Band catches up.")
percStop = input.int(title="Stop", defval=8, group = "order entry", inline = "perc")
trigInput = input.string(title='Execute Trades On...', defval='Wick', options=['Wick', 'Close'], group = "order entry",
  tooltip = "Useful for comparing standing stop orders at the Bollinger Band boundary (executing on the wick) vs. waiting for candle closes prior to taking action")

// Moving Average Filtering Inputs
useMaFilter = input.bool(title='Use Moving Average for Filtering (Current Timeframe)?', defval=false, group = "moving average filtering",
  tooltip = "Signals will be ignored when price is under this moving average.  The intent is to keep you out of bear periods and only buying when 
             price is showing strength.")
maType = input.string(defval='SMA', options=['EMA', 'SMA'], title='MA Type For Filtering', group = "moving average filtering")
maLength = input.int(defval=50, title="Moving Average:    Length", minval=1, group = "moving average filtering", inline = "1ma")
ma1Color = input.color(color.new(color.green, 50), title = " Color", group = "moving average filtering", inline = "1ma")
useMaFilter2 = input.bool(title='Use Moving Average for Filtering (High Timeframe)?', defval=false, group = "moving average filtering")
tfSet = input.timeframe(defval="D", title="Timeframe of Moving Average", group = "moving average filtering",
  tooltip = "Allows you to set a different time frame for a moving average filter.  Trades will be ignored when price is under this moving average.
  The idea is to keep your eye on the larger moves in the market and stay on the right side of the longer term trends and help you be pickier about 
  the stocks you trade.")
ma2Type = input.string(defval='SMA', options=['EMA', 'SMA'], title='MA Type For Filtering', group = "moving average filtering")
ma2Length = input.int(defval=50, title="Moving Average:    Length", minval=1, group = "moving average filtering", inline = "2ma")
ma2Color = input.color(color.new(color.white, 50), title = " Color", group = "moving average filtering", inline = "2ma")


// === THE BOLLINGER BAND ===
// Logic
bbBasis = ta.sma(close, bbLength)
bbUpper = bbBasis + bbMultTop * ta.stdev(close, bbLength)
bbLower = bbBasis - bbMultBot * ta.stdev(close, bbLength)

// Plotting
plot(bbBasis, "Basis", color=color.new(color.white, 50))
p1 = plot(bbUpper, color=color.new(color.blue, 50), linewidth=1, title='Upper Bollinger Band')
p2 = plot(bbLower, color=color.new(color.blue, 50), linewidth=1, title='Lower Bollinger Band')
fill(p1, p2, title = "Background", color=color.rgb(33, 150, 243, 95))

// == FILTERING LOGIC ==
// Declare function to be able to swap out EMA/SMA
ma(maType, src, length) =>
    maType == 'EMA' ? ta.ema(src, length) : ta.sma(src, length)  //Ternary Operator (if maType equals EMA, then do ema calc, else do sma calc)
maFilter = ma(maType, close, maLength)
maFilter2 = request.security(syminfo.tickerid, tfSet, ma(ma2Type, close, ma2Length))

// Plotting
plot(useMaFilter ? maFilter : na, title='Trend Filter MA - CTF', color=ma1Color, linewidth=2, style=plot.style_line)
plot(useMaFilter2 ? maFilter2 : na, title='Trend Filter MA - HTF', color=ma2Color, linewidth=2, style=plot.style_line)


// == ENTRY AND EXIT CRITERIA ==
// Trigger stop based on candle close or High/Low (i.e. Wick)
trigResistance = trigInput == 'Close' ? close : trigInput == 'Wick' ? high : na
trigSupport = trigInput == 'Close' ? close : trigInput == 'Wick' ? low : na
buySignal = trigResistance >= bbUpper 

buyConditions = (useMaFilter ? bbUpper > maFilter : true) and
  (useMaFilter2 ? bbUpper > maFilter2 : true) 
  
// == STOP AND PRICE LEVELS ==
// Configure initial stop level
inPosition = strategy.position_size > 0
stopLevel = strategy.position_avg_price - (strategy.position_avg_price * percStop/100)
posStop = stopLevel > bbLower ? stopLevel : bbLower


// Check if using stop vs. not
stop = useTightStop ? posStop : bbLower
plot(inPosition ? stop : na, style=plot.style_linebr, color=color.new(color.red, 40), linewidth = 1, title = "Stop Levels", trackprice=false)

sellSignal = trigSupport <= stop

// == STRATEGY ENTRIES & EXITS ==
// This string of code enters and exits at the candle close
if trigInput == 'Close'
    strategy.entry('Long', strategy.long, when=buyConditions and buySignal)
    strategy.close('Long', when=sellSignal)

// This string of code enters and exits at the wick (i.e. with pre-set stops)
if trigInput == 'Wick'
    strategy.entry('Long', strategy.long, stop=bbUpper, when=buyConditions)
    strategy.exit('Exit Long', from_entry='Long', stop=stop)
strategy.cancel('Long',when= not(buyConditions)) // Resets stop level once buyConditions aren't true anymore



Plus de