Chiến lược giao dịch hồi quy trung bình động hai chiều


Ngày tạo: 2024-01-15 12:15:14 sửa đổi lần cuối: 2024-01-15 12:15:14
sao chép: 0 Số nhấp chuột: 670
1
tập trung vào
1617
Người theo dõi

Chiến lược giao dịch hồi quy trung bình động hai chiều

Tổng quan

Chiến lược giao dịch đảo ngược đường trung bình hai chiều (Bidirectional Moving Average Reversion Trading Strategy) là một chiến lược giao dịch định lượng được xây dựng dựa trên nguyên tắc đảo ngược đường trung bình giá. Chiến lược này sử dụng nhiều nhóm đường trung bình di chuyển để nắm bắt cơ hội đảo ngược giá, đi vào sân sau khi giá lệch khỏi đường trung bình một mức độ nhất định và tháo lỗ khi chờ đợi giá quay trở lại đường trung bình.

Nguyên tắc chiến lược

Chiến lược này chủ yếu dựa trên lý thuyết quay trở về giá trung bình. Nó cho rằng giá luôn xoay quanh một biến động giá trung bình, và khi giá lệch khỏi giá trung bình, nó có nhiều khả năng quay trở lại giá trung bình. Cụ thể, chiến lược này đồng thời thiết lập ba nhóm đường trung bình: đường trung bình mở, đường trung bình bán và đường trung bình giới hạn.

Từ logic mã, đường trung bình mở vị trí được chia thành đường giao dịch và đường giao dịch, bao gồm đường dài và đường ngắn. Mức độ lệch giữa chúng và giá quyết định kích thước vị trí. Ngoài ra, đường trung bình bình là đường trung bình riêng để quyết định thời gian của vị trí bình thường.

Phân tích lợi thế

Lợi thế của chiến lược hồi quy theo đường trung bình hai chiều là:

  1. Các nhà đầu tư cũng có thể sử dụng các công cụ này để thu thập các thông tin liên quan đến các hoạt động kinh doanh.
  2. Kiểm soát rủi ro thông qua lỗ hổng giới hạn
  3. Có thể tùy chỉnh các tham số, thích ứng mạnh mẽ
  4. Dễ hiểu, dễ tối ưu hóa tham số

Chiến lược này được áp dụng cho các giống có biến động thấp, phạm vi biến động giá thấp, đặc biệt là các giống vào giai đoạn thu hồi. Nó có thể nắm bắt hiệu quả cơ hội biến đổi giá tạm thời. Đồng thời, các biện pháp kiểm soát rủi ro của nó cũng khá hoàn hảo, thậm chí nếu giá không quay trở lại, nó có thể kiểm soát tổn thất trong một phạm vi nhất định.

Phân tích rủi ro

Tuy nhiên, chiến lược này cũng có một số rủi ro:

  1. Chiến lược này có khả năng mở nhiều vị trí liên tiếp và cuối cùng phá vỡ vị trí khi có một làn sóng giá mạnh.
  2. Rủi ro biến động giá quá lớn. Nếu biến động giá quá lớn, vị trí có thể đạt đến mức tổn thất giới hạn và bị buộc phải thanh toán.
  3. Rủi ro tối ưu hóa tham số. Cài đặt tham số của chiến lược có ảnh hưởng quan trọng đến khả năng sinh lợi của nó, nếu các tham số được đặt không đúng cách, sẽ làm giảm đáng kể khả năng thu lợi nhuận.

Đối với các rủi ro trên, có thể tối ưu hóa theo các khía cạnh sau:

  1. Giới hạn mở kho để tránh quá thường xuyên
  2. Giảm kích thước vị thế một cách thích hợp để ngăn chặn rủi ro bùng nổ
  3. Tối ưu hóa các thiết lập như chu kỳ đường trung bình, tham số đường cân bằng

Hướng tối ưu hóa

Chiến lược này cũng có nhiều khả năng tối ưu hóa, chủ yếu từ các góc độ sau:

  1. Tăng logic điều kiện mở vị trí để ngăn chặn sự sụt giảm theo xu hướng
  2. Thêm logic giảm vị trí để ngăn chặn rủi ro do biến động giá lớn
  3. Thử các loại chỉ số đường trung bình khác nhau để tìm một sự kết hợp tốt hơn
  4. Tự động tối ưu hóa tham số bằng cách sử dụng phương pháp học máy
  5. Thêm chiến lược dừng lỗ tự động để kiểm soát rủi ro tốt hơn

Tóm tắt

Chiến lược giao dịch quay trở lại đường trung bình hai chiều kiếm lợi nhuận bằng cách nắm bắt cơ hội quay trở lại sau khi giá lệch khỏi đường trung bình di chuyển. Nó kiểm soát rủi ro một cách hiệu quả và có thể thu được lợi nhuận tốt hơn thông qua tối ưu hóa tham số. Mặc dù chiến lược này cũng có một số rủi ro, nhưng có thể được kiểm soát bằng cách cải thiện logic mở vị trí, giảm quy mô vị trí.

Mã nguồn chiến lược
/*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()