Chiến lược giao dịch đảo ngược trung bình di chuyển hai chiều

Tác giả:ChaoZhang, Ngày: 2024-01-15 12:15:14
Tags:

img

Tổng quan

Chiến lược giao dịch đảo ngược trung bình chuyển động hai chiều là một chiến lược giao dịch định lượng được xây dựng dựa trên lý thuyết đảo ngược giá trung bình. Chiến lược này nắm bắt các cơ hội đảo ngược giá bằng cách thiết lập nhiều trung bình chuyển động và bước vào thị trường khi giá lệch đáng kể so với trung bình chuyển động, và thoát ra khi nó quay trở lại.

Chiến lược logic

Ý tưởng cốt lõi của chiến lược này là sự đảo ngược giá trung bình, cho thấy giá có xu hướng biến động xung quanh một giá trị trung bình, và có cơ hội cao hơn để quay trở lại khi chúng lệch quá xa so với mức trung bình. Cụ thể, chiến lược này thiết lập ba nhóm trung bình động: trung bình động nhập cảnh, trung bình động xuất cảnh và trung bình động dừng lỗ. Nó sẽ mở các vị trí dài hoặc ngắn tương ứng khi giá chạm vào mức trung bình động nhập cảnh; đóng các vị trí khi giá chạm vào mức trung bình động xuất cảnh; và kiểm soát tổn thất với mức trung bình động dừng lỗ trong trường hợp giá tiếp tục xu hướng mà không quay trở lại.

Từ quan điểm logic mã, có hai đường trung bình động đầu vào - dài và ngắn - bao gồm đường trung bình động nhanh và chậm tương ứng. Sai lệch giữa chúng và giá xác định kích thước vị trí. Ngoài ra, đường trung bình động đầu ra là một đường trung bình động riêng biệt báo hiệu khi nào phải đóng các vị trí. Khi giá chạm vào đường này, các vị trí hiện có sẽ được làm phẳng.

Phân tích lợi thế

Những lợi thế chính của chiến lược đảo ngược trung bình động hai chiều bao gồm:

  1. Khám phá sự đảo ngược giá, phù hợp với các thị trường giới hạn phạm vi
  2. Kiểm soát rủi ro thông qua dừng lỗ
  3. Các thông số có thể tùy chỉnh cao cho khả năng thích nghi
  4. Dễ hiểu, thuận tiện cho tối ưu hóa tham số

Chiến lược này hoạt động tốt với các công cụ biến động thấp có dao động giá tương đối nhỏ, đặc biệt là khi bước vào chu kỳ giới hạn phạm vi. Nó có thể nắm bắt hiệu quả các cơ hội từ sự đảo ngược giá tạm thời. Trong khi đó, các biện pháp kiểm soát rủi ro khá toàn diện, giới hạn lỗ trong phạm vi hợp lý ngay cả khi giá không quay trở lại.

Phân tích rủi ro

Ngoài ra còn có một số rủi ro liên quan đến chiến lược này:

  1. Theo đuổi các xu hướng rủi ro. Các vị trí mới liên tiếp có thể dẫn đến thanh lý trong khi xu hướng mạnh.
  2. Rủi ro biến động giá quá mức.
  3. Rủi ro tối ưu hóa tham số: cài đặt tham số không phù hợp có thể dẫn đến hiệu suất kém đáng kể.

Một số cách để giảm thiểu các rủi ro trên bao gồm:

  1. Hạn chế nhập mới để tránh giao dịch quá mức
  2. Giảm kích thước vị thế để hạn chế rủi ro thanh lý
  3. Tối ưu hóa các thông số như thời gian trung bình động và nhân đường thoát

Hướng dẫn tối ưu hóa

Ngoài ra còn có nhiều chỗ để tối ưu hóa thêm chiến lược này:

  1. Thêm thêm logic nhập để ngăn chặn theo đuổi xu hướng
  2. Tích hợp kích cỡ vị trí thích nghi với biến động
  3. Thử nghiệm với các loại trung bình động khác nhau
  4. Học máy cho tối ưu hóa tham số tự động
  5. Tích hợp các điểm dừng kéo theo để quản lý rủi ro năng động hơn

Kết luận

Chiến lược giao dịch đảo ngược trung bình chuyển động hai chiều nhằm mục đích kiếm lợi từ sự đảo ngược giá sau khi có sự lệch đáng kể so với mức trung bình chuyển động của nó. Với các biện pháp kiểm soát rủi ro thích hợp, nó có thể đạt được lợi nhuận nhất quán thông qua điều chỉnh tham số. Trong khi các rủi ro như theo đuổi xu hướng và biến động quá mức vẫn tồn tại, chúng có thể được giải quyết thông qua cải thiện logic nhập cảnh, giảm kích thước vị trí và nhiều hơn nữa. Chiến lược dễ hiểu này xứng đáng được nghiên cứu và tối ưu hóa thêm từ các nhà giao dịch định lượng.


/*backtest
start: 2023-12-15 00:00:00
end: 2024-01-14 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 = 30, pyramiding = 1, commission_value = 0.1, 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 Long"
maopeningtyp_l = 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_l = input.source(ohlc4, title = "", inline=info_opening, group=info_opening)
maopeninglen_l = input.int(3, minval = 1, title = "", inline=info_opening, group=info_opening)
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")

info_opening_s = "MA Opening Short"
maopeningtyp_s = input.string("SMA", title="Type", options=["SMA", "EMA", "TEMA", "DEMA", "ZLEMA", "WMA", "Hma", "Thma", "Ehma", "H", "L", "DMA"], title = "", inline=info_opening_s, group=info_opening_s)
maopeningsrc_s = input.source(ohlc4, title = "", inline=info_opening_s, group=info_opening_s)
maopeninglen_s = input.int(3, minval = 1, title = "", inline=info_opening_s, group=info_opening_s)
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")


//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)

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_l = 0.0
maopening_s = 0.0
maclosing = 0.0
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_l := ma_func(maopeningtyp_l, maopeningsrc_l, maopeninglen_l)
maopening_s := ma_func(maopeningtyp_s, maopeningsrc_s, maopeninglen_s)

//MA Closing
maclosing := ma_func(maclosingtyp, maclosingsrc, maclosinglen) * maclosingmul

long1 = long1on == false ? 0 : long1shift == 0 ? 0 : long1lot == 0 ? 0 : maopening_l == 0 ? 0 : maopening_l * long1shift
short1 = short1on == false ? 0 : short1shift == 0 ? 0 : short1lot == 0 ? 0 : maopening_s == 0 ? 0 : maopening_s * short1shift
//Colors
long1col = long1 == 0 ? na : color.green
short1col = short1 == 0 ? na : color.red
//Lines
// plot(maopening_l, offset = OFFS, color = color.new(color.green, 50))
// plot(maopening_s, offset = OFFS, color = color.new(color.red, 50))
plot(maclosing, offset = OFFS, color = color.fuchsia)
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 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()

Thêm nữa