빙구처럼 트레이딩: 코인 차트 "처음부터" 공부하기 #22- 간단한 보조지표 만들기 (ADX I)

in #sct7 years ago (edited)

보조지표의 끝판왕 이라고 "제가" 부르고 있는 ADX 를 살펴 보겠습니다. 끝판왕이라 부른 이유는 일단 복잡합니다. 제가 앞에서 언급한 거의 대부분의 함수들이 다 들어가있는 하죠. 오늘 강의는... 화이팅!


수식 분해

https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/dmi

일단 수식 부터가.. ㅋㅋㅋㅋㅋㅋ 피델리티에서 업로드한 자료니깐 믿을만 한 것 같구, 하나하나 차근차근 알아봅시다. 코딩은 뒷편에~

True Range

먼저 트루 레인지는 예전 포스팅에서 캔들의 크기라고 설명 드렸습니다. 하지만 세 가지 중 가장 큰 것에 해당하게 되죠. (앞 포스팅에서 고점 - 저점 이라 설명 드린 이유는 코인에서는 갭 상승이 없이 때문!)

  • 고점 - 저점
  • 고점 - 전종가
  • 저점 - 전종가

아래 두 케이스는 갭상승 또는 갭하락 할 경우에 해당하기에 코인은 고점 빼기 저점 만 생각해주시면 됩니다!

+ DI

만약 (현고점 - 전고점)이 (전저점 - 현저점) 보다 크다면, +DI 는 (현고점 - 전고점) 또는 (0) 중 큰 것

0이 되는 상황이 순간적으로 이해가 안되서 자암시 생각을 해보니,

대충 이런 상황 이군요. 고점은 낮아지고, 저점이 높아지면, 둘 다 음의 값을 가지게 된다. 그리고 만약 고점을 낮춘 수치보다, 저점을 올린 수치가 더 크면 +DI 가 0 이 되는군요. 의미상으로는 저점을 많이 올리면, 마이너스가 나오는 수치여도 0 으로 만들어준다? 저점의 상승 분을 중요하게 계산합니다.

고점을 높이고 저점을 높인 상황이라면 (현고점 - 전고점) 에 해당하는 값으로 저장이 될 거고

고점을 높이고 저점을 낮춘 상황이라면 고점을 더 높였으면 +DI 에 해당하고, 저점을 더 낮췄으면 해당하지 않는군.

요약: 이전 캔들의 고점과 저점을 비교하여, 두 가지 수치를 비교하여 어떤 값이 더 크고, 양의 값을 갖는지에 따라 수치를 정한다!

- DI

마이너스 DI 는 + 의 정 반대

만약, (전저가 - 현저가) 가 (현고가 - 전고가) 보다 크다면, -DI 는 (전저가 - 현저가) 또는 0 중 큰 값.

  • DI 랑 반대로 생각하면 되는 개념입니다. 만약 설명이 부가적으로 필요하시다면 댓글남겨주세요.

보니깐 DI 들은 풀어서쓰면 Directional Movement 즉, 단기 방향성을 나타내주네요. 현 캔들과 전 캔들의 정보만을 비교하여, 단기 추세를 수치적으로 나타냅니다. +DI 는 단기적으로 상승 추세가 얼마나 강한지, -DI 는 단기적으로 하락 추세가 얼마나 강한지.


만약 +DI 하고 -DI 가 음수 라면, 둘다 0 이다.

흠.. 이 파트는 좀 의문이 드는게 이미 위에서 0 보다 작으면 0으로 만들라고 써있어서, 당연히 둘 다 0이 되는게 아닌가요?


만약 +DI 하고 -DI 가 양수이고, +DI 가 -DI 보다 클 경우
+DI 는 (현고가 = 전고가) 그리고 -DI 는 0 이다!

반대로 +DI 가 -DI 보다 작을 경우
+DI 는 0 이고, -DI 는 (전저가 - 현저가) 라고 하네요.

둘 다 추세가 있는 상황에서는 한 쪽 추세 값을 0 으로 만들고, 한쪽 값을 그대로 유지함으로 강한 추세 쪽에 값이 튀어나오게 되겠네요.


시그널을 과하게 키워서 만들어봤습니다. DI 값들만 넣어봤습니다.

  • 고점과 저점을 높이거나, 고점을 높이는 수치가 저점을 낮추는 수치보다 높을때 파란색
  • 고점과 저점을 낮추거나, 저점을 낮추는 수치가 고점을 낮추는 수치보다 높으면 주황색
    값을 프린팅 하는군요.

위에서 의문점이 들었던 두 DI 값이 음의 값일때 둘다 0 이다 라는 점은, Inside Bar 에 해당하는 값들 일 때 위로도 아래로도 방향성이 없다고 판단하고 두 값 전부 0으로 보내는 군요. DI 가 0으로 가기전 어딘가에 조건절이 붙어야 할 것 같네요.

보니깐 DI 만으로도 잼있는걸 할 수 있겠어요! 잘 기억해두시구! 캔들 보시는 분들이 ADX 를 좋아하시는 이유가 있었어요! @rtytf 삼촌!


이제 두 DI 값들은 Wilder's Smoothing Technique 으로 스무딩을 하라고 합니다. 이게 뭐냥.... 그래서 찾으러 갔습다!

http://etfhq.com/blog/2010/08/19/wilders-smoothing/

와일더? 윌더? 라는 사람에 의해서 만들어졌고, 그가 만든 여러 지표에 사용되는 기본 베이스 변수 인듯 합니다. 가장 유명한 지표로는 RSI. 오호 RSI 만드신 분이였군요! EMA 랑 동일한 결과를 보여준다고 해요. 하지만 주기가 두배에 1개 만큼 (2n-1) 다르네요. 즉 ema(50)=ws-ma(99) => ema(n) - ws-ma (2n-1) . 밑에 데이터는 ema smoothing 을 ma 와 종가를 활용하여 찾을 수 있는 공식이 있네요. 요건 패쓰.

인트로는 여까지고. 찾는 방법은

이동평균값부터 구합니다. 고냥 Sum(Close,N)/N

해주시고,

WSMA(i) = (Sum1-WSMA1+Close(i)))/N

이라고 합니다.

여기서 WSMA1 은 첫 주기, 즉 50 주기였다면 첫 생성 캔들부터 50 개의 캔들에 대한 평균값.
WSMA(i) 는 현 주기의 스무딩 작업이 된 값이고 = 결과물
Close(i) = 현재 종가
N = 스무딩시킬 주기
Sum1 = 이전 세 개 종가의 합

실제 예시를 보면, 3주기를 만드는 방법을 만들어뒀네요. 일단 이동평균을 구하고, 3주기니깐 3번째 캔들이 만들어지면 되겠죠?

두 번째 항에는

일단 한 개 전까지 항들의 합. 빨간색 네모를 더한 값을 가져오고, 하나 앞의 WSMA 값을 가져와야 하지만, N+1 항에는 N 번째를 SMA 로 대체하니깐
(전 3개의 종가의 합 - 하나 전 SMA + 현재 종가)/주기

이렇게 되겠네요.

다음항은 요런식으로 계산 되는 것 같고. 이전 3개의 종가합, 이전 WSMA, 현재종가

다음 것도 똑같이 할려니깐... 엥? 5+4+3 은 12 아닌감..뭔가 잘못 알고 있는 건가... 오타낸 것 같기도하고...

시각적으로 보면, 좀 더 이어진 느낌이 납니다. 장기 이동평균선은 둔감한 느낌이라면 이친구는 음... 약간 노이즈를 캔슬 시키는 효과가 있는 것 같습니다. SMA 랑 WSMA 랑 비교해서 전략을 구성해도 괜찮아 보이는 군요.

뭐 이런식으로 해서 이전 평균 값을 빼버리고, 현재 종가를 넣어서 현재 가격에 좀 더 충실하도록 설계한 공식 같습니다.

중요한 파트가

Close - WSMA 라는 부분 같은데, 만약 현재 종가가 전캔들의 종가보다 편차 만큼이 이동평균의 편차에 가중이 되네요.

즉, 식을 살짝 재구성하면

WSMA = ((이전 주기만큼 값의 합) + (현재 종가 - 이전 WSMA ))/주기

이렇게 구성이 되는데 분수니깐 찢어주면

(이전 주기만큼 값의 합) / 주기 : 이동 평균선; 그냥 평균값 내는 것이고

(현재종가 - 이전 WSMA ) / 주기 : 현재 종가와 어제 WSMA 의 편차를 보여주는 것이니, 많이 오르면 많이 오른만큼 추가해주고, 어제 평균보다 종가가 더 내려가면 더 내려간 만큼 가중 해주는 듯 합니다. 그래서

급등한 부분을 자세히 관찰하면 WSMA 가 더 가파르게 오르는 현상이 보이네요. 급등을 할때 더 붙고 아닐때는 SMA 에 마이너스를 주니깐, 횡보할때 MA 값보다 느리고, 추세가 터질때 MA 보다 크게 움직이네요.

아 그리고 RSI 에 이용되는 이동평균이여서, rma 라고 불립니다! 그리고... 킬링 포인트는

rma 라는 함수가 트레이딩뷰가 지원합니다. 즉 위 계산을 코딩을 하지 않으셔도 됩니다. ㅋㅋㅋㅋㅋㅋㅋ


쨋든 위 두 DI 들과 True Range를 smoothing 을 이용하여 평균을 만들어줍니다. closing (종가) 에 해당하는 부분에 Di 값들과 TR 값을 넣으면 되겠죠?

변수들의 세련된 평균을 만들어준다! 라고 생각하시면 될 것 같습니다.


이제 DI 의 평균을 TR 의 평균으로 나눠 줍니다. 그리고 100으로 곱해줍니다.

(rma(+DI,주기)) / (rma(TR,주기)) * 100
(rma(-DI,주기)) / (rma(TR,주기)) * 100

흐음 DI, 얼마나 방향성 있게 움직였는지, 를 TR, 평균적으로 얼마나 큰 값을 가지는지, 로 나눠줌으로써 현재 캔들의 크기 (고점 - 저점) 대비 얼마나 큰 방향성으로 움직이냐? 를 알아낼 수 있고 그걸 100으로 곱해줘서 퍼센트로 나타내는 군요.

즉 +DI 가 10인데 (10원 만큼의 상승 힘) , TR 이 1000 이면, 변동성이 1000 인데, 10 만큼의 상승 분이니깐 상승 힘이 작다 라고 해석할 수 있고,

+DI 가 10인데 , TR 이 15, 이면 변동성이 15 인데, 10 만큼 상승 분이니깐 거의 급등한 상태라고 할 수 있겠네요.


이제 DX (Directional Movement Index) 를 계산할 차례 입니다. DX 는 두 DI 들을 뺀값의 절대값과, 두 DI 들의 합으로 나누는 것 입니다. 그 값에 100을 곱해줘서 퍼센트로 나타내줍니다.

절대값( [+DI] -[-DI] ) / ( [+DI] + [-DI] ) * 100

그럼 하락 세를 뜻하는 -DI 와 상승 세를 뜻하는 +DI 의 차를 두 DI 들의 합, 상승/하락 세의 합으로 나눠 줌으로써 상승세 또는 하락세가 뚜렷한지 안한지를 알 수 있습니다.

  • 만약 보합세, 박스권이라면 +DI 와 -DI 가 비슷하게 됨으로, DX 이 0 으로 가겠죠.
  • 만약 위아래로 크게 왔다 갔다 하는 확장 파동의 형태라면, 보합세와 동일하게 +DI 도 커지고, -DI 도 커지니깐 차는 0, DX 는 0
  • 만약 방향성이 있으면 +DI, -DI 둘 중 하나가 양극화 되어 있는 값을 가지기 때문에 한 가지가 커지며, DX 값이 커지게 되죠.

이제 대망의 ADX 를 구할 차례 입니다. 단어만 봐도 느낌이 오시겠죠! Average Directional Index. DX 의 평균이 되겠습니다. ...아니 그냥 평균을 쓰지 왜... 이걸 또 스무딩을 해.........

The following values are smoothed by multiplying the previous ADX value by the specified period – 1, adding the current DX value, and dividing this total by the period specified.

일단 첫 주기의 ADX 는 평균값 그냥 단순하게 가져오고 그 이후부터는 한 개 전의 ADX 값하고 1주기 낮춘 값을 곱하고, 현재 DX 값을 더하고, 주기로 나눠 주랍니다. (사실 뇌정지가 와서 이 파트가... 뭔지...) 과거 ADX 값을 희석 시키고, 현재 DX 값에 가중치를 두려는 작업 같은데, DX 를 rma 에 넣어도 상관 없을 것 같습니다. 크게 지장있는 부분은 아니라서.


마지막 ADXR 은 현재 ADX 와 n-주기 전의 ADX 값을 평균내는 것 이라고 합니다. 이건 식으로 좀 봤으면 좋겠는데,

이렇게 현재 ADX 값과 n 개 전에 ADX 를 뽑아서, 평균 내라는건가? 이건 처음 보는 컨셉이라 패쓰 하겠습니당..


후우... 독자도 저자도 핵고통 받으며 ADX 라는 보조지표를 분해해봤습니다..... 사실 분해까지 안해도 되는데, 굳이 분해하는 이유는 어느 순간 보조지표를 만들다 보면 특정 보조지표의 특정 변수/함수 만 사용하고 싶은 순간이 옵니다.

만약 ADX 의 상승 힘을 나타내는 DI 만 사용하고 싶다던지, smoothing 을 사용하지 않고 단순 평균을 사용한다던지, DI 들의 편차를 MACD 형태로 나타낸다든지, ADX 에 표준편차를 씌워 (볼린저 벤트) 편차를 활용한 기법을 제작해본다던지.


오늘은 코딩까지만 합시다. 코딩은 사실 제가 한 것은 아니고 트레이딩뷰에 공개되어 있는 코드로 가지고 왔습니다. 조금 복잡하기도 하고 있는데 또 만들긴 좀 그래서.. 하하하 ...

https://www.tradingview.com/script/5op9FJ57-Directional-Movement-DMI/

요기서 가져온 코드 입니다! 전 해석만 살짝 하고 넘어가겠습니다.

adxlen = input(17, title="ADX Smoothing")
dilen = input(17, title="DI Length")

먼저 변수를 지정해 줍니다. 저는 보통 그냥

adxlen = 17
dilen = 17

이런식으로 고정을 시켜버리는데, input 함수를 사용할 경우 트레이딩뷰 안에서 코드 수정없이 주기를 조절하실 수 있습니다!

이런식으로 말이죠!

dirmov(len) =>
up = change(high)
down = -change(low)
truerange = rma(tr, len)
plus = fixnan(100 * rma(up > down and up > 0 ? up : 0, len) / truerange)
minus = fixnan(100 * rma(down > up and down > 0 ? down : 0, len) / truerange)
[plus, minus]

흠.. 이번에는 함수를 만들어 버립니다. 일단 큰거부터 설명드리자면

dirmov(len) 이라는 함수에 len 만 넣으면, [plus, minus] 에 해당하는 값들이 나온다. 코딩 수업은 아니니깐 그냥 이런게 있구나~

up = change(high)
down = -change(low)

업/다운은 눈치 채셨겠지만, 고점간의 변화량과, 저점간의 변화량 입니다. 위에서 다시 살짝 수식을 가져오자면,

(현고점 - 전고점) , (전저점 - 현저점)

이 두 변수를 비교하는 것이기 때문에, down 에는 - 값이 붙습니다. (하나는 (현 - 전) 이고 하나는 (전 - 현) 이기 때문이죠. )

truerange = rma(tr, len)

트루 레인지는 어차피 tr 값 그대로 쓰는 경우가 없기 때문에 바로 스무딩 처리 (smoothing) 를 하여 값을 저장해줍니다. 여기서 tr 은 트레이딩뷰가 자체적으로 지원하는 변수로 (고점 - 저점) 에 대한 값을 불러옵니다!

tr = (high -low)

식으로 표현하면 이렇게 되겠죠?

plus = fixnan(100 * rma(up > down and up > 0 ? up : 0, len) / truerange)
minus = fixnan(100 * rma(down > up and down > 0 ? down : 0, len) / truerange)

이제 어려운 파튼데... 음... 이건 넘어가겠습니다. 위에서 말한 조건절들, +DI > - DI 이고 +DI > 0 이면 +DI 값이고, 아니면 0 이다. 이걸 RMA 에 넣고, truerange 라는 위에서 설정한 변수로 나눠 주는 것이니. 음... fixnan 은 주어진 주기동안 없는 값을 가장 가까운 값으로 바꾸라는 뜻인데. truerange 값이 0 일 경우 문제가 생기긴 하는데, 그럴 경우는 없으니, 음. 왜 넣었을까용?

그리고

[plus, minus]
위 plus , minus 값을 프린팅해라! 즉, 위 len 자리에 주기를 넣으면 +DI 하고 -DI값을 주는 함수를 만든 것 입니다.

adx(dilen, adxlen) =>
[plus, minus] = dirmov(dilen)
sum = plus + minus
adx = 100 * rma(abs(plus - minus) / (sum == 0 ? 1 : sum), adxlen)
[adx, plus, minus]

ADX 파트 일단 dirmov 함수를 불러와서 plus와 minus 변수를 가져오고, 그 값을 합합니다. 여기까지는 직관적이고 쉽고.

adx = 100 * rma( abs(plus - minus) / (sum == 0 ? 1 : sum), adxlen )

위에는 +DI 와 -DI 의 차를 절대값으로 만들고, 합으로 나눠줍니다. 만약 합이 0 일 경우 1이고, 아니면 합을 가져다 씁니다. 합이 0 인 경우가 빈캔들 이 오류로 생기면 가끔 생기는데 그거 잡으려고 한듯 합니다. 그리고 rma 안에 넣어서 adxlen 의 주기로 평균을 만들어버리고 100곱해서 퍼센트로 나눕니다.

DX = abs(plus - minus) / (sum == 0 ? 1 : sum)

음 아까 공식에서는 DX 에 100 곱하라 했는데, 상관 없겠죠 어차피 상수니깐?

[adx, plus, minus]

마지막으로 adx, +di, -di 값들을 나오게 만들면 끄읕!

[sig, up, down] = adx(dilen, adxlen)

변수 이름을 이렇게 지정 주시고, (adx(dilen,adxlen) = [adx, plus, minus ] 나오니깐, [sig, up, down] = [adx, plus, minus] 가 되는 것과 똑같습니다!)

sig = adx
up = plus
down = minus

보기 좋은 포멧으로 풀어쓰자면 이런식?

plot(sig, color=red, title="ADX")
plot(up, color=blue, title="+DI")
plot(down, color=orange, title="-DI")

이걸 이제 차트에 그려줍니다....!! 그럼 끄읕.


ADX 가 구성되는 개념을 배우셨으니, 다음 시간에는 ADX 를 활용하여 만들 수 있는 전략들을 살펴 보겠습니다. 이 포스팅을 @bystyx 스님께 헌정합니다! :)


질문, 댓글, 팔로우는 감사합니다!

새로운 아이디어, 종목 추천 등은 언제나 환영입니다!


Sort:  

헌정이라뇨.

다음 시간 포스팅이 기대됩니다.

전 거래량 기준, MACD, DMI, ADX DI, RSI 등으로 트레이딩 데스크로 셋업해서 활용하고 있는데, 보조지표를 어떤 조합으로 보고 해석하는지 그래서 매매 결정을 하는지도 궁금합니다.

오오!! 스님도 얼른 비법을 갈쳐주시죠~~~ ㅋㅋㅋㅋㅋ (흥.. 맨날 제 보따리만 푸는 느낌입니다!) ADX 를 예전에 볼때 그냥 선들만 보고 될지 안될지 결정했었는데, 포스팅하는 겸, 변수가 어떻게 생기고, 함수는 어떻게 활용하는지 까지 보고 나니 굉장한 활용도가 보이네요. 왜 제이삼촌하고 스님이 좋아하시는 보조지표인지 알 것 같아요. 특히 DI 부분에서 고점들과 저점들을 비교해서 TR 로 나눠 매수세/매도세를 퍼센트로 상대적 수치화하는 부분이 굉장히 인상 깊었습니다. 흐흐.. 뉴욕가서 스님 트레이딩 비기를 훔쳐보고 말겁니다!!!! ㅋㅋㅋㅋㅋㅋ :) 덕분에 레벨업한 기분입니다!

오오!! 스님도 얼른 비법을 갈쳐주시죠~~~ ㅋㅋㅋㅋㅋ (흥.. 맨날 제 보따리만 푸는 느낌입니다!) ADX 를 예전에 볼때 그냥 선들만 보고 될지 안될지 결정했었는데, 포스팅하는 겸, 변수가 어떻게 생기고, 함수는 어떻게 활용하는지 까지 보고 나니 굉장한 활용도가 보이네요. 왜 제이삼촌하고 스님이 좋아하시는 보조지표인지 알 것 같아요. 특히 DI 부분에서 고점들과 저점들을 비교해서 TR 로 나눠 매수세/매도세를 퍼센트로 상대적 수치화하는 부분이 굉장히 인상 깊었습니다. 흐흐.. 뉴욕가서 스님 트레이딩 비기를 훔쳐보고 말겁니다!!!! ㅋㅋㅋㅋㅋㅋ :) 덕분에 레벨업한 기분입니다!