Bollinger Bands Breakout xu hướng ngắn hạn sau chiến lược

Tác giả:ChaoZhang, Ngày: 2023-11-23 17:01:12
Tags:

img

Tổng quan

Chiến lược Bollinger Bands Breakout là một chiến lược theo xu hướng ngắn hạn được tối ưu hóa cho giao dịch tiền điện tử. Nó sử dụng chỉ số Bollinger Bands được thiết lập tốt như là bộ tạo tín hiệu cốt lõi và có khả năng nắm giữ cả các vị trí dài và ngắn. Với các cơ chế quản lý rủi ro toàn diện, nó là một hệ thống giao dịch tự động mạnh mẽ phù hợp với thị trường xu hướng.

Chiến lược có khả năng cấu hình cao, bao gồm các tham số Bollinger Bands, các bộ lọc khác nhau, cài đặt lấy lợi nhuận / dừng lỗ và ngưỡng lỗ tối đa trong ngày.

Làm thế nào nó hoạt động

Chiến lược này tập trung vào chỉ số Bollinger Bands, tính toán một dải giữa, một dải trên và một dải dưới phục vụ như các thay thế cho giá trung bình và giới hạn biến động.

Ngoài ra, nhiều bộ lọc được thực hiện để tránh tín hiệu sai:

  1. Trình lọc xu hướng: dài trên trung bình động, ngắn dưới trung bình động

  2. Bộ lọc biến động: chỉ giao dịch khi biến động mở rộng

  3. Bộ lọc hướng: có thể cấu hình cho chỉ đường dài, chỉ đường ngắn hoặc cả hai hướng

  4. Tấm lọc tỷ lệ thay đổi: chuyển động giá đủ từ khóa trước được yêu cầu

  5. Date Filter: for backtesting timeframe specification Các thông số kỹ thuật khung thời gian

Các bước ra được xử lý thông qua các cơ chế lấy lợi nhuận, dừng lỗ và dừng lại để khóa lợi nhuận và hạn chế lỗ.

Ưu điểm

Những lợi thế chính của chiến lược này bao gồm:

  1. Chỉ số Bollinger Bands đáng tin cậy như tín hiệu cốt lõi

  2. Các bộ lọc tùy chỉnh ngăn chặn các giao dịch không mong muốn

  3. Thiết kế dừng lỗ / lấy lợi nhuận toàn diện

  4. Tiêu chuẩn bảo vệ lỗ trong ngày tối đa chống lại sự rút tiền cực lớn

  5. Thịnh vượng trong các thị trường xu hướng với tiềm năng lợi nhuận

Rủi ro

Mặc dù có những lợi thế, một số rủi ro vẫn còn:

  1. Whipsaws xung quanh Bollinger Bands có thể dẫn đến tổn thất

  2. Các bộ lọc quá cứng giảm giao dịch trên các thị trường giới hạn phạm vi

  3. Khoảng cách có thể dừng lại các vị trí trước

  4. Không thể tránh hoàn toàn những chuyển động cực đoan

Các biện pháp giảm thiểu bao gồm điều chỉnh bộ lọc, can thiệp bằng tay và dừng điều chỉnh.

Cơ hội gia tăng

Các tối ưu hóa có thể cho chiến lược này:

  1. Tìm kiếm các kết hợp tham số tối ưu

  2. giới thiệu máy học để tối ưu hóa thích nghi

  3. Nghiên cứu các phương pháp dừng lỗ tốt hơn, ví dụ như dừng biến động

  4. Bao gồm cảm xúc để hướng dẫn các hành động tùy ý

  5. Sử dụng các công cụ tương quan để điều chỉnh thống kê

Kết luận

Chiến lược Bollinger Bands Breakout là một hệ thống đã được thử nghiệm thời gian để giao dịch xu hướng ngắn hạn. Bằng cách kết hợp các ưu điểm của tín hiệu Bollinger Bands và các bộ lọc thận trọng, nó tạo ra các mục nhập chất lượng cho xu hướng trong khi tránh các tín hiệu sai. Các cơ chế quản lý rủi ro toàn diện cũng chứa các khoản rút hiệu quả. Với những cải tiến liên tục, chiến lược này có tiềm năng trở thành một hệ thống giao dịch tự động đáng sợ.


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


//@version=5
strategy("Bollinger Bands - Breakout Strategy",overlay=true
         )



// Define the length of the Bollinger Bands
bbLengthInput = input.int (15,title="Length", group="Bollinger Bands", inline="BB")
bbDevInput = input.float (2.0,title="StdDev", group="Bollinger Bands", inline="BB")

// Define the settings for the Trend Filter
trendFilterInput = input.bool(false, title="Above/Below", group = "Trend Filter", inline="Trend")
trendFilterPeriodInput = input(223,title="", group = "Trend Filter", inline="Trend")
trendFilterType = input.string (title="", defval="EMA",options=["EMA","SMA","RMA", "WMA"], group = "Trend Filter", inline="Trend")

volatilityFilterInput = input.bool(true,title="StdDev", group = "Volatility Filter", inline="Vol")
volatilityFilterStDevLength = input(15,title="",group = "Volatility Filter", inline="Vol")
volatilityStDevMaLength = input(15,title=">MA",group = "Volatility Filter", inline="Vol")

// ROC Filter

// f_security function by LucF for PineCoders available here: https://www.tradingview.com/script/cyPWY96u-How-to-avoid-repainting-when-using-security-PineCoders-FAQ/
f_security(_sym, _res, _src, _rep) => request.security(_sym, _res, _src[not _rep and barstate.isrealtime ? 1 : 0])[_rep or barstate.isrealtime ? 0 : 1]
high_daily = f_security(syminfo.tickerid, "D", high, false)

roc_enable = input.bool(false, "", group="ROC Filter from CloseD", inline="roc")
roc_threshold = input.float(1, "Treshold", step=0.5, group="ROC Filter from CloseD", inline="roc")

closed = f_security(syminfo.tickerid,"1D",close, false)
roc_filter= roc_enable ? (close-closed)/closed*100  > roc_threshold : true

// Trade Direction Filter

// tradeDirectionInput = input.string("Auto",options=["Auto", "Long&Short","Long Only", "Short Only"], title="Trade", group="Direction Filter", tooltip="Auto: if a PERP is detected (in the symbol description), trade long and short\n Otherwise as per user-input")

// tradeDirection = switch tradeDirectionInput
// 	"Auto" => str.contains(str.lower(syminfo.description), "perp") or str.contains(str.lower(syminfo.description), ".p") ? strategy.direction.all : strategy.direction.long
// 	"Long&Short" => strategy.direction.all
// 	"Long Only" => strategy.direction.long
//     "Short Only" => strategy.direction.short
// 	=> strategy.direction.all

// strategy.risk.allow_entry_in(tradeDirection)


// Calculate and plot the Bollinger Bands
[bbMiddle, bbUpper, bbLower] = ta.bb (close, bbLengthInput, bbDevInput)

plot(bbMiddle, "Basis", color=color.orange)
bbUpperPlot = plot(bbUpper, "Upper", color=color.blue)
bbLowerrPlot = plot(bbLower, "Lower", color=color.blue)
fill(bbUpperPlot, bbLowerrPlot, title = "Background", color=color.new(color.blue, 95))


// Calculate and view Trend Filter

float tradeConditionMa = switch trendFilterType
	"EMA" => ta.ema(close, trendFilterPeriodInput)
	"SMA" => ta.sma(close, trendFilterPeriodInput)
	"RMA" => ta.rma(close, trendFilterPeriodInput)
    "WMA" => ta.wma(close, trendFilterPeriodInput)
	// Default used when the three first cases do not match.
	=> ta.wma(close, trendFilterPeriodInput)


trendConditionLong  = trendFilterInput ? close > tradeConditionMa : true
trendConditionShort = trendFilterInput ? close < tradeConditionMa : true
plot(trendFilterInput ? tradeConditionMa : na, color=color.yellow)

// Calculate and view Volatility Filter

stdDevClose = ta.stdev(close,volatilityFilterStDevLength)
volatilityCondition = volatilityFilterInput ? stdDevClose > ta.sma(stdDevClose,volatilityStDevMaLength) : true

bbLowerCrossUnder =  ta.crossunder(close, bbLower)
bbUpperCrossOver =  ta.crossover(close, bbUpper)

bgcolor(volatilityCondition ? na : color.new(color.red, 95))


// Date Filter

start = input(timestamp("2017-01-01"), "Start", group="Date Filter")
finish = input(timestamp("2050-01-01"), "End", group="Date Filter")

date_filter = true

// Entry and Exit Conditions

entryLongCondition = bbUpperCrossOver and trendConditionLong and volatilityCondition and date_filter and roc_filter
entryShortCondition = bbLowerCrossUnder and trendConditionShort and volatilityCondition and date_filter and roc_filter

exitLongCondition = bbLowerCrossUnder
exitShortCondition = bbUpperCrossOver

// Orders

if entryLongCondition
    strategy.entry("EL", strategy.long)

if entryShortCondition
    strategy.entry("ES", strategy.short)

if exitLongCondition
    strategy.close("EL")

if exitShortCondition
    strategy.close("ES")



// Long SL/TP/TS

xl_ts_percent      = input.float(2,step=0.5, title= "TS", group="Exit Long", inline="LTS", tooltip="Trailing Treshold %")
xl_to_percent      = input.float(0.5, step=0.5, title= "TO", group="Exit Long", inline="LTS", tooltip="Trailing Offset %")

xl_ts_tick = xl_ts_percent * close/syminfo.mintick/100
xl_to_tick = xl_to_percent * close/syminfo.mintick/100

xl_sl_percent      = input.float (2, step=0.5, title="SL",group="Exit Long", inline="LSLTP") 
xl_tp_percent      = input.float(9, step=0.5, title="TP",group="Exit Long", inline="LSLTP")

xl_sl_price = strategy.position_avg_price * (1-xl_sl_percent/100)
xl_tp_price = strategy.position_avg_price * (1+xl_tp_percent/100)

strategy.exit("XL+SL/TP", "EL", stop=xl_sl_price, limit=xl_tp_price, trail_points=xl_ts_tick, trail_offset=xl_to_tick,comment_loss= "XL-SL", comment_profit = "XL-TP",comment_trailing = "XL-TS")

// Short SL/TP/TS
xs_ts_percent      = input.float(2,step=0.5, title= "TS",group="Exit Short", inline ="STS", tooltip="Trailing Treshold %")
xs_to_percent      = input.float(0.5, step=0.5, title= "TO",group="Exit Short", inline ="STS", tooltip="Trailing Offset %")

xs_ts_tick = xs_ts_percent * close/syminfo.mintick/100
xs_to_tick = xs_to_percent * close/syminfo.mintick/100

xs_sl_percent      = input.float (2, step=0.5, title="SL",group="Exit Short", inline="ESSLTP", tooltip="Stop Loss %") 
xs_tp_percent      = input.float(9, step=0.5, title="TP",group="Exit Short",  inline="ESSLTP", tooltip="Take Profit %")

xs_sl_price = strategy.position_avg_price * (1+xs_sl_percent/100)
xs_tp_price = strategy.position_avg_price * (1-xs_tp_percent/100)

strategy.exit("XS+SL/TP", "ES", stop=xs_sl_price, limit=xs_tp_price, trail_points=xs_ts_tick, trail_offset=xs_to_tick,comment_loss= "XS-SL", comment_profit = "XS-TP",comment_trailing = "XS-TS")


max_intraday_loss = input.int(10, title="Max Intraday Loss (Percent)", group="Risk Management")

//strategy.risk.max_intraday_loss(max_intraday_loss, strategy.percent_of_equity)

// Monthly Returns table, modified from QuantNomad. Please put calc_on_every_tick = true to plot it. 

monthly_table(int results_prec, bool results_dark) =>
    new_month = month(time) != month(time[1])
    new_year  = year(time)  != year(time[1])
    
    eq = strategy.equity
    
    bar_pnl = eq / eq[1] - 1
    
    cur_month_pnl = 0.0
    cur_year_pnl  = 0.0
    
    // Current Monthly P&L
    cur_month_pnl := new_month ? 0.0 : 
                     (1 + cur_month_pnl[1]) * (1 + bar_pnl) - 1 
    
    // Current Yearly P&L
    cur_year_pnl := new_year ? 0.0 : 
                     (1 + cur_year_pnl[1]) * (1 + bar_pnl) - 1  
    
    // Arrays to store Yearly and Monthly P&Ls
    var month_pnl  = array.new_float(0)
    var month_time = array.new_int(0)
    
    var year_pnl  = array.new_float(0)
    var year_time = array.new_int(0)
    
    last_computed = false
    
    if (not na(cur_month_pnl[1]) and (new_month or barstate.islast))
        if (last_computed[1])
            array.pop(month_pnl)
            array.pop(month_time)
            
        array.push(month_pnl , cur_month_pnl[1])
        array.push(month_time, time[1])
    
    if (not na(cur_year_pnl[1]) and (new_year or barstate.islast))
        if (last_computed[1])
            array.pop(year_pnl)
            array.pop(year_time)
            
        array.push(year_pnl , cur_year_pnl[1])
        array.push(year_time, time[1])
    
    last_computed := barstate.islast ? true : nz(last_computed[1])
    
    // Monthly P&L Table    
    var monthly_table = table(na)
    
    cell_hr_bg_color = results_dark ? #0F0F0F : #F5F5F5
    cell_hr_text_color = results_dark ? #D3D3D3 : #555555
    cell_border_color = results_dark ? #000000 : #FFFFFF

    // ell_hr_bg_color = results_dark ? #0F0F0F : #F5F5F5
    // cell_hr_text_color = results_dark ? #D3D3D3 : #555555
    // cell_border_color = results_dark ? #000000 : #FFFFFF
    if (barstate.islast)
        monthly_table := table.new(position.bottom_right, columns = 14, rows = array.size(year_pnl) + 1, bgcolor=cell_hr_bg_color,border_width=1,border_color=cell_border_color)
    
        table.cell(monthly_table, 0,  0, syminfo.tickerid + " " + timeframe.period,     text_color=cell_hr_text_color, bgcolor=cell_hr_bg_color)
        table.cell(monthly_table, 1,  0, "Jan",  text_color=cell_hr_text_color, bgcolor=cell_hr_bg_color)
        table.cell(monthly_table, 2,  0, "Feb",  text_color=cell_hr_text_color, bgcolor=cell_hr_bg_color)
        table.cell(monthly_table, 3,  0, "Mar",  text_color=cell_hr_text_color, bgcolor=cell_hr_bg_color)
        table.cell(monthly_table, 4,  0, "Apr",  text_color=cell_hr_text_color, bgcolor=cell_hr_bg_color)
        table.cell(monthly_table, 5,  0, "May",  text_color=cell_hr_text_color, bgcolor=cell_hr_bg_color)
        table.cell(monthly_table, 6,  0, "Jun",  text_color=cell_hr_text_color, bgcolor=cell_hr_bg_color)
        table.cell(monthly_table, 7,  0, "Jul",  text_color=cell_hr_text_color, bgcolor=cell_hr_bg_color)
        table.cell(monthly_table, 8,  0, "Aug",  text_color=cell_hr_text_color, bgcolor=cell_hr_bg_color)
        table.cell(monthly_table, 9,  0, "Sep",  text_color=cell_hr_text_color, bgcolor=cell_hr_bg_color)
        table.cell(monthly_table, 10, 0, "Oct",  text_color=cell_hr_text_color, bgcolor=cell_hr_bg_color)
        table.cell(monthly_table, 11, 0, "Nov",  text_color=cell_hr_text_color, bgcolor=cell_hr_bg_color)
        table.cell(monthly_table, 12, 0, "Dec",  text_color=cell_hr_text_color, bgcolor=cell_hr_bg_color)
        table.cell(monthly_table, 13, 0, "Year", text_color=cell_hr_text_color, bgcolor=cell_hr_bg_color)
    
        for yi = 0 to array.size(year_pnl) - 1
            table.cell(monthly_table, 0,  yi + 1, str.tostring(year(array.get(year_time, yi))), text_color=cell_hr_text_color, bgcolor=cell_hr_bg_color)
            
            y_color = array.get(year_pnl, yi) > 0 ? color.lime :  array.get(year_pnl, yi) < 0 ? color.red : color.gray
            table.cell(monthly_table, 13, yi + 1, str.tostring(math.round(array.get(year_pnl, yi) * 100, results_prec)), bgcolor = y_color)
            
        for mi = 0 to array.size(month_time) - 1
            m_row   = year(array.get(month_time, mi))  - year(array.get(year_time, 0)) + 1
            m_col   = month(array.get(month_time, mi)) 
            m_color = array.get(month_pnl, mi) > 0 ? color.lime : array.get(month_pnl, mi) < 0 ? color.red : color.gray
            
            table.cell(monthly_table, m_col, m_row, str.tostring(math.round(array.get(month_pnl, mi) * 100, results_prec)), bgcolor = m_color)

results_prec = input(2, title = "Precision", group="Results Table")
results_dark = input.bool(defval=true, title="Dark Mode", group="Results Table")
monthly_table(results_prec, results_dark)

Thêm nữa