Chiến lược Bollinger Band Breakout

Tác giả:ChaoZhang, Ngày: 2023-11-13 11:26:50
Tags:

img

Tổng quan

Chiến lược này sử dụng các dải Bollinger Bands động trên và dưới để đi dài khi giá phá vỡ trên dải trên và đóng vị trí khi giá giảm xuống dưới dải dưới. Không giống như các chiến lược phá vỡ truyền thống với mức cố định, các dải Bollinger Bands thay đổi năng động dựa trên biến động lịch sử, làm cho nó tốt hơn trong việc xác định các điều kiện mua quá mức và bán quá mức.

Chiến lược logic

Chiến lược này chủ yếu dựa trên chỉ số Bollinger Bands để xác định sự đột phá.

  1. Đường trung gian: trung bình động n-period
  2. Dải trên: Đường trung + lệch chuẩn k * n thời gian
  3. Phạm vi dưới: Đường trung - lệch chuẩn k * n thời gian

Khi giá tăng trên dải trên, thị trường được coi là đã mua quá mức, và một vị trí dài có thể được bắt đầu. Khi giá giảm xuống dưới dải dưới, thị trường bị bán quá mức và vị trí nên được đóng.

Chiến lược cho phép tùy chỉnh các thông số Bollinger Bands: thời gian trung bình động n và nhân lệ lệch chuẩn k. Các giá trị mặc định là 20 thời gian cho trung bình động và 2 cho nhân lệch chuẩn.

Chiến lược này kiểm tra xem giá đóng cửa có vượt quá dải trên sau mỗi ngày giao dịch hay không. Nếu vậy, tín hiệu dài sẽ được kích hoạt vào ngày mở cửa tiếp theo. Một khi dài, chiến lược sẽ theo dõi nếu giá phá vỡ dưới dải dưới trong thời gian thực và đóng vị trí nếu như vậy.

Chiến lược này cũng kết hợp bộ lọc trung bình động chỉ tạo ra tín hiệu mua khi giá trên đường trung bình động.

Hai lựa chọn dừng lỗ được cung cấp: dừng lỗ tỷ lệ phần trăm cố định hoặc theo dõi dải dưới.

Ưu điểm của Chiến lược

  • Sử dụng Bollinger Bands để đánh giá mức mua/bán quá mức
  • Bộ lọc trung bình động tránh giao dịch chống lại xu hướng
  • Các thông số Bollinger Bands có thể tùy chỉnh phù hợp với các khoảng thời gian khác nhau
  • Lựa chọn giữa hai phương pháp dừng lỗ
  • Kiểm tra ngược cho phép tối ưu hóa tham số và xác minh ngoài mẫu

Rủi ro của chiến lược

  • Bollinger Bands không thể xác định đầy đủ quá mua/ quá bán
  • Bộ lọc trung bình di chuyển có thể bỏ lỡ các đột phá nhanh hơn
  • Đặt lỗ dừng cố định có thể quá bảo thủ, dừng kéo theo có thể quá hung hăng
  • Các thông số cần tối ưu hóa cho các sản phẩm và khung thời gian khác nhau
  • Không thể giới hạn kích thước tổn thất, cần phải xem xét quản lý tiền

Hướng dẫn tối ưu hóa

  • Kiểm tra các kết hợp tham số trung bình động khác nhau
  • Hãy thử các thông số khác nhau của Bollinger Bands
  • So sánh tỷ lệ lỗ dừng cố định so với dải thấp hơn về lợi nhuận
  • Thêm mô-đun quản lý tiền vào giới hạn mỗi lỗ giao dịch
  • Bao gồm các chỉ số khác để xác nhận tín hiệu Bollinger Bands

Kết luận

Chiến lược này xác định các điều kiện mua quá mức / bán quá mức bằng cách sử dụng các dải động Bollinger Bands, đề cập đến các bộ lọc trung bình động và sử dụng các điểm dừng để bảo vệ vốn. So với các mức cố định truyền thống, nó thích nghi tốt hơn với biến động thị trường. Với tối ưu hóa tham số và kiểm soát rủi ro hơn nữa, chiến lược có thể đạt được sự ổn định và lợi nhuận cao hơn. Nhìn chung, bằng cách sử dụng bản chất năng động của các dải Bollinger, chiến lược nắm bắt điểm mạnh của các chiến lược đột phá và có giá trị giao dịch trực tiếp và tối ưu hóa dài hạn.


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



Thêm nữa