Bollinger Band Breakout Strategi

Penulis:ChaoZhang, Tarikh: 2023-11-13 11:26:50
Tag:

img

Ringkasan

Strategi ini menggunakan band atas dan bawah Bollinger Bands yang dinamik untuk pergi lama apabila harga memecahkan band atas dan menutup kedudukan apabila harga jatuh di bawah band bawah. Tidak seperti strategi breakout tradisional dengan tahap tetap, band Bollinger Bands berubah secara dinamik berdasarkan turun naik sejarah, menjadikannya lebih baik dalam mengenal pasti keadaan overbought dan oversold.

Logika Strategi

Strategi ini bergantung terutamanya pada penunjuk Bollinger Bands untuk mengenal pasti pecah.

  1. Garis Tengah: purata bergerak n-periode
  2. Garis atas: Garis tengah + k * penyimpangan standard n-periode
  3. Garis bawah: Garis tengah - penyimpangan standard k * n-periode

Apabila harga naik di atas band atas, pasaran dianggap terlalu banyak dibeli, dan kedudukan panjang boleh dimulakan. Apabila harga jatuh di bawah band bawah, pasaran terlalu banyak dijual, dan kedudukan harus ditutup.

Strategi ini membolehkan penyesuaian parameter Bollinger Bands: tempoh purata bergerak n dan pengganda penyesuaian standard k. Nilai lalai adalah 20 tempoh untuk purata bergerak dan 2 untuk pengganda penyesuaian standard.

Strategi ini memeriksa jika harga penutupan melanggar band atas selepas setiap hari dagangan. Jika ia berlaku, isyarat panjang dicetuskan pada pembukaan hari berikutnya.

Strategi ini juga menggabungkan penapis purata bergerak yang hanya menghasilkan isyarat beli apabila harga berada di atas garis purata bergerak. purata bergerak boleh ditetapkan pada jangka masa semasa atau lebih tinggi untuk mengawal masa kemasukan dengan lebih baik.

Dua pilihan stop loss disediakan: peratusan stop loss tetap atau mengikuti jalur bawah. Yang terakhir memberikan lebih banyak ruang untuk keuntungan berjalan.

Kelebihan Strategi

  • Menggunakan Bollinger Bands untuk menilai tahap overbought / oversold
  • Penapis purata bergerak mengelakkan perdagangan terhadap trend
  • Parameter Bollinger Bands yang boleh disesuaikan sesuai dengan tempoh yang berbeza
  • Pilihan antara dua kaedah stop loss
  • Backtesting membolehkan pengoptimuman parameter dan pengesahan di luar sampel

Risiko Strategi

  • Bollinger Bands tidak dapat menentukan sepenuhnya overbought/oversold
  • Penapis purata bergerak mungkin terlepas pelarian yang lebih cepat
  • Stop loss tetap boleh terlalu konservatif, trailing stop boleh terlalu agresif
  • Parameter memerlukan pengoptimuman untuk produk dan jangka masa yang berbeza
  • Tidak dapat mengehadkan saiz kerugian, perlu mempertimbangkan pengurusan wang

Arahan pengoptimuman

  • Uji kombinasi parameter purata bergerak yang berbeza
  • Cuba parameter Bollinger Bands yang berbeza
  • Bandingkan peratusan stop loss tetap vs band bawah yang tertinggal dari segi pulangan
  • Tambah modul pengurusan wang kepada had kerugian setiap perdagangan
  • Memasukkan penunjuk lain untuk mengesahkan isyarat Bollinger Bands

Kesimpulan

Strategi ini mengenal pasti keadaan overbought / oversold menggunakan Bollinger Bands band dinamik, merujuk kepada penapis purata bergerak, dan menggunakan berhenti untuk melindungi modal. Berbanding dengan breakout peringkat tetap tradisional, ia menyesuaikan diri dengan lebih baik dengan turun naik pasaran. Dengan pengoptimuman parameter dan kawalan risiko yang lebih lanjut, strategi ini dapat mencapai kestabilan dan pulangan yang lebih tinggi. Secara keseluruhan, dengan memanfaatkan sifat dinamik Bollinger Bands, strategi ini menangkap kekuatan strategi breakout dan bernilai perdagangan langsung dan pengoptimuman jangka panjang.


/*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



Lebih lanjut