Chiến lược đảo ngược trung bình động kép là một chiến lược giao dịch đảo ngược trung bình ngắn hạn điển hình. Chiến lược tạo ra tín hiệu giao dịch bằng hai đường trung bình động với các thiết lập tham số khác nhau. Nó nhằm mục đích kiếm lợi nhuận khi sự đảo ngược xu hướng xảy ra.
Chiến lược này sử dụng hai đường trung bình động để tạo ra tín hiệu giao dịch. Mở MA đầu tiên được sử dụng để xác định hướng xu hướng. Mở MA thứ hai được sử dụng để tạo ra tín hiệu giao dịch.
Khi maopening tăng, nó chỉ ra thị trường hiện tại đang trong xu hướng tăng. Khi maopening giảm, nó chỉ ra thị trường hiện tại đang trong xu hướng giảm. maclosing được nhân với một hệ số lớn hơn 1 để làm cho nó nhạy cảm hơn để tạo ra các tín hiệu đảo ngược sớm.
Cụ thể, khi maopening tăng và maclosing vượt qua dưới maopening, nó cho thấy một sự đảo ngược xu hướng. Chiến lược sẽ mở vị trí ngắn. Khi maopening giảm và maclosing vượt qua trên maopening, nó cho thấy một sự đảo ngược xu hướng. Chiến lược sẽ mở vị trí dài.
Các thông số của chiến lược bao gồm loại MA, độ dài, nguồn dữ liệu vv. Hiệu suất giao dịch có thể được tối ưu hóa bằng cách điều chỉnh các thông số này.
Những lợi thế chính của Chiến lược đảo ngược hai MA là:
Lượng rút ngắn, phù hợp với giao dịch ngắn hạn.
Dễ dàng thực hiện và dễ hiểu.
Rất dễ cấu hình với nhiều thông số điều chỉnh. Các thông số của hai MAs và hệ số có thể được tối ưu hóa.
Dễ dàng tự động hóa với luồng logic rõ ràng.
Rủi ro có thể kiểm soát được với cơ chế dừng lỗ.
Ngoài ra còn có một số rủi ro của chiến lược:
Sự chậm trễ của các tín hiệu giao thoa MA. Các MAs chính nó tụt lại phía sau giá. Sự giao thoa có thể xảy ra sau khi xu hướng đã đảo ngược trong một thời gian.
Rủi ro của các giao dịch whipsaw. xu hướng đảo ngược có thể nhanh chóng đảo ngược lại, gây ra tổn thất liên tiếp.
Mặc dù dừng lỗ hạn chế lỗ duy nhất, nhưng dừng lỗ liên tục vẫn có thể dẫn đến giảm lớn.
Rủi ro quá phù hợp: Tối ưu hóa tham số quá mức có thể dẫn đến quá phù hợp và hiệu suất kém trong giao dịch trực tiếp.
Các giải pháp bao gồm:
Tối ưu hóa các thông số để tìm ra các MAs nhanh hơn.
Thêm các bộ lọc, như chỉ số khối lượng và biến động, để tránh giao dịch whipsaw.
Điều chỉnh vị trí dừng lỗ để giảm xác suất dừng lỗ liên tiếp.
Kiểm tra độ bền của các bộ tham số để đánh giá rủi ro quá cố.
Chiến lược có thể được tối ưu hóa thêm trong các khía cạnh sau:
Kiểm tra các loại MAs khác nhau để tìm những loại nhạy cảm hơn, như KAMA, ZLEMA v.v.
Tối ưu hóa độ dài MA để tìm sự kết hợp tối ưu. Thông thường thời gian ngắn hơn có hiệu suất tốt hơn.
Kiểm tra các nguồn dữ liệu khác nhau, chẳng hạn như giá gần, giá trung bình, giá điển hình v.v.
Thêm bộ lọc xu hướng để tránh các tín hiệu đảo ngược không phù hợp, như kênh Donchian.
Thêm các chỉ số khác để xác nhận, như MACD, OBV vv
Cải thiện các cơ chế quản lý rủi ro, chẳng hạn như di chuyển dừng lỗ, lỗ tài khoản tối đa vv
Tối ưu hóa danh mục đầu tư để tìm ra phân bổ tài sản tối ưu.
Kiểm tra độ bền của các thông số để đánh giá rủi ro quá phù hợp.
Phản hồi MA kép là một chiến lược giao dịch ngắn hạn đơn giản và thực tế. Nó phù hợp để nắm bắt các sự đảo ngược ngắn hạn với giao dịch định lượng. Tuy nhiên, có những rủi ro như trượt và giao dịch chích. Chiến lược có thể được cải thiện bằng cách tối ưu hóa các tham số, thêm bộ lọc, tăng cường kiểm soát rủi ro vv để phát triển một chiến lược ổn định và hiệu quả với hiệu suất giao dịch thực sự tốt.
/*backtest start: 2023-10-17 00:00:00 end: 2023-11-16 00:00:00 period: 1h basePeriod: 15m exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}] */ //@version=5 strategy(title = "hamster-bot MRS 2", overlay = true, default_qty_type = strategy.percent_of_equity, initial_capital = 100, default_qty_value = 100, pyramiding = 9, commission_value = 0.045, backtest_fill_limits_assumption = 1) info_options = "Options" on_close = input(false, title = "Entry on close", inline=info_options, group=info_options) OFFS = input.int(0, minval = 0, maxval = 1, title = "| Offset View", inline=info_options, group=info_options) trade_offset = input.int(0, minval = 0, maxval = 1, title = "Trade", inline=info_options, group=info_options) use_kalman_filter = input.bool(false, title="Use Kalman filter", group=info_options) //MA Opening info_opening = "MA Opening" maopeningtyp = input.string("SMA", title="Type", options=["SMA", "EMA", "TEMA", "DEMA", "ZLEMA", "WMA", "Hma", "Thma", "Ehma", "H", "L", "DMA"], title = "", inline=info_opening, group=info_opening) maopeningsrc = input.source(ohlc4, title = "", inline=info_opening, group=info_opening) maopeninglen = input.int(3, minval = 1, maxval = 200, title = "", inline=info_opening, group=info_opening) //MA Closing info_closing = "MA Closing" maclosingtyp = input.string("SMA", title="Type", options=["SMA", "EMA", "TEMA", "DEMA", "ZLEMA", "WMA", "Hma", "Thma", "Ehma", "H", "L", "DMA"], title = "", inline=info_closing, group=info_closing) maclosingsrc = input.source(ohlc4, title = "", inline=info_closing, group=info_closing) maclosinglen = input.int(3, minval = 1, maxval = 200, title = "", inline=info_closing, group=info_closing) maclosingmul = input.float(1, step = 0.005, title = "mul", inline=info_closing, group=info_closing) long1on = input(true, title = "", inline = "long1") long1shift = input.float(0.96, step = 0.005, title = "Long", inline = "long1") long1lot = input.int(10, minval = 0, maxval = 10000, step = 10, title = "Lot 1", inline = "long1") short1on = input(true, title = "", inline = "short1") short1shift = input.float(1.04, step = 0.005, title = "short", inline = "short1") short1lot = input.int(10, minval = 0, maxval = 10000, step = 10, title = "Lot 1", inline = "short1") startTime = input(timestamp("01 Jan 2010 00:00 +0000"), "Start date", inline = "period") finalTime = input(timestamp("31 Dec 2030 23:59 +0000"), "Final date", inline = "period") HMA(_src, _length) => ta.wma(2 * ta.wma(_src, _length / 2) - ta.wma(_src, _length), math.round(math.sqrt(_length))) EHMA(_src, _length) => ta.ema(2 * ta.ema(_src, _length / 2) - ta.ema(_src, _length), math.round(math.sqrt(_length))) THMA(_src, _length) => ta.wma(ta.wma(_src,_length / 3) * 3 - ta.wma(_src, _length / 2) - ta.wma(_src, _length), _length) tema(sec, length)=> tema1= ta.ema(sec, length) tema2= ta.ema(tema1, length) tema3= ta.ema(tema2, length) tema_r = 3*tema1-3*tema2+tema3 donchian(len) => math.avg(ta.lowest(len), ta.highest(len)) ATR_func(_src, _len)=> atrLow = low - ta.atr(_len) trailAtrLow = atrLow trailAtrLow := na(trailAtrLow[1]) ? trailAtrLow : atrLow >= trailAtrLow[1] ? atrLow : trailAtrLow[1] supportHit = _src <= trailAtrLow trailAtrLow := supportHit ? atrLow : trailAtrLow trailAtrLow f_dema(src, len)=> EMA1 = ta.ema(src, len) EMA2 = ta.ema(EMA1, len) DEMA = (2*EMA1)-EMA2 f_zlema(src, period) => lag = math.round((period - 1) / 2) ema_data = src + (src - src[lag]) zl= ta.ema(ema_data, period) f_kalman_filter(src) => float value1= na float value2 = na value1 := 0.2 * (src - src[1]) + 0.8 * nz(value1[1]) value2 := 0.1 * (ta.tr) + 0.8 * nz(value2[1]) lambda = math.abs(value1 / value2) alpha = (-math.pow(lambda, 2) + math.sqrt(math.pow(lambda, 4) + 16 * math.pow(lambda, 2)))/8 value3 = float(na) value3 := alpha * src + (1 - alpha) * nz(value3[1]) //SWITCH ma_func(modeSwitch, src, len, use_k_f=true) => modeSwitch == "SMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(ta.sma(src, len)) : ta.sma(src, len) : modeSwitch == "RMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(ta.rma(src, len)) : ta.rma(src, len) : modeSwitch == "EMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(ta.ema(src, len)) : ta.ema(src, len) : modeSwitch == "TEMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(tema(src, len)) : tema(src, len): modeSwitch == "DEMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(f_dema(src, len)) : f_dema(src, len): modeSwitch == "ZLEMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(f_zlema(src, len)) : f_zlema(src, len): modeSwitch == "WMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(ta.wma(src, len)) : ta.wma(src, len): modeSwitch == "VWMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(ta.vwma(src, len)) : ta.vwma(src, len): modeSwitch == "Hma" ? use_kalman_filter and use_k_f ? f_kalman_filter(HMA(src, len)) : HMA(src, len): modeSwitch == "Ehma" ? use_kalman_filter and use_k_f ? f_kalman_filter(EHMA(src, len)) : EHMA(src, len): modeSwitch == "Thma" ? use_kalman_filter and use_k_f ? f_kalman_filter(THMA(src, len/2)) : THMA(src, len/2): modeSwitch == "ATR" ? use_kalman_filter and use_k_f ? f_kalman_filter(ATR_func(src, len)): ATR_func(src, len) : modeSwitch == "L" ? use_kalman_filter and use_k_f ? f_kalman_filter(ta.lowest(len)): ta.lowest(len) : modeSwitch == "H" ? use_kalman_filter and use_k_f ? f_kalman_filter(ta.highest(len)): ta.highest(len) : modeSwitch == "DMA" ? donchian(len) : na //Var sum = 0.0 maopening = 0.0 maclosing = 0.0 os = maopeningsrc cs = maclosingsrc pos = strategy.position_size p = 0.0 p := pos == 0 ? (strategy.equity / 100) / close : p[1] truetime = true loss = 0.0 maxloss = 0.0 equity = 0.0 //MA Opening maopening := ma_func(maopeningtyp, maopeningsrc, maopeninglen) //MA Closing maclosing := ma_func(maclosingtyp, maclosingsrc, maclosinglen) * maclosingmul long1 = long1on == false ? 0 : long1shift == 0 ? 0 : long1lot == 0 ? 0 : maopening == 0 ? 0 : maopening * long1shift short1 = short1on == false ? 0 : short1shift == 0 ? 0 : short1lot == 0 ? 0 : maopening == 0 ? 0 : maopening * short1shift //Colors maopeningcol = maopening == 0 ? na : color.blue maclosingcol = maclosing == 0 ? na : color.fuchsia long1col = long1 == 0 ? na : color.green short1col = short1 == 0 ? na : color.red //Lines plot(maopening, offset = OFFS, color = maopeningcol) plot(maclosing, offset = OFFS, color = maclosingcol) long1line = long1 == 0 ? close : long1 short1line = short1 == 0 ? close : short1 plot(long1line, offset = OFFS, color = long1col) plot(short1line, offset = OFFS, color = short1col) //Lots lotlong1 = p * long1lot lotshort1 = p * short1lot //Entry if maopening > 0 and maclosing > 0 and truetime //Long sum := 0 strategy.entry("L", strategy.long, lotlong1, limit = on_close ? na : long1, when = long1 > 0 and pos <= sum and (on_close ? close <= long1[trade_offset] : true)) sum := lotlong1 //Short sum := 0 pos := -1 * pos strategy.entry("S", strategy.short, lotshort1, limit = on_close ? na : short1, when = short1 > 0 and pos <= sum and (on_close ? close >= short1[trade_offset] : true)) sum := lotshort1 strategy.exit("Exit", na, limit = maclosing) if time > finalTime strategy.close_all()