분봉 차트에서 다른 분봉을 계산할 때는,
현재 차트 주기의 배수에 해당하는 더 큰 주기만 가능합니다.
예) 5분봉 → 10분봉, 15분봉, 20분봉
랭귀지는 봉의 시가, 고가, 저가, 종가만 활용할 수 있으며,
개별 봉의 내부 가격 변동이나 시간 흐름은 알 수 없습니다.
따라서 차트 주기보다 낮은 주기는 수식으로 계산할 수 없으며,
차트 주기의 배수가 아닌 주기 역시 계산이 불가능합니다.
input : 분주기(30),Length(14);
var : TL(0),TH(0),cnt(0),Dcnt(0),preTRange(0),prePlusDM14(0),MinusDM14(0),preMinusDM14(0);
Var : TRange(0), MyRange(Length), PlusDM14(0), PlusDM(0), MinusDM(0),preADX(0);
Var : CummDMI(0), Cummi(0);
var : S1(0),D1(0),TM(0),TF(0),CB(0);
var : DPlus(0),DMinus(0),ADXv(0),PreADXv(0);
Array : HH[61](0),LL[61](0),CC[61](0),TR[61](0),DMIv[61](0);
// 새로운 영업일이 시작하면 시작시간(S1)과 날짜(D1)를 초기화
if Bdate != Bdate[1] Then
{
//첫봉의 stime을 분단위로 변환
S1 = TimeToMinutes(stime);
//첫봉의 날짜를 저장
D1 = sdate;
}
// D1에 날짜가 저장된 이후(영업일 변경이 되는 봉이 발생 후에)
if D1 > 0 then
{
//같은 날짜인지 판단하여 영업일 변경이후 경과분(TM)계산
if sdate == D1 Then
TM = TimeToMinutes(stime)-S1;//첫봉과 동일날짜이면 첫봉부터 경과분계산
Else
TM = TimeToMinutes(stime)+1440-S1;//다음날이면 24시간(1440분)을 더해서 보정
//영업일 변경이후 경과분을 분주기로 나누어 나머지를 구함
TF = TM%분주기;
//새로운 영업일이 시작하거나 새로운 분이 시작되면
if Bdate != Bdate[1] or
(Bdate == Bdate[1] and 분주기 > 1 and TF < TF[1]) or
(Bdate == Bdate[1] and 분주기 > 1 and TM >= TM[1]+분주기) or
(Bdate == Bdate[1] and 분주기 == 1 and TM > TM[1]) Then
{
Dcnt = Dcnt+1;
if Dcnt >= Length+2 Then
CB = CB+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 = ADXv[1];
}
// 봉의 고저 업데이트
if H > HH[0] Then
HH[0] = H;
if L < LL[0] Then
LL[0] = L;
// 최신 종가 저장
CC[0] = C;
// 전 봉(전체 집계용) 기준 TR 계산: 이전 종가 기준으로 고저 범위 산출
if CC[1] > 0 Then{
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; // 해당 분봉의 TR
}
// CB==1: 초기 윈도우(Length) 동안의 DMI/ADX 계산(단순 합산)
If CB == 1 Then
{
MyRange = Length;
DPlus = 0;
PlusDM14 = 0;
TRange = 0;
DMinus = 0;
MinusDM14 = 0;
For cnt = 0 To MyRange - 1 {
// +DM, -DM 계산(현재봉과 다음봉 비교)
If HH[cnt] - HH[cnt+1] < 0 Then
PlusDM = 0 ;
Else
PlusDM = HH[cnt] - HH[cnt+1];
If LL[cnt+1] - LL[cnt] < 0 Then
MinusDM = 0;
Else
MinusDM = LL[cnt+1] - LL[cnt];
var1 = PlusDM;
var2 = MinusDM;
// 두 방향성 중 큰 쪽만 채택
If var1 >= var2 Then
MinusDM = 0;
If var2 >= var1 Then
PlusDM = 0;
TRange = TRange + TR[cnt];
PlusDM14 = PlusDM14 + PlusDM;
MinusDM14 = MinusDM14 + MinusDM;
}
// 비율로 환산
If TRange <> 0 Then
DPlus = 100 * PlusDM14 / TRange;
Else
DPlus = 0 ;
If TRange <> 0 Then
DMinus = 100 * MinusDM14 / TRange;
Else
DMinus = 0;
If DPlus + DMinus == 0 Then
DMIv[0] = 0;
Else
DMIv[0] = 100 * AbsValue(DPlus - DMinus) / (DPlus + DMinus); // DMI 값(초기)
}
// CB>1: 지수 가중(또는 Wilder 방식과 유사)으로 누적 갱신
Else If CB > 1 Then {
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 {
// Wilder 식(이전값 비율 보존 후 현재값 추가)
TRange = preTRange - (preTRange / MyRange) + TR[0];
PlusDM14 = prePlusDM14 - (prePlusDM14 / MyRange) + PlusDM;
MinusDM14 = preMinusDM14 - (preMinusDM14 / MyRange) + MinusDM;
}
// 비율 환산
If TRange <> 0 Then
DPlus = 100 * PlusDM14 / TRange;
Else
DPlus = 0 ;
If TRange <> 0 Then
DMinus = 100 * MinusDM14 / TRange;
Else
DMinus = 0;
If DPlus + DMinus == 0 Then
DMIv[0] = 0;
Else
DMIv[0] = 100 * AbsValue(DPlus - DMinus) / (DPlus + DMinus); // DMI(현재)
}
// ADX 계산: 초기구간은 단순평균, 이후는 지수식
If CB >= 1 AND Length > 0 Then
{
If CB < Length Then
{
CummDMI = 0;
for cnt = 0 To CB - 1
{
CummDMI = CummDMI + DMIV[cnt];
}
ADXv = CummDMI / CB; // 초기 구간 평균
}
Else
ADXv = (PreADXv * (Length - 1) + DMIv[0]) / Length; // 이후 지수식 평균
}
plot1(adxV);
plot2(DPlus);
plot3(DMinus);
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일 지수이동평균으로 평활화 시켜 구한다.
[설명]
분봉차트에서 다른 분봉주기의 ADX, DMI, DI+, DI-를 계산하는 수식입니다.
1.
24시간 거래되는 상품들도 있으므로
날짜변경이 아닌 영업일 변경을 기준으로 현재봉이 몇분이 경과했는지 계산
2.
경과한 분을 다른주기로 나누어 나머지를 구해서
다른주기의 시작봉 체크
3.
필요한 값을 배열에 저장하는데
새로운 다른주기 시작봉이 발생하면 기존 배열의 값을 다음방으로 순차적으로 이동하고
0번방에 최신값 저장
4.
계산에 필요한 배열값이 모이면 계산