input : Length(14);
var : TL(0),TH(0),cnt(0),Dcnt(0),preTRange(0),prePlusDM14(0),MinusDM14(0),TRange1(0),preMinusDM14(0);
Var : Counter(0), TRange(0), MyRange(Length), PlusDM14(0), PlusDM(0), MinusDM(0),preADX(0);
Var : CummDMI(0),b(0),DayDP(0),DayDM(0),DayADX(0),preADXv(0);
Array : HH[100](0),LL[100](0),CC[100](0),TR[100](0),DMIv[100](0);
// 새로운 영업일이 시작되면(일자 변경 시)
if bdate != bdate[1] Then
{
//일별 카운트
Dcnt = Dcnt+1;
//배열을 한 칸씩 밀고 현재값을 0번에 저장
for cnt = 99 downto 1
{
HH[cnt] = HH[cnt-1];
LL[cnt] = LL[cnt-1];
CC[cnt] = CC[cnt-1];
TR[cnt] = TR[cnt-1];
DMIv[cnt] = DMIv[cnt-1];
}
// 배열 0번방에 오늘 고/저/종가를 저장
HH[0] = H;
LL[0] = L;
CC[0] = C;
//각 변수의 전일값을 저장
preTRange = TRange[1];
prePlusDM14 = PlusDM14[1];
preMinusDM14 = MinusDM14[1];
preADXv = DayADX[1];
}
// 당일의 고가/저가 갱신 (같은 일 내에서 고/저를 계속 갱신)
if H > HH[0] Then
HH[0] = H;
if L < LL[0] Then
LL[0] = L;
// 종가 갱신
CC[0] = C;
// 전일 종가가 존재하는 경우(과거 데이터가 있는 경우)에
if CC[1] > 0 Then
{
//True Range 계산
If CC[1] > HH[0] then
TH = CC[1];
else
TH = HH[0];
If CC[1] < LL[0] then
TL = CC[1];
else
TL = LL[0];
TR[0] = TH-TL;
}
// 초기기간(Length+1일째)에는 기간 전체를 합산하여 초기값 계산
If Dcnt == Length+1 Then
{
// 사용할 기간 설정
MyRange = Length;
// 초기 누적값 초기화
DayDP = 0;
PlusDM14 = 0;
TRange = 0;
DayDM = 0;
MinusDM14 = 0;
TRange1 = 0;
// 기간 전체를 순회하며 PlusDM, MinusDM, TrueRange 누적
For Counter = 0 To MyRange - 1
{
If HH[Counter] - HH[Counter+1] < 0 Then
PlusDM = 0 ;
Else
PlusDM = HH[Counter] - HH[Counter+1];
If LL[Counter+1] - LL[Counter] < 0 Then
MinusDM = 0;
Else
MinusDM = LL[Counter+1] - LL[Counter];
var1 = PlusDM;
var2 = MinusDM;
// 동일 기간에서 더 큰 방향성만 남김 (상승/하락 중 하나만)
If var1 >= var2 Then
MinusDM = 0;
If var2 >= var1 Then
PlusDM = 0;
TRange = TRange + TR[Counter];
PlusDM14 = PlusDM14 + PlusDM;
MinusDM14 = MinusDM14 + MinusDM;
}
// 비율 계산 (정규화)
If TRange <> 0 Then
DayDP = 100 * PlusDM14 / TRange;
Else
DayDP = 0 ;
If TRange <> 0 Then
DayDM = 100 * MinusDM14 / TRange;
Else
DayDM = 0;
// DMI 값 (DI 차이의 절대값 비율)
If DayDP + DayDM == 0 Then
DMIv[0] = 0;
Else
DMIv[0] = 100 * AbsValue(DayDP - DayDM) / (DayDP + DayDM);
}
// 그 이후(정상 운용) 시 매일 지수평활 업데이트 방식으로 값 갱신
Else If Dcnt > Length+1 Then
{
// 일단 당일의 PlusDM/MinusDM 계산 (전일 대비)
If HH[0] - HH[1] < 0 Then
PlusDM = 0;
Else
PlusDM = HH[0] - HH[1];
If LL[1] - LL[0] < 0 Then
MinusDM = 0;
Else
MinusDM = LL[1] - LL[0];
var1 = PlusDM;
var2 = MinusDM;
// 상하 방향 중 큰 것만 채택
If var1 >= var2 Then
MinusDM = 0;
If var2 >= var1 Then
PlusDM = 0;
// 지수평활 방식으로 이전 누적값에서 일부를 빼고 당일 값을 더함
If MyRange > 0 Then
{
TRange = preTRange - (preTRange / MyRange) + TR[0];
PlusDM14 = prePlusDM14 - (prePlusDM14 / MyRange) + PlusDM;
MinusDM14 = preMinusDM14 - (preMinusDM14 / MyRange) + MinusDM;
}
// 비율 계산
If TRange <> 0 Then
DayDP = 100 * PlusDM14 / TRange;
Else
DayDP = 0 ;
If TRange <> 0 Then
DayDM = 100 * MinusDM14 / TRange;
Else
DayDM = 0;
If DayDP + DayDM == 0 Then
DMIv[0] = 0;
Else
DMIv[0] = 100 * AbsValue(DayDP - DayDM) / (DayDP + DayDM);
}
// ADX 계산: 초기 ADX는 최근 Length개의 DMI 평균으로 시작
If DMIv[Length] == 0 Then
{
CummDMI = 0;
b = 0;
for Counter = 0 To Length-1
{
if DMiV[counter] > 0 Then
{
CummDMI = CummDMI + DMIV[Counter];
b = b+1;
}
}
DayADX = CummDMI / B; // 초기 ADX
}
Else
// 이후 ADX는 지수평활 방식으로 갱신
DayADX = (preADXv * (Length - 1) + DMIv[0]) / Length;
// 차트 출력: ADX, DI+(%) 및 DI-(%) (여기선 DayDP/DayDM 사용)
plot1(DayADX);
plot2(DayDP);
plot3(DayDM);
plot4(DMiV[0]);
JavaScript
복사
[공식]
1.
Directional Movement 계산
DM은 금일의 주가움직임의 범위(고가-저가)가 전일의 주가움직임의 범위를 벗어나는 부분중에서 가장 큰 부분으로 정의 된다. 이때 금일범위가 전일범위에서 위로 확장된 경우 PDM값은 당일고가와 전일고가와의 차이가 되며, NDM은 '0'이 된다. 금일범위가 전일범위에서 아래로 확장된 경우에는 전일저가와 당일저가와의 차이를 NDM값으로 하고, PDM값은 '0'이 된다.
2.
True Range 계산
이것은 전일과 당일 주가의 전체 변동범위를 의미하며,
구체적으로는 당일의 고가와 저가의 폭, 당일의 고가와 전일의 종가의 폭,
당일의 저가와 전일의 종가의 폭중에서 절대값이 가장 큰 것으로 정의된다.
3.
PDI, NDI 계산
평활화된 PDM과 NDM을 각각 평활화된 TR로 나누어 PDI와 NDI를 계산한다.
여기서 평활화 방법은 일반적으로 14일 지수이동평균을 사용한다.
4.
Directional Movement Index 계산
PDI에서 NDI을 뺀값에 절대치를 취한 것을 PDI과 NDI의 합으로 나누어
백분율로 구한것이다.
5.
ADX 계산
DX를 14일 지수이동평균으로 평활화 시켜 구한다.