양방향 이동 평균 회전 거래 전략

저자:차오장, 날짜: 2024-01-15 12:15:14
태그:

img

전반적인 설명

양방향 이동 평균 반전 거래 전략은 가격 평균 반전 이론에 기반한 양적 거래 전략이다. 이 전략은 여러 이동 평균을 설정하여 가격이 이동 평균에서 크게 벗어나면 시장에 진입하고, 다시 돌아온 경우 시장에서 빠져 나가는 방식으로 가격 반전 기회를 포착합니다.

전략 논리

이 전략의 핵심 아이디어는 가격 평균 회귀 (Price mean reversal) 이며, 이는 가격이 평균 값 주위에서 변동하는 경향이 있으며 평균에서 너무 멀리 벗어날 때 회귀 할 가능성이 높다는 것을 암시합니다. 구체적으로, 이 전략은 세 가지 이동 평균 그룹을 설정합니다. 입시 이동 평균, 출구 이동 평균 및 스톱-손실 이동 평균. 가격이 입시 이동 평균에 도달하면 대응하는 긴 또는 짧은 포지션을 열고, 가격이 출구 이동 평균에 도달하면 포지션을 닫고, 가격이 다시 회귀하지 않고 추세를 계속하는 경우 중단 손실 이동 평균으로 손실을 제어합니다.

코드 논리 관점에서, 두 가지 진입 이동 평균 - 길고 짧은 - 각각 빠른 이동 평균과 느린 이동 평균으로 구성되어 있습니다. 그것들과 가격 사이의 오차는 포지션 크기를 결정합니다. 또한 출구 이동 평균은 포지션을 닫을 때를 신호하는 별도의 이동 평균입니다. 가격이이 선을 칠 때 기존 포지션은 평평화됩니다.

이점 분석

양방향 이동 평균 회전 전략의 주요 장점은 다음과 같습니다.

  1. 범위에 제한된 시장에 적합한 가격 반전을 포착합니다.
  2. 스톱 손실을 통해 위험을 제어
  3. 적응력을 위해 매우 사용자 정의 가능한 매개 변수
  4. 이해하기 쉽고, 매개 변수 최적화를 위해 편리합니다

이 전략은 상대적으로 작은 가격 변동이 있는 낮은 변동성 도구와 잘 작동합니다. 특히 범위 제한 주기에 들어갈 때 효과적으로 일시적인 가격 반전에서 기회를 잡을 수 있습니다. 한편으로, 위험 통제 조치는 상당히 포괄적입니다. 가격이 되돌리지 않더라도 합리적인 범위 내에서 손실을 제한합니다.

위험 분석

이 전략과 관련된 위험도 있습니다.

  1. 트렌드를 쫓는 위험성: 트렌드가 크게 변할 때 연속적으로 새로운 포지션은 청산으로 이어질 수 있습니다.
  2. 과도한 가격 변동 위험. 중지 손실은 변동성 증가에 의해 영향을받을 수 있습니다.
  3. 매개 변수 최적화 위험: 부적절한 매개 변수 설정은 상당한 저성능으로 이어질 수 있습니다.

위 위험 요소 를 줄일 수 있는 몇 가지 방법 은 다음 과 같다.

  1. 과잉 거래를 피하기 위해 새로운 항목을 제한
  2. 청산 위험을 제한하기 위해 포지션 크기를 줄이는 것
  3. 이동평균 기간과 출구선 곱셈과 같은 매개 변수 최적화

최적화 방향

또한 이 전략을 더 이상 최적화 할 수있는 충분한 공간이 있습니다.

  1. 트렌드 추적을 방지하기 위해 추가 입력 논리를 추가합니다.
  2. 변동성 대비 적응형 포지션 사이징을 포함
  3. 다른 종류의 이동 평균을 실험
  4. 자동화된 매개 변수 최적화를 위한 기계 학습
  5. 더 역동적 인 위험 관리를 위해 후속 중단을 포함합니다.

결론

쌍방향 이동 평균 반전 거래 전략은 이동 평균 수준에서 상당한 오차가 발생한 후 가격 반전에서 이익을 얻는 것을 목표로합니다. 적절한 위험 제어 조치가 있으면 매개 변수 조정으로 일관된 이익을 얻을 수 있습니다. 추세 추구하고 과도한 변동성 같은 위험이 여전히 존재하지만, 진입 논리를 개선하고 위치 크기를 줄임으로써 해결할 수 있습니다. 이해하기 쉬운이 전략은 양적 거래자로부터 추가 연구와 최적화를받을 가치가 있습니다.


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

더 많은