#property description "지표에는 현재 지표에 더 큰 시간 프레임의 캔들스틱이 표시됩니다"
//--- 지표 설정
#property indicator_chart_window
#property indicator_buffers 16
#property indicator_plots 8
//---- 플롯 1
#property indicator_label1 "BearBody"
#property indicator_color1 clrSeaGreen,clrSeaGreen
//---- 플롯 2
#property indicator_label2 "BearBodyEnd"
#property indicator_color2 clrSeaGreen,clrSeaGreen
//---- 플롯 3
#property indicator_label3 "BearShadow"
#property indicator_color3 clrSalmon,clrSalmon
//---- 플롯 4
#property indicator_label4 "BearShadowEnd"
#property indicator_color4 clrSalmon,clrSalmon
//---- 플롯 5
#property indicator_label5 "BullBody"
#property indicator_color5 clrOlive,clrOlive
//---- 플롯 6
#property indicator_label6 "BullBodyEnd"
#property indicator_color6 clrOlive,clrOlive
//---- 플롯 7
#property indicator_label7 "BullShadow"
#property indicator_color7 clrSkyBlue,clrSkyBlue
//---- 플롯 8
#property indicator_label8 "BullShadowEnd"
#property indicator_color8 clrSkyBlue,clrSkyBlue
//--- 사전정의된 상수
#define INDICATOR_EMPTY_VALUE 0.0
//--- 매개변수 입력
input ENUM_TIMEFRAMES InpPeriod=PERIOD_H4; // 지표 계산을 위한 시간 프레임
input datetime InpDateStart=D'2013.01.01 00:00'; // 분석 시작 일자
//--- 캔들스틱에 대한 지표 버퍼
double ExtBearBodyFirst[];
double ExtBearBodySecond[];
double ExtBearBodyEndFirst[];
double ExtBearBodyEndSecond[];
double ExtBearShadowFirst[];
double ExtBearShadowSecond[];
double ExtBearShadowEndFirst[];
double ExtBearShadowEndSecond[];
//--- 강세 캔들스틱에 대한 지표 버퍼
double ExtBullBodyFirst[];
double ExtBullBodySecond[];
double ExtBullBodyEndFirst[];
double ExtBullBodyEndSecond[];
double ExtBullShadowFirst[];
double ExtBullShadowSecond[];
double ExtBullShadowEndFirst[];
double ExtBullShadowEndSecond[];
//--- 글로벌 변수
datetime ExtTimeBuff[]; // 더 큰 시간 프레임의 시간 버퍼
int ExtSize=0; // 시간 버퍼 크기
int ExtCount=0; // 인덱스 내부 시간 버퍼
int ExtStartPos=0; // 지표 계산을 위한 초기 포지션
bool ExtStartFlag=true; // 초기 포지션 수신을 위한 보조 플래그
datetime ExtCurrentTime[1]; // 더 큰 시간 프레임의 막대 생성의 마지막 시간
datetime ExtLastTime; // 더 큰 시간 프레임에서 계산이 수행된 마지막 시간
bool ExtBearFlag=true; // 지표 버퍼에 데이터를 쓰는 순서를 정의하는 플래그
bool ExtBullFlag=true; // 강세 지표 버퍼에 데이터를 쓰는 순서를 정의하는 플래그
int ExtIndexMax=0; // 배열의 최대 ㅇ요소 인덱스
int ExtIndexMin=0; // 배열의 최소 요소 인덱스
int ExtDirectionFlag=0; // 현재 캔들스틱에 대한 가격 이동 방향
//--- 정확한 드로잉을 위해 캔들스틱의 시가와 종가 사이를 바꿈
const double ExtEmptyBodySize=0.2*SymbolInfoDouble(Symbol(),SYMBOL_POINT);
//+------------------------------------------------------------------+
//| 캔들스틱의 기본 부분 채우기 |
//+------------------------------------------------------------------+
void FillCandleMain(const double &open[],const double &close[],
const double &high[],const double &low[],
const int start,const int last,const int fill_index,
int &index_max,int &index_min)
{
//--- 배열에서 최대 및 최소 요소의 인덱스를 찾기
index_max=ArrayMaximum(high,ExtStartPos,last-start+1); // 최대(고가)
index_min=ArrayMinimum(low,ExtStartPos,last-start+1); // 최소(저가)
//--- 현재 시간 프레임에서 몇 개의 막대를 채울 것인지를 정의
int count=fill_index-start+1;
//--- 첫 막대의 종가가 마지막 막대의 종가보다 높으면 캔들스틱은 약세입니다
if(open[start]>close[last])
{
//--- 그 전에 캔들스틱이 강세였다면, 강세 지표의 값을 지웁니다
if(ExtDirectionFlag!=-1)
ClearCandle(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,start,count);
//--- 약세 캔들스틱
ExtDirectionFlag=-1;
//--- 캔들스틱 생성
FormCandleMain(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,open[start],
close[last],high[index_max],low[index_min],start,count,ExtBearFlag);
//--- 함수 나가기
return;
}
//--- 첫 번째 막대의 종가가 마지막 막대의 종가보다 낮으면 캔들스틱은 강세입니다
if(open[start]<close[last])
{
//--- 그 전에 캔들스틱이 약세였다면, 약세 지표 버퍼 값을 지웁니다
if(ExtDirectionFlag!=1)
ClearCandle(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,start,count);
//--- 강세 캔들스틱
ExtDirectionFlag=1;
//--- 캔들스틱 생성
FormCandleMain(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,close[last],
open[start],high[index_max],low[index_min],start,count,ExtBullFlag);
//--- 함수 나가기
return;
}
//--- 만약 여러분이 기능의 이 부분에 있다면, 첫 번째 막대의 오픈 가격은 다음과 같습니다
//--- 마지막 막대의 종가; 그러한 캔들스틱은 약세로 간주됩니다
//--- 그 전에 촛대가 강세였다면, 강세 지표 버퍼의 값을 지웁니다
if(ExtDirectionFlag!=-1)
ClearCandle(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,start,count);
//--- 약세 캔들스틱
ExtDirectionFlag=-1;
//--- 종가 및 시가가 동일할 경우, 정확한 표시를 위해 시프트를 사용
if(high[index_max]!=low[index_min])
FormCandleMain(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,open[start],
open[start]-ExtEmptyBodySize,high[index_max],low[index_min],start,count,ExtBearFlag);
else
FormCandleMain(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,
open[start],open[start]-ExtEmptyBodySize,high[index_max],
high[index_max]-ExtEmptyBodySize,start,count,ExtBearFlag);
}
//+------------------------------------------------------------------+
//| 캔들스틱의 끝 채우기 |
//+------------------------------------------------------------------+
void FillCandleEnd(const double &open[],const double &close[],
const double &high[],const double &low[],
const int start,const int last,const int fill_index,
const int index_max,const int index_min)
{
//--- 단 하나의 막대도 그리지 않습니다
if(last-start==0)
return;
//--- 첫 막대의 종가가 마지막 막대의 종가보다 높으면 캔들스틱은 약세입니다
if(open[start]>close[last])
{
//--- 캔들스틱 끝 생성
FormCandleEnd(ExtBearBodyEndFirst,ExtBearBodyEndSecond,ExtBearShadowEndFirst,ExtBearShadowEndSecond,
open[start],close[last],high[index_max],low[index_min],fill_index,ExtBearFlag);
//--- 함수 나가기
return;
}
//--- 첫 번째 막대의 종가가 마지막 막대의 종가보다 낮으면 캔들스틱은 강세입니다
if(open[start]<close[last])
{
//--- 캔들스틱 끝 생성
FormCandleEnd(ExtBullBodyEndFirst,ExtBullBodyEndSecond,ExtBullShadowEndFirst,ExtBullShadowEndSecond,
close[last],open[start],high[index_max],low[index_min],fill_index,ExtBullFlag);
//--- 함수 나가기
return;
}
//--- 만약 여러분이 기능의 이 부분에 있다면, 첫 번째 막대의 오픈 가격은 다음과 같습니다
//--- 마지막 막대의 종가; 그러한 캔들스틱은 약세로 간주됩니다
//--- 캔들스틱 끝 생성
if(high[index_max]!=low[index_min])
FormCandleEnd(ExtBearBodyEndFirst,ExtBearBodyEndSecond,ExtBearShadowEndFirst,ExtBearShadowEndSecond,open[start],
open[start]-ExtEmptyBodySize,high[index_max],low[index_min],fill_index,ExtBearFlag);
else
FormCandleEnd(ExtBearBodyEndFirst,ExtBearBodyEndSecond,ExtBearShadowEndFirst,ExtBearShadowEndSecond,open[start],
open[start]-ExtEmptyBodySize,high[index_max],high[index_max]-ExtEmptyBodySize,fill_index,ExtBearFlag);
}
//+------------------------------------------------------------------+
//| 사용자 지정 지표 초기화 함수 |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 지표 기간 확인
if(!CheckPeriod((int)Period(),(int)InpPeriod))
return(INIT_PARAMETERS_INCORRECT);
//--- 가격 데이터를 전면에 표시
ChartSetInteger(0,CHART_FOREGROUND,0,1);
//--- 바인딩 지표 버퍼
SetIndexBuffer(0,ExtBearBodyFirst);
SetIndexBuffer(1,ExtBearBodySecond);
SetIndexBuffer(2,ExtBearBodyEndFirst);
SetIndexBuffer(3,ExtBearBodyEndSecond);
SetIndexBuffer(4,ExtBearShadowFirst);
SetIndexBuffer(5,ExtBearShadowSecond);
SetIndexBuffer(6,ExtBearShadowEndFirst);
SetIndexBuffer(7,ExtBearShadowEndSecond);
SetIndexBuffer(8,ExtBullBodyFirst);
SetIndexBuffer(9,ExtBullBodySecond);
SetIndexBuffer(10,ExtBullBodyEndFirst);
SetIndexBuffer(11,ExtBullBodyEndSecond);
SetIndexBuffer(12,ExtBullShadowFirst);
SetIndexBuffer(13,ExtBullShadowSecond);
SetIndexBuffer(14,ExtBullShadowEndFirst);
SetIndexBuffer(15,ExtBullShadowEndSecond);
//--- 지표 생성을 위한 일부 속성 값 설정
for(int i=0;i<8;i++)
{
PlotIndexSetInteger(i,PLOT_DRAW_TYPE,DRAW_FILLING); // 그래픽 구성 유형
PlotIndexSetInteger(i,PLOT_LINE_STYLE,STYLE_SOLID); // 선 그리기 스타일
PlotIndexSetInteger(i,PLOT_LINE_WIDTH,1); // 선 그리기 굵기
}
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 사용자 지정 지표 반복 함수 |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
//--- 계산된 막대가 아직 없는 경우
if(prev_calculated==0)
{
//--- 더 큰 시간 프레임의 도착 시간 수신
if(!GetTimeData())
return(0);
}
//--- 직접 인덱싱 설정
ArraySetAsSeries(time,false);
ArraySetAsSeries(high,false);
ArraySetAsSeries(low,false);
ArraySetAsSeries(open,false);
ArraySetAsSeries(close,false);
//--- 막대 계산을 위한 시작 변수
int start=prev_calculated;
//--- 막대가 생성된 경우, 막대의 지표 값을 다시 계산
if(start!=0 && start==rates_total)
start--;
//--- 지표 값 계산을 위한 루프
for(int i=start;i<rates_total;i++)
{
//--- 빈 값으로 지표 버퍼의 i 요소 채우기
FillIndicatorBuffers(i);
//--- InpDateStart 날짜부터 막대 계산 수행
if(time[i]>=InpDateStart)
{
//--- 처음으로 값을 표시할 포지션 정의
if(ExtStartFlag)
{
//--- 초기 막대의 수를 저장
ExtStartPos=i;
//--- 더 긴 시간[i]을 초과한 첫 번째 날짜를 정의
while(time[i]>=ExtTimeBuff[ExtCount])
if(ExtCount<ExtSize-1)
ExtCount++;
//--- 이 블록에 다시 들어가지 않도록 플래그 값을 변경
ExtStartFlag=false;
}
//--- 배열에 아직 요소가 있는지 확인
if(ExtCount<ExtSize)
{
//--- 현재 시간 프레임의 값이 더 큰 시간 프레임의 값에 도달할 때까지 기다림
if(time[i]>=ExtTimeBuff[ExtCount])
{
//--- 캔들스틱의 주요 부분을 그림 (마지막 막대와 끝에서 2번째 막대 사이의 영역을 채우지 않음)
FillCandleMain(open,close,high,low,ExtStartPos,i-1,i-2,ExtIndexMax,ExtIndexMin);
//--- 캔들스틱의 끝 부분을 채움 (마지막 막대와 끝에서 2번째 막대 사이의 영역)
FillCandleEnd(open,close,high,low,ExtStartPos,i-1,i-1,ExtIndexMax,ExtIndexMin);
//--- 다음 캔들스틱을 그리기 위한 초기 포지션을 옮김
ExtStartPos=i;
//--- 배열 카운터 증가
ExtCount++;
}
else
continue;
}
else
{
//--- 배열 값 재설정
ResetLastError();
//--- 더 큰 시간 프레임에서 마지막 날짜 수신
if(CopyTime(Symbol(),InpPeriod,0,1,ExtCurrentTime)==-1)
{
Print("Data copy error, code = ",GetLastError());
return(0);
}
//--- 새 날짜가 이후인 경우 캔들스틱 생성을 중지
if(ExtCurrentTime[0]>ExtLastTime)
{
//--- 주 지표 버퍼에서 마지막 막대외 끝에서 2번째 막대 사이의 영역을 지움
ClearEndOfBodyMain(i-1);
//--- 보조 지표 버퍼를 사용하여 해당 구역에 기입
FillCandleEnd(open,close,high,low,ExtStartPos,i-1,i-1,ExtIndexMax,ExtIndexMin);
//--- 다음 캔들스틱을 그리기 위한 초기 포지션을 옮김
ExtStartPos=i;
//--- 가격 방향 플래그 재설정
ExtDirectionFlag=0;
//--- 새 마지막 날짜를 저장
ExtLastTime=ExtCurrentTime[0];
}
else
{
//--- 캔들스틱 생성
FillCandleMain(open,close,high,low,ExtStartPos,i,i,ExtIndexMax,ExtIndexMin);
}
}
}
}
//--- 다음 호출을 위한 prev_calculated의 반환 값
return(rates_total);
}
//+------------------------------------------------------------------+
//| 지정된 지표 기간의 정확성을 확인 |
//+------------------------------------------------------------------+
bool CheckPeriod(int current_period,int high_period)
{
//--- 지표 기간은 표시된 시간 프레임을 초과해야 합니다
if(current_period>=high_period)
{
Print("오류! 지표 기간의 값이 현지 시간 프레임의 값을 초과해야 합니다!");
return(false);
}
//--- 지표 기간이 1주일 또는 1개월이면 해당 기간이 올바릅니다
if(high_period>32768)
return(true);
//--- 기간 값을 분으로 변환
if(high_period>30)
high_period=(high_period-16384)*60;
if(current_period>30)
current_period=(current_period-16384)*60;
//--- 지표 기간은 표시된 시간 프레임의 배수가 되어야 합니다
if(high_period%current_period!=0)
{
Print("오류! 지표 기간의 값은 현재 시간 프레임 값의 배수가 되어야 합니다!");
return(false);
}
//--- 지표 기간는 표시된 시간 프레임을 3배 이상 초과해야 합니다
if(high_period/current_period<3)
{
Print("오류! 지표 기간은 현재 기간의 3배 이상 초과해야 합니다!");
return(false);
}
//--- 지표 기간이 현재 시간 프레임에 대해 올바릅니다
return(true);
}
//+------------------------------------------------------------------+
//| 더 큰 시간 프레임에서 시간 데이터 수신 |
//+------------------------------------------------------------------+
bool GetTimeData(void)
{
//--- 오류 값 재설정
ResetLastError();
//--- 현재 시간에 대한 모든 데이터를 복사
if(CopyTime(Symbol(),InpPeriod,InpDateStart,TimeCurrent(),ExtTimeBuff)==-1)
{
//--- 오류 코드 수신
int code=GetLastError();
//--- 에러 메시지 출력
PrintFormat("Data copy error! %s",code==4401
? "내역이 아직 업데이트되고 있습니다!"
: "Code = "+IntegerToString(code));
//--- false를 반환하여 데이터 다운로드를 반복해서 시도
return(false);
}
//--- 배열 크기 수신
ExtSize=ArraySize(ExtTimeBuff);
//--- 배열의 루프 인덱스를 0으로 설정
ExtCount=0;
//--- 시간 프레임에서 현재 캔들스틱의 포지션을 0으로 설정
ExtStartPos=0;
ExtStartFlag=true;
//--- 더 큰 시간 프레임의 마지ㅁㄱ 시간 값을 저장
ExtLastTime=ExtTimeBuff[ExtSize-1];
//--- 실행 성공
return(true);
}
//+--------------------------------------------------------------------------+
//| 기능은 캔들스틱의 주요 부분을 구성합니다. 플래그에 따라 |
//| 값, 함수는 데이터 및 배열을 정의합니다 |
//| 정확하게 표시하기 위해 사용하기 위해. |
//+--------------------------------------------------------------------------+
void FormCandleMain(double &body_fst[],double &body_snd[],
double &shadow_fst[],double &shadow_snd[],
const double fst_value,const double snd_value,
const double fst_extremum,const double snd_extremum,
const int start,const int count,const bool flag)
{
//--- 플래그의 값 확인
if(flag)
{
//--- 캔들스틱의 몸통 생성
FormMain(body_fst,body_snd,fst_value,snd_value,start,count);
//--- 캔들스틱의 그림자 생성
FormMain(shadow_fst,shadow_snd,fst_extremum,snd_extremum,start,count);
}
else
{
//--- 캔들스틱의 몸통 생성
FormMain(body_fst,body_snd,snd_value,fst_value,start,count);
//--- 캔들스틱의 그림자 생성
FormMain(shadow_fst,shadow_snd,snd_extremum,fst_extremum,start,count);
}
}
//+--------------------------------------------------------------------------------+
//| 기능은 캔들스틱의 끝을 구성합니다. 플래그의 값에 따라, |
//| 함수는 데이터 및 배열을 정의합니다 |
//| 정확하게 표시하기 위해 사용하기 위해. |
//+--------------------------------------------------------------------------------+
void FormCandleEnd(double &body_fst[],double &body_snd[],
double &shadow_fst[],double &shadow_snd[],
const double fst_value,const double snd_value,
const double fst_extremum,const double snd_extremum,
const int end,bool &flag)
{
//--- 플래그의 값 확인
if(flag)
{
//--- 캔들스틱의 몸통 끝을 생성
FormEnd(body_fst,body_snd,fst_value,snd_value,end);
//--- 캔들스틱의 그림자 끝을 생성
FormEnd(shadow_fst,shadow_snd,fst_extremum,snd_extremum,end);
//--- 플래그의 값을 반대로 변경
flag=false;
}
else
{
//--- 캔들스틱의 몸통 끝을 생성
FormEnd(body_fst,body_snd,snd_value,fst_value,end);
//--- 캔들스틱의 그림자 끝을 생성
FormEnd(shadow_fst,shadow_snd,snd_extremum,fst_extremum,end);
//--- 플래그의 값을 반대로 변경
flag=true;
}
}
//+-------------------------------------------------------------------------------------+
//| 캔들스틱의 끝(마지막과 끝에서 2번째 사이의 영역)을 지웁니다 |
//| 막대) |
//+-------------------------------------------------------------------------------------+
void ClearEndOfBodyMain(const int ind)
{
ClearCandle(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,ind,1);
ClearCandle(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,ind,1);
}
//+------------------------------------------------------------------+
//| 캔들스틱 비우기 |
//+------------------------------------------------------------------+
void ClearCandle(double &body_fst[],double &body_snd[],double &shadow_fst[],
double &shadow_snd[],const int start,const int count)
{
//--- 확인
if(count!=0)
{
//--- 빈 값으로 지표 버퍼 채우기
ArrayFill(body_fst,start,count,INDICATOR_EMPTY_VALUE);
ArrayFill(body_snd,start,count,INDICATOR_EMPTY_VALUE);
ArrayFill(shadow_fst,start,count,INDICATOR_EMPTY_VALUE);
ArrayFill(shadow_snd,start,count,INDICATOR_EMPTY_VALUE);
}
}
//+------------------------------------------------------------------+
//| 캔들스틱의 주요 부분 생성 |
//+------------------------------------------------------------------+
void FormMain(double &fst[],double &snd[],const double fst_value,
const double snd_value,const int start,const int count)
{
//--- 확인
if(count!=0)
{
//--- 값으로 지표 버퍼 채우기
ArrayFill(fst,start,count,fst_value);
ArrayFill(snd,start,count,snd_value);
}
}
//+------------------------------------------------------------------+
//| 캔들스틱의 끝 생성 |
//+------------------------------------------------------------------+
void FormEnd(double &fst[],double &snd[],const double fst_value,
const double snd_value,const int last)
{
//--- 값으로 지표 버퍼 채우기
ArrayFill(fst,last-1,2,fst_value);
ArrayFill(snd,last-1,2,snd_value);
}
//+------------------------------------------------------------------+
//| 지표 버퍼의 i 요소를 빈 값으로 채우기 |
//+------------------------------------------------------------------+
void FillIndicatorBuffers(const int i)
{
//--- 지표 버퍼의 셀에 빈 값을 설정
ExtBearBodyFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBearBodySecond[i]=INDICATOR_EMPTY_VALUE;
ExtBearShadowFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBearShadowSecond[i]=INDICATOR_EMPTY_VALUE;
ExtBearBodyEndFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBearBodyEndSecond[i]=INDICATOR_EMPTY_VALUE;
ExtBearShadowEndFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBearShadowEndSecond[i]=INDICATOR_EMPTY_VALUE;
ExtBullBodyFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBullBodySecond[i]=INDICATOR_EMPTY_VALUE;
ExtBullShadowFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBullShadowSecond[i]=INDICATOR_EMPTY_VALUE;
ExtBullBodyEndFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBullBodyEndSecond[i]=INDICATOR_EMPTY_VALUE;
ExtBullShadowEndFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBullShadowEndSecond[i]=INDICATOR_EMPTY_VALUE;
}
|