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


생성 날짜: 2024-01-15 12:15:14 마지막으로 수정됨: 2024-01-15 12:15:14
복사: 0 클릭수: 670
avatar of ChaoZhang ChaoZhang
1
집중하다
1617
수행원

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

개요

양방향 이동 평균 반전 거래 전략 (Bidirectional Moving Average Reversion Trading Strategy) 은 가격 평균 반전 원리를 이용한 양적 거래 전략이다. 이 전략은 이동 평균의 여러 그룹을 설정하여 가격 반전 기회를 포착하고, 가격의 평균에서 어느 정도 벗어난 후 현장에 들어가며, 가격이 평균으로 돌아오는 것을 기다리는 동안 평소 포지션 마저리드 (Placing arbitrage) 를 수행한다.

전략 원칙

이 전략은 주로 가격의 평균 회귀 이론에 기초한다. 그것은 가격이 항상 평균값의 변동을 중심으로 움직이며, 가격이 평균값에서 크게 벗어날 때 평균값으로 돌아가는 것이 더 가능하다고 믿는다. 구체적으로, 이 전략은 동시에 세 개의 평균선을 설정한다: 개시 평균선, 매매 평균선 및 제한 평균선. 가격이 개시 평균선에 도달하면, 상반된 매수 또는 매수 포지션이 열린다. 가격이 매매 평균선에 도달하면, 이전 포지션이 평행된다. 마지막으로, 가격이 계속 움직이지 않으면 손실을 제어 할 수 있습니다.

코드 논리적으로 볼 때, 개시 평균선은 상수선과 하위선으로 나뉘며, 각각 긴 선과 짧은 선으로 구성된다. 가격과의 오차 정도가 포지션 크기를 결정한다. 또한, 평소 평균선은 평소 포지션의 시간을 결정하는 데 사용되는 별도의 평균선이다. 가격이 이 평준으로 운행되면 포지션은 평정된다.

우위 분석

양방향 평평선 회귀 전략의 장점은 주로 다음과 같다.

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