
ADX, DMI의 수식, 엑셀과 트레이딩뷰로 구현해보기
*2021-11-18 글
ADX란 Average Directional Movement Index의 약자로, 상승했을 때의 상승분과 하락했을 때의 하락분을 비교하여 추세를 정의하는 지표입니다.
다음과 같이 추세에 따라 적색, 청색선이 교차되고, 그 강도가 검정색 선으로 표기되는 모습을 확인할 수 있습니다.
여기서 적색, 청색선을 DMI (Directional Movement Index)라고 정의하며, DMI는 +DI와 -DI로 구성되어있습니다.
TR = 고가 - 저가, abs(전일 종가 - 고가), abs(전일 종가 - 저가) 중, 가장 큰 값
+DI = eavg(전일 고가 < 금일 고가이고, 전일 저가 하락 폭 < 금일 고가 상승 폭일 때, 상승 폭, 아니라면 0) / TR
- DI = eavg(전일 저가 > 금일 저가이고, 전일 저가 하락 폭 > 금일 고가 상승 폭일 때, 하락 폭, 아니라면 0) / TR
ADX는 다음과 같습니다.
ADX = eavg(abs(N일간 +DI - N일간 -DI) / (N일간 +DI + N일간 -DI) * 100)
*abs는 절대값, eavg는 지수이동평균을 의미
상승과 하락의 기준을 고저점 갱신 여부 및 상대적인 등락폭으로 비교함을 알 수 있습니다.
어쩌면 단순한 모멘텀과 비슷한 양상을 띌 수도 있으나 - 수식 구조 상, 꼬리가 길게 생긴 경우 추세를 잘 설명하지 못할 수 있다는 한계가 존재합니다.
위 자료는 아래꼬리가 긴 경우입니다. - DI (청색)가 급증하였으나, 이후 큰 반등이 눈에 띕니다.
이렇듯 ADX와 DMI는 고가와 저가끼리만 비교하기 때문에, 최근 추세를 반영하지 못하는 경우가 생깁니다.
위 경우를 더 자세히 보면, 확실히 하락 이후의 추세는 바뀐 것이 보입니다. 다만 지표는 추세의 전환을 표시하는데 13 candles의 딜레이가 발생하였습니다.
Backtest
카카오를 대상으로, 2000년 4월부터 2021년 11월까지 ADX & DMI를 사용한 "Long Only" 백테스팅 결과입니다.
모든 백테스트는 리스크 관리를 따로 하지 않았으며, 조건에 따라 자산의 100%를 전부 운용했을 때의 결과입니다.
ADX & DMI 설정 값은 14, 14입니다.
1.
매수 조건: +DI가 -DI를 상향 돌파하였을 때
매도 조건: +DI가 -DI를 하향 돌파하였을 때
Sharpe Ratio = 0.116
Sortino Ratio = 0.344
생각보다 결과가 잘나와서 당황스럽습니다. 카카오는 고저점의 갱신 여부와 추세의 상관관계가 높은 종목이었나 봅니다.
2.
매수 조건: +DI가 -DI를 상향 돌파하였을 때
매도 조건: ADX가 2일 연속 우하향하였을 때
Sharpe Ratio = 0.115
Sortino Ratio = 0.289
MDD를 줄이기 위해, 강도가 줄어들기 시작하면 바로 실현하는 조건으로 변경하였습니다.
확실히 MDD는 줄었으나 성과지표는 기존보다 안좋아졌습니다. 첫번째 백테스트의 수익률이 강하게 적용된 것이 원인으로 보입니다.
3.
매수 조건: +DI가 -DI를 상향 돌파하였을 때
매도 조건: +DI가 -DI보다 높고 ADX가 2일 연속 우하향하였을 때
Sharpe Ratio = 0.109
Sortino Ratio = 0.245
추세가 아직 끝나지 않은 상태일 때, 강도가 줄어들기 시작하면 실현하는 조건으로 변경해 보았습니다.
MDD가 소폭 완화되었으나, 수익률이 더 줄어들어 성과지표가 악화되었습니다.
DMI는 ADX의 강도 추이를 살펴보는 것이 MDD관리에 효과적임을 알 수 있었습니다.
Excel
1. TR
먼저 +DI와 - DI에 적용될 값인 TR(True Range)을 먼저 만들어 줍니다.
TR = MAX(고가 - 저가, ABS(전일 종가 - 고가), ABS(전일 종가 - 저가))
=MAX(C3-D3,ABS(B2-C3),ABS(B2-D3))
2. 상승 & 하락폭
상승폭은 금일 고가 - 전일 고가
하락폭은 전일 저가 - 금일 저가
로 만들어줍니다.
3. +DI, -DI Source
고가가 전일보다 높고, 상승폭이 하락폭보다 크다면
상승폭,
아니라면 0
=IF(AND(C2<C3,G3<F3),F3,0)
저가가 전일보다 낮고, 하락폭이 상승폭보다 크다면
하락폭,
아니라면 0
=IF(AND(D2>D3,G3>F3),G3,0)
4. DI
먼저, 데이터 - 테이터분석 - 지수평활법을 통해 Source의 지수이동평균을 만듭니다.
만약 데이터분석이 보이지 않는다면 좌측 상단 시작 - 엑셀옵션 - 추가기능 - 분석도구 추가를 통해 추가기능을 받아주시면 됩니다.
이 때, 감쇠인수는 1-알파 입니다.
DI의 지수평균에서 사용되는 알파는 1/기간으로, 감쇠인수에는 1 - (1/기간)을 입력해주시면 됩니다.
저의 경우 14일을 기준으로 잡았기 때문에,
1 - (1/14) = 0.92857
+DI -DI 모두 같은 방법으로 지수평균값을 만들어주시면 됩니다.
이후
지수이동평균값 / TR = DI
5. ADX
DMI를 모두 완성하셨습니다. 이제 ADX를 만들 차례입니다.
+DI, -DI의 차의 절대값 / +DI, -DI의 합 * 100
=ABS(L14-M14)/SUM(L14:M14)*100
이후 같은 방법으로 지수이동평균 시켜주면 ADX가 완성됩니다. 이번에도 14일을 기준으로 하였습니다.
ADX와 DI간 격차때문에 DI에도 각각 100씩 곱하여 표현하였습니다.
확대샷
엑셀로 그리려니 지저분해보입니다.
TradingView
//@version=4
study(title="ADX & DMI")
al = input(14, title="ADX length")
l = input(14, title="DI Length")
up = change(high)
down = -change(low)
pDM = na(up) ? na : (up > down and up > 0 ? up : 0)
mDM = na(down) ? na : (down > up and down > 0 ? down : 0)
tru = rma(tr, l)
p = fixnan(100 * rma(pDM, l) / tru)
m = fixnan(100 * rma(mDM, l) / tru)
sum = p + m
adx = 100 * rma(abs(p - m) / (sum == 0 ? 1 : sum), al)
plot(adx, color=color.black, title="ADX")
plot(p, color=color.red, title="+DI")
plot(m, color=color.blue, title="-DI")