Chiến lược này giao dịch sự đột phá giá của Bollinger Bands. Nó nhằm mục đích nắm bắt các cơ hội xu hướng từ sự đột phá kênh.
Chiến lược logic:
Tính toán Bollinger Bands với đường trung bình động n giai đoạn như đường trung và các dải biến động trên và dưới.
Nhập ngắn khi giá phá vỡ dưới dải dưới. Nhập dài khi phá vỡ trên dải trên.
Đặt dừng bên ngoài dải đối diện để kiểm soát rủi ro.
Điều chỉnh chiều rộng băng thông dựa trên tối đa drawdown để tối ưu hóa tham số.
Thêm bộ lọc âm lượng để tránh các sự đột phá giả.
Ưu điểm:
Việc phá vỡ các dải băng hiệu quả xác định các biến đổi xu hướng.
Bollinger tối ưu hóa tham số là đơn giản và thực tế.
Bộ lọc âm lượng cải thiện chất lượng bằng cách tránh nhầm lẫn.
Rủi ro:
Các ban nhạc bị tụt lại có thể bỏ lỡ thời điểm tốt nhất.
Sự đảo ngược sau khi đột quỵ là phổ biến, đòi hỏi phải dừng lại hợp lý.
Tìm kiếm các giao dịch tần số thấp trong tối ưu hóa có thể bỏ lỡ cơ hội.
Tóm lại, đây là một chiến lược thoát kênh điển hình giao dịch Bollinger Breaks. Các quy tắc tương đối đơn giản có lợi cho tối ưu hóa nhưng các vấn đề về vị trí trì hoãn và dừng lại vẫn ảnh hưởng đến lợi nhuận ổn định dài hạn.
/*backtest start: 2023-08-12 00:00:00 end: 2023-09-11 00:00:00 period: 2h basePeriod: 15m exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}] */ //@version=2 // strategy("ChannelBreakOutStrategyV2.1", commission_type = "percent", commission_value = 0.1, calc_on_order_fills = true, overlay=true) length = input(title="Length", minval=1, maxval=1000, defval=40) maxR = input(title = "R", minval = 1.0, maxval = 10, defval = 3, step = 0.1) adoptR = input(title = "Auto Adjust R", defval = false) stepR = input(title = "Step in R", minval = 0.01, maxval = 0.1, step = 0.01, defval = 0.02) baseYear = input(title = "Base Year", minval = 2000, maxval = 2016, defval = 2000) volumeTh = input(title = "Volume Threadhold", minval = 100.0, maxval = 200, defval = 120, step = 5) hasLong = input(title = "Include Long", defval = true) hasShort = input(title = "Include Short", defval = true) usePositionSizing = input(title = "Enable Position Sizing", defval = true) getTrailStop(val, current) => s = val > 1.6 ? 0.8 : val >= 1.4 ? 0.85 : val >= 1.3 ? 0.9 : 0.93 s * current upBound = highest(high, length) downBound = lowest(low, length) hasVol = (volume / sma(volume, length) * 100 >= volumeTh) ? 1 : 0 hasPos = strategy.position_size != 0 ? 1 : 0 trailstop = atr(length) * 3 ptvalue = syminfo.pointvalue equity = strategy.openprofit > 0 ? strategy.equity - strategy.openprofit : strategy.equity curR = adoptR == false ? maxR : n == 0 ? maxR : hasPos == 1 ? curR[1] : (rising(equity,1) > 0? curR[1] + stepR : falling(equity, 1) > 0 ? curR[1] <= 2.0 ? 2.0 : curR[1] - stepR : curR[1]) contracts = usePositionSizing == false ? 20 : floor(equity / 100 * curR / (trailstop * ptvalue)) realbuystop = close - trailstop realsellstop = close + trailstop isPFst = (hasPos[1] == 0 and hasPos == 1) ? 1 : 0 isPOn = (hasPos[1] + hasPos == 2) ? 1 : 0 largestR = hasPos == 0 or isPFst == 1 ? -1 : nz(largestR[1]) < close ? close : largestR[1] pctRise = largestR / strategy.position_avg_price rbs = strategy.position_size <= 0 ? realbuystop : isPFst ? strategy.position_avg_price - trailstop : pctRise >= 1.3 ? getTrailStop(pctRise, largestR) : (isPOn and realbuystop > rbs[1] and close > close[1]) ? realbuystop : rbs[1] rss = strategy.position_size >= 0 ? realsellstop : isPFst ? strategy.position_avg_price + trailstop : (isPOn and realsellstop < rss[1] and close < close[1]) ? realsellstop : rss[1] isStart = na(rbs) or na(rss) ? 0 : 1 buyARun = close - open > 0 ? 0 : open - close sellARun = open - close > 0 ? 0 : close - open if (strategy.position_size > 0 and buyARun >= trailstop / 3 * 2 and pctRise < 1.3) strategy.close("buy") strategy.cancel("exit") if (strategy.position_size < 0 and sellARun >= trailstop / 3 * 2) strategy.close("sell") strategy.cancel("exit") strategy.cancel("buy") strategy.cancel("sell") conLong = hasLong == true and hasPos == 0 and year > baseYear and (isStart + hasVol) == 2 strategy.order("buy", strategy.long, qty = contracts, stop=upBound + syminfo.mintick * 5, comment="BUY", when = conLong) if (rbs > high) strategy.close("buy") strategy.exit("exit", "buy", stop = rbs, when = hasPos == 1 and isStart == 1) conShort = hasShort == true and hasPos == 0 and year > baseYear and (isStart + hasVol) == 2 strategy.order("sell", strategy.short, qty = contracts, stop=downBound - syminfo.mintick * 5, comment="SELL", when = conShort) if (rss < low) strategy.close("sell") strategy.exit("exit", "sell", stop = rss, when = hasPos == 1 and isStart == 1) plot(series = rbs, color=blue) plot(series = realbuystop, color=green) plot(series = rss, color=red) plot(series = realsellstop, color=yellow)