
Chiến lược đảo ngược đường trung bình chuyển động kép (Dual Moving Average Reversion Strategy) là một chiến lược đảo ngược ngắn hạn điển hình. Chiến lược này sử dụng hai đường trung bình với các tham số khác nhau để phát tín hiệu giao dịch và thu lợi nhuận khi xu hướng đảo ngược.
Chiến lược này sử dụng hai đường trung bình để tạo tín hiệu giao dịch. Đường trung bình đầu tiên được sử dụng để xác định hướng xu hướng và đường trung bình thứ hai được sử dụng để phát tín hiệu giao dịch.
Khi maopening tăng, nó cho thấy hiện tại đang trong giai đoạn xu hướng tăng; khi maopening giảm, nó cho thấy hiện tại đang trong giai đoạn xu hướng giảm. Maclosing nhân với một hệ số lớn hơn 1, làm cho nó nhạy cảm hơn, có thể phát ra tín hiệu đảo ngược trước.
Cụ thể hơn, khi maopening tăng và maclosing dưới maopening, biểu thị xu hướng đảo ngược, khi đó chiến lược sẽ mở lỗ; khi maopening giảm và maclosing trên maopening, biểu thị xu hướng đảo ngược, khi đó chiến lược sẽ mở thêm.
Các tham số của chiến lược bao gồm loại đường trung bình, chiều dài, nguồn dữ liệu, v.v. Các tham số này có thể được điều chỉnh để có hiệu quả giao dịch tốt hơn. Ngoài ra, chiến lược cũng có một số tùy chọn được tích hợp, chẳng hạn như cách mở vị trí, cách dừng lỗ, v.v., có thể được thiết lập theo nhu cầu.
Những lợi thế của chiến lược đảo ngược đường hai chiều bao gồm:
Trở lại nhỏ, phù hợp với giao dịch đường ngắn. Sử dụng hai đường trung bình nhanh, có thể nhanh chóng nắm bắt sự đảo ngược của xu hướng ngắn hạn, Trở lại nhỏ hơn.
Đơn giản và dễ nắm bắt. Hình thức giao dịch được gọi là tín hiệu giao dịch, rất đơn giản và rõ ràng.
Có nhiều tham số có thể điều chỉnh, có thể tối ưu hóa. Các tham số và hệ số có chứa 2 đường trung bình, có thể tìm ra sự kết hợp tham số tốt nhất bằng cách tối ưu hóa.
Có thể lên lịch, phù hợp với giao dịch tự động. Lập trình giao dịch tự động rất phù hợp với việc thực hiện giao dịch tự động.
Có thể kiểm soát rủi ro, có cơ chế dừng lỗ. Có thể thiết lập dừng di động hoặc dừng số, có thể kiểm soát tổn thất đơn lẻ.
Tuy nhiên, chiến lược đảo ngược đường hai chiều cũng có một số rủi ro:
Giao lộ hai đường trung bình bị tụt hậu. Chính đường trung bình bị tụt hậu so với giá, và xu hướng có thể đã bị đảo ngược trong một thời gian khi giao lộ xảy ra.
Dễ bị mắc kẹt. Sự đảo ngược xu hướng không nhất thiết phải kéo dài và có thể sớm quay trở lại, gây ra tình trạng mắc kẹt.
Việc thu hồi vẫn còn tồn tại. Việc dừng lỗ kịp thời có thể làm giảm tổn thất đơn lẻ, nhưng việc dừng lỗ liên tục cũng có thể dẫn đến việc thu hồi lớn hơn.
Rủi ro tối ưu hóa dữ liệu. Các tham số tối ưu hóa quá mức, hoạt động tốt trong dữ liệu lịch sử nhưng không hiệu quả trên ổ đĩa thực.
Các giải pháp đối phó với rủi ro bao gồm:
Tối ưu hóa tham số, tìm thiết lập đường trung bình phản ứng nhanh.
Kết hợp với các chỉ số khác để tránh bị giam giữ, chẳng hạn như chỉ số giá trị, chỉ số biến động.
Điều chỉnh vị trí dừng để giảm khả năng dừng liên tục.
Thử nghiệm tối ưu hóa tham số đa nhóm, đánh giá sức mạnh tham số.
Chiến lược đảo ngược hai đường đều có thể được tối ưu hóa theo các khía cạnh sau:
Kiểm tra các loại đường trung bình khác nhau để tìm đường trung bình nhạy cảm hơn. Như Kama, ZLEMA, v.v.
Tối ưu hóa tham số đường trung bình để tìm ra sự kết hợp chiều dài tốt nhất. Các đường trung bình thường có hiệu quả tốt hơn với chu kỳ ngắn hơn.
Kiểm tra các nguồn dữ liệu khác nhau, chẳng hạn như giá đóng cửa, giá trung bình, giá điển hình.
Thêm bộ lọc xu hướng để tránh tín hiệu đảo ngược không phù hợp. Các kênh Donchian có thể được sử dụng.
Xác nhận kết hợp với các chỉ số khác, chẳng hạn như chỉ số giá cả MACD, OBV, v.v.
Tăng cơ chế quản lý rủi ro, chẳng hạn như dừng di chuyển, lỗ tối đa trên tài khoản.
Tối ưu hóa danh mục đầu tư, tìm kiếm tỷ lệ phân bổ tài sản tốt nhất.
Thêm thử nghiệm sức mạnh tham số, đánh giá nguy cơ tham số quá tối ưu.
Chiến lược đảo ngược hai đường bằng nhau là một chiến lược đường ngắn đơn giản và thực tế, phù hợp để nắm bắt sự đảo ngược ngắn hạn của thị trường. Chiến lược này có sự rút lui nhỏ, dễ thực hiện và rất phù hợp để giao dịch số lượng. Nhưng cũng có một số vấn đề, chẳng hạn như rủi ro bị trì trệ, bị mắc kẹt. Có thể cải thiện hiệu quả của chiến lược bằng cách tối ưu hóa tham số, tăng bộ lọc chỉ số và cải thiện kiểm soát rủi ro.
/*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()