트렌드 앵글 이동 평균 크로스오버 전략

저자:차오장, 날짜: 2024-01-25 14:35:13
태그:

img

전반적인 설명

전략 논리

이 전략은 주로 다음의 평가 지표에 기초합니다.

  1. 이동 평균 기울기 각: 가격 트렌드 방향을 결정하기 위해 주릭 이동 평균과 기하급수 이동 평균의 기울기 각을 계산합니다. 0보다 큰 각은 상승 추세를 나타냅니다. 0보다 작은 각은 하락 추세를 나타냅니다.

  2. 가격 변화율: 변동성 기준으로 신호를 필터하기 위해 지난 12 바에 대한 폐쇄 가격 변화율을 계산합니다.

이동평균 기울기가 0보다 높고 가격 변화율이 기준을 충족하면, 긴 경로로 이동합니다. 기울기가 0보다 낮고 가격 변화율이 기준을 충족하면, 짧은 경로로 이동합니다.

특히, 전략은 먼저 Jurik MA와 EMA의 기울기 각도를 계산합니다. 그 다음 가격 변화율 지표는 범위 제한 기간을 필터링하기 위해 계산됩니다. 이동 평균 기울기 신호 트렌드와 가격 변화율이 기준을 충족하면 거래 신호가 생성됩니다.

이점 분석

이 전략의 장점:

  1. 트렌드를 결정하기 위해 MA 기울기를 사용하는 것은 좋은 승률과 매우 신뢰할 수 있습니다.

  2. 가격 변동률 지표는 유효하지 않은 거래를 피하기 위해 폭 변동을 효과적으로 필터합니다.

  3. 유리크 MA는 급격한 대응을 하고 EMA는 안정적인 트렌드 판단을 하고, 둘 다 상호 보완적입니다.

  4. 트렌딩 시장에서 길고 짧게 가는 것은 더 큰 수익을 얻을 수 있습니다.

위험 분석

이 전략의 몇 가지 위험:

  1. 극단적인 가격 윙사에서 MA는 잘못된 신호를 생성할 수 있습니다. 이는 매개 변수 최적화로 감소할 수 있습니다.

  2. 신호가 빈번하게 변하여 불필요한 거래를 유발할 수 있습니다. 추가 필터를 추가 할 수 있습니다.

  3. 스톱 손실은 갑작스러운 가격 격차 사건에서 깨질 수 있습니다. 더 넓은 스톱 손실을 사용할 수 있습니다.

최적화 방향

이 전략은 다음과 같은 측면에서 최적화 될 수 있습니다.

  1. MA 매개 변수를 최적화하여 안정성을 향상시키는 최적의 매개 변수 조합을 찾습니다.

  2. 변동성, 볼륨 필터 등을 추가하여 유효하지 않은 거래를 추가로 줄이십시오.

  3. 더 똑똑한 스톱 로스 포지셔닝을 위해 다른 지표를 포함합니다.

  4. 안정적인 수익성을 위한 적응형 위치 크기 알고리즘 개발

결론


/*backtest
start: 2023-12-01 00:00:00
end: 2023-12-31 23:59:59
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

//@version=4
// Based on ma angles code by Duyck which also uses Everget Jurik MA calulation and angle calculation by KyJ
strategy("Trend Angle BF", overlay=false)

/////////////// Time Frame ///////////////
testStartYear = input(2017, "Backtest Start Year") 
testStartMonth = input(1, "Backtest Start Month")
testStartDay = input(1, "Backtest Start Day")
testPeriodStart = timestamp(testStartYear,testStartMonth,testStartDay, 0, 0)

testStopYear = input(2019, "Backtest Stop Year")
testStopMonth = input(12, "Backtest Stop Month")
testStopDay = input(31, "Backtest Stop Day")
testPeriodStop = timestamp(testStopYear,testStopMonth,testStopDay, 0, 0)

testPeriod() => true
    
src=input(ohlc4,title="source")

// definition of "Jurik Moving Average", by Everget
jma(_src,_length,_phase,_power) =>
    phaseRatio = _phase < -100 ? 0.5 : _phase > 100 ? 2.5 : _phase / 100 + 1.5
    beta = 0.45 * (_length - 1) / (0.45 * (_length - 1) + 2)
    alpha = pow(beta, _power)
    jma = 0.0
    e0 = 0.0
    e0 := (1 - alpha) * _src + alpha * nz(e0[1])
    e1 = 0.0
    e1 := (_src - e0) * (1 - beta) + beta * nz(e1[1])
    e2 = 0.0
    e2 := (e0 + phaseRatio * e1 - nz(jma[1])) * pow(1 - alpha, 2) + pow(alpha, 2) * nz(e2[1])
    jma := e2 + nz(jma[1])

//// //// Determine Angle by KyJ //// //// 
angle(_src) =>
    rad2degree=180/3.14159265359  //pi 
    ang=rad2degree*atan((_src[0] - _src[1])/atr(14)) 

jma_line=jma(src,10,50,1)
ma=ema(src,input(56))
jma_slope=angle(jma_line)
ma_slope=angle(ma)

///////////// Rate Of Change ///////////// 
source = close
roclength = input(12, minval=1)
pcntChange = input(2, minval=1)
roc = 100 * (source - source[roclength]) / source[roclength]
emaroc = ema(roc, roclength / 2)
isMoving() => emaroc > (pcntChange / 2) or emaroc < (0 - (pcntChange / 2))

/////////////// Strategy ///////////////
long = ma_slope>=0 and isMoving()
short = ma_slope<=0 and isMoving()

last_long = 0.0
last_short = 0.0
last_long := long ? time : nz(last_long[1])
last_short := short ? time : nz(last_short[1])

long_signal = crossover(last_long, last_short)
short_signal = crossover(last_short, last_long)

last_open_long_signal = 0.0
last_open_short_signal = 0.0
last_open_long_signal := long_signal ? open : nz(last_open_long_signal[1])
last_open_short_signal := short_signal ? open : nz(last_open_short_signal[1])

last_long_signal = 0.0
last_short_signal = 0.0
last_long_signal := long_signal ? time : nz(last_long_signal[1])
last_short_signal := short_signal ? time : nz(last_short_signal[1])

in_long_signal = last_long_signal > last_short_signal
in_short_signal = last_short_signal > last_long_signal

last_high = 0.0
last_low = 0.0
last_high := not in_long_signal ? na : in_long_signal and (na(last_high[1]) or high > nz(last_high[1])) ? high : nz(last_high[1])
last_low := not in_short_signal ? na : in_short_signal and (na(last_low[1]) or low < nz(last_low[1])) ? low : nz(last_low[1])
sl_inp = input(2.0, title='Stop Loss %') / 100
tp_inp = input(900.0, title='Take Profit %') / 100 
 
take_level_l = strategy.position_avg_price * (1 + tp_inp)
take_level_s = strategy.position_avg_price * (1 - tp_inp) 

since_longEntry = barssince(last_open_long_signal != last_open_long_signal[1]) 
since_shortEntry = barssince(last_open_short_signal != last_open_short_signal[1]) 

slLong = in_long_signal ? strategy.position_avg_price * (1 - sl_inp) : na
slShort = strategy.position_avg_price * (1 + sl_inp)
long_sl = in_long_signal ? slLong : na
short_sl = in_short_signal ? slShort : na

/////////////// Execution /////////////// 
if testPeriod()
    strategy.entry("Long",  strategy.long, when=long)
    strategy.entry("Short", strategy.short, when=short)
    strategy.exit("Long Ex", "Long", stop=long_sl, limit=take_level_l, when=since_longEntry > 0)
    strategy.exit("Short Ex", "Short", stop=short_sl, limit=take_level_s, when=since_shortEntry > 0)
    
///////////// Plotting /////////////
hline(0, title='Zero line', color=color.purple, linewidth=1)
plot(ma_slope,title="ma slope", linewidth=2,color=ma_slope>=0?color.lime:color.red)
bgcolor(isMoving() ? long ? color.green : short ? color.red : na : color.white, transp=80)
bgcolor(long_signal ? color.lime : short_signal ? color.red : na, transp=30) 


더 많은