Chiến lược này kết hợp Bollinger Bands và Chỉ số Sức mạnh Tương đối (RSI) để xác định các cơ hội khi Bollinger Bands đang nén và RSI đang tăng, với việc dừng lỗ để kiểm soát rủi ro.
Lý thuyết cốt lõi của chiến lược này là xác định Bollinger Bands squeeze và dự đoán sự đột phá giá khi RSI đang trong xu hướng tăng. Cụ thể, khi độ lệch tiêu chuẩn giữa băng BB 20 giai đoạn nhỏ hơn ATR * 2, chúng tôi xác định BB squeeze xảy ra; trong khi đó, nếu cả 10 và 14 giai đoạn RSI đang tăng, chúng tôi dự đoán giá có thể sớm vượt qua băng trên BB và đi dài.
Sau khi tham gia thị trường, chúng tôi sử dụng khoảng cách an toàn ATR + stop loss thích nghi để khóa lợi nhuận và quản lý rủi ro. Các vị trí sẽ được đóng khi giá đạt stop loss hoặc RSI trở nên quá mua (RSI 14 giai đoạn trên 70 và RSI 10 giai đoạn vượt quá 14).
Lợi thế lớn nhất của chiến lược này là xác định thời gian củng cố với BB squeeze và dự đoán hướng phá vỡ với RSI. Ngoài ra, sử dụng stop loss thích nghi dựa trên biến động thị trường thay vì stop loss cố định có thể khóa lợi nhuận tốt hơn trong khi kiểm soát rủi ro.
Rủi ro chính của chiến lược này là sai xác định BB squeeze và RSI uptrend, có thể dẫn đến breakout sai. Bên cạnh đó, stop loss thích nghi có thể không đóng các vị trí kịp thời trong thời gian biến động cao. Cải thiện các phương pháp stop loss như curve stop loss có thể giảm thiểu rủi ro này.
Chiến lược này có thể được tối ưu hóa thêm trong các khía cạnh sau:
Cải thiện các thông số BB để xác định ép chính xác hơn
Kiểm tra các giá trị khác nhau cho các giai đoạn RSI
Kiểm tra các kỹ thuật dừng lỗ khác như đường cong SL hoặc SL nhìn lại
Điều chỉnh các tham số dựa trên các đặc điểm của biểu tượng
Chiến lược này tận dụng tính bổ sung của BB và RSI để đạt được lợi nhuận điều chỉnh rủi ro tốt.
/*backtest start: 2023-12-01 00:00:00 end: 2023-12-31 23:59:59 period: 1h basePeriod: 15m exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}] */ // This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © DojiEmoji // //@version=4 strategy("[KL] BOLL + RSI Strategy",overlay=true,pyramiding=1) // Timeframe { backtest_timeframe_start = input(defval = timestamp("01 Apr 2016 13:30 +0000"), title = "Backtest Start Time", type = input.time) USE_ENDTIME = input(false,title="Define backtest end-time (If false, will test up to most recent candle)") backtest_timeframe_end = input(defval = timestamp("01 May 2021 19:30 +0000"), title = "Backtest End Time (if checked above)", type = input.time) within_timeframe = true // } // Bollinger bands (sdv=2, len=20) { BOLL_length = 20, BOLL_src = close, SMA20 = sma(BOLL_src, BOLL_length), BOLL_sDEV_x2 = 2 * stdev(BOLL_src, BOLL_length) BOLL_upper = SMA20 + BOLL_sDEV_x2, BOLL_lower = SMA20 - BOLL_sDEV_x2 plot(SMA20, "Basis", color=#872323, offset = 0) BOLL_p1 = plot(BOLL_upper, "BOLL Upper", color=color.navy, offset = 0, transp=50) BOLL_p2 = plot(BOLL_lower, "BOLL Lower", color=color.navy, offset = 0, transp=50) fill(BOLL_p1, BOLL_p2, title = "Background", color=#198787, transp=85) // } // Volatility Indicators { ATR_x2 = atr(BOLL_length) * 2 // multiplier aligns with BOLL avg_atr = sma(ATR_x2, input(1,title="No. of candles to lookback when determining ATR is decreasing")) plot(SMA20+ATR_x2, "SMA20 + ATR_x2", color=color.gray, offset = 0, transp=50) plot(SMA20-ATR_x2, "SMA20 - ATR_x2", color=color.gray, offset = 0, transp=50) plotchar(ATR_x2, "ATR_x2", "", location = location.bottom) //} // Trailing stop loss { TSL_source = low var entry_price = float(0), var stop_loss_price = float(0) trail_profit_line_color = color.green if strategy.position_size == 0 or not within_timeframe trail_profit_line_color := color.black stop_loss_price := TSL_source - ATR_x2 else if strategy.position_size > 0 stop_loss_price := max(stop_loss_price, TSL_source - ATR_x2) plot(stop_loss_price, color=trail_profit_line_color) if strategy.position_size > 0 and stop_loss_price > stop_loss_price[1] alert("Stop loss limit raised", alert.freq_once_per_bar) // } end of Trailing stop loss //Buy setup - Long positions { is_squeezing = ATR_x2 > BOLL_sDEV_x2 if is_squeezing and within_timeframe and not is_squeezing[1] alert("BOLL bands are squeezing", alert.freq_once_per_bar) else if not is_squeezing and within_timeframe and is_squeezing[1] alert("BOLL bands stopped squeezing", alert.freq_once_per_bar) ema_trend = ema(close, 20) concat(a, b) => concat = a if a != "" concat := concat + ", " concat := concat + b concat // } // Sell setup - Long position { rsi_10 = rsi(close, 10), rsi_14 = rsi(close, 14) overbought = rsi_14 > input(70,title="[Exit] RSI(14) value considered as overbought") and rsi_10 > rsi_14 // } end of Sell setup - Long position // MAIN: { if within_timeframe entry_msg = "" exit_msg = "" // ENTRY { conf_count = 0 volat_decr = avg_atr <= avg_atr[1] rsi_upslope = rsi_10 > rsi_10[1] and rsi_14 > rsi_14[1] if volat_decr and rsi_upslope and is_squeezing and strategy.position_size == 0 strategy.entry("Long",strategy.long, comment=entry_msg) entry_price := close stop_loss_price := TSL_source - ATR_x2 // } // EXIT { if strategy.position_size > 0 bExit = false if close <= entry_price and TSL_source <= stop_loss_price exit_msg := concat(exit_msg, "stop loss [TSL]") bExit := true else if close > entry_price and TSL_source <= stop_loss_price exit_msg := concat(exit_msg, "take profit [TSL]") bExit := true else if overbought exit_msg := concat(exit_msg, "overbought") bExit := true strategy.close("Long", when=bExit, comment=exit_msg) // } // } // CLEAN UP: if strategy.position_size == 0 and not is_squeezing entry_price := 0 stop_loss_price := float(0)