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

일단 수식 부터가.. ㅋㅋㅋㅋㅋㅋ 피델리티에서 업로드한 자료니깐 믿을만 한 것 같구, 하나하나 차근차근 알아봅시다. 코딩은 뒷편에~
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 으로 스무딩을 하라고 합니다. 이게 뭐냥.... 그래서 찾으러 갔습다!

와일더? 윌더? 라는 사람에 의해서 만들어졌고, 그가 만든 여러 지표에 사용되는 기본 베이스 변수 인듯 합니다. 가장 유명한 지표로는 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 스님께 헌정합니다! :)
질문, 댓글, 팔로우는 감사합니다!
새로운 아이디어, 종목 추천 등은 언제나 환영입니다!
헌정이라뇨.
다음 시간 포스팅이 기대됩니다.
전 거래량 기준, MACD, DMI, ADX DI, RSI 등으로 트레이딩 데스크로 셋업해서 활용하고 있는데, 보조지표를 어떤 조합으로 보고 해석하는지 그래서 매매 결정을 하는지도 궁금합니다.
오오!! 스님도 얼른 비법을 갈쳐주시죠~~~ ㅋㅋㅋㅋㅋ (흥.. 맨날 제 보따리만 푸는 느낌입니다!) ADX 를 예전에 볼때 그냥 선들만 보고 될지 안될지 결정했었는데, 포스팅하는 겸, 변수가 어떻게 생기고, 함수는 어떻게 활용하는지 까지 보고 나니 굉장한 활용도가 보이네요. 왜 제이삼촌하고 스님이 좋아하시는 보조지표인지 알 것 같아요. 특히 DI 부분에서 고점들과 저점들을 비교해서 TR 로 나눠 매수세/매도세를 퍼센트로 상대적 수치화하는 부분이 굉장히 인상 깊었습니다. 흐흐.. 뉴욕가서 스님 트레이딩 비기를 훔쳐보고 말겁니다!!!! ㅋㅋㅋㅋㅋㅋ :) 덕분에 레벨업한 기분입니다!
오오!! 스님도 얼른 비법을 갈쳐주시죠~~~ ㅋㅋㅋㅋㅋ (흥.. 맨날 제 보따리만 푸는 느낌입니다!) ADX 를 예전에 볼때 그냥 선들만 보고 될지 안될지 결정했었는데, 포스팅하는 겸, 변수가 어떻게 생기고, 함수는 어떻게 활용하는지 까지 보고 나니 굉장한 활용도가 보이네요. 왜 제이삼촌하고 스님이 좋아하시는 보조지표인지 알 것 같아요. 특히 DI 부분에서 고점들과 저점들을 비교해서 TR 로 나눠 매수세/매도세를 퍼센트로 상대적 수치화하는 부분이 굉장히 인상 깊었습니다. 흐흐.. 뉴욕가서 스님 트레이딩 비기를 훔쳐보고 말겁니다!!!! ㅋㅋㅋㅋㅋㅋ :) 덕분에 레벨업한 기분입니다!