트렌드 각도 이동 평균 교차 전략


생성 날짜: 2024-01-25 14:35:13 마지막으로 수정됨: 2024-01-25 14:35:13
복사: 2 클릭수: 1182
avatar of ChaoZhang ChaoZhang
1
집중하다
1617
수행원

트렌드 각도 이동 평균 교차 전략

개요

이 전략은 평균선의 기울기각을 계산하여 트렌드 방향을 판단하고, 가격변동률 지표와 결합하여, 장단 양방향 거래를 한다. 그것의 본질은 평균선의 기울기각을 이용하여 가격 경향을 결정하고, 가격변동률 지표가 교차한 상황을 조정하는 트렌드 추적 전략이다.

전략 원칙

이 전략은 주로 다음과 같은 지표들을 기반으로 판단됩니다.

  1. 평균선 각: 쥬리크 평균선과 지수 이동 평균의 기울기 각을 계산하여 가격 트렌드 방향을 판단한다. 0보다 큰 각은 상승 트렌드이며, 0보다 작은 각은 하락 트렌드이다.

  2. 가격 변화율: 최근 12개의 K 선의 종결 가격 변화율을 계산하고, 변동성을 통해 무효 신호를 필터링한다.

평균선 각이 위로 (((0보다 크다) 고 가격변동률이 조건을 충족하면 더 많은 것을 하고, 평균선 각이 아래로 (((0) 미만일 때 가격변동률이 조건을 충족하면 공백을 한다.

구체적으로, 전략은 먼저 쥬리크 평균선과 EMA의 기울기 각도를 계산한다. 그리고 가격의 변화율 지표를 계산해, 필터링 정리 기간을 사용한다. 평균선 각도가 트렌드를 지시하고, 가격 변화율이 조건에 부합하면 거래 신호를 발생시킨다.

우위 분석

이 전략은 다음과 같은 장점을 가지고 있습니다.

  1. 평균선 기울기를 이용한 추세를 판단하는 것은 매우 신뢰할 수 있으며, 승률이 높다.

  2. 가격변동률 지표는 효율적으로 변동성을 필터링하여 무효 거래를 방지한다.

  3. Jurik은 평균선에서 돌파구에 신속하게 반응하고, EMA는 안정적인 추세 판단을 제공하며, 둘은 상호 보완한다.

  4. 장단한 쌍방향 거래 방식을 채택하여, 동향상태에서 더 많은 돈을 잡을 수 있다.

위험 분석

이 전략에는 몇 가지 위험도 있습니다.

  1. 가격의 급격한 변동이 있을 때, 평균선이 잘못된 신호를 생성할 확률이 높습니다. 최적화 매개 변수를 사용하여 이 위험을 줄일 수 있습니다.

  2. 평선 신호는 재배치 시 자주 전환되어 불필요한 거래가 발생할 수 있습니다. 부가적인 필터링 조건을 추가하여 유효하지 않은 거래를 줄일 수 있습니다.

  3. 갑작스러운 사건으로 인해 가격이 급격하게 상승할 때, 스톱 로즈는 타격될 수 있으며, 스톱 로즈는 적절히 완화될 수 있다.

최적화 방향

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

  1. 평균선 변수를 최적화하고, 최적의 변수 조합을 찾고, 전략의 안정성을 높인다.

  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)