English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
다른 인디케이터 기반으로 인디케이터를 쓰는 방법에 관하여

다른 인디케이터 기반으로 인디케이터를 쓰는 방법에 관하여

MetaTrader 5 | 5 7월 2021, 10:24
88 0
Dmitry Fedoseev
Dmitry Fedoseev

시작하며

MQL5에서는 "MQL5: 당신만의 인디케이터 만들기" 문서에 정리된 것 처럼 1부터 모든걸 만들어가는 방법 외에도, 클라이언트 터미널 내장이나 커스텀 인디케이터처럼 이미 존재하는 다른 인디케이터를 기반으로 만들어내는 방법이 있습니다. 두가지 선택지가 존재합니다: 첫번째는 인디케이터를 개선하는 것으로 새 계산과 도표를 넣습니다 (이 방식은 오픈소스코드인 커스텀 인디케이터에만 적용가능합니다), 두번째 방법은 터미널에 내장된 것이나 iCustom() 또는 IndicatorCreate() 함수들을 이용하여 기존의 커스텀 인디케이터를 활용하는 것이죠.

첫번째 선택지. 도표 추가하기

이 방식의 인디케이터 생성법을 다루는데에 "인디케이터를 다른 인디케이터에 적용시키기" 문서에서 나오는 True_Strength_Index_ver3 인디케이터를 활용해 개선해보는 것으로 보여드리겠습니다. 인디케이터에 평활 유형과 주기를 선택할 수 있는 신호 선을 추가해 보겠습니다. 이 프로세스는 총 8단계로 구성되어 있습니다.

1. 파일 카피 만들기

MetaEditor에서 True_Strength_Index_ver3 인디케이터를 열고 새 이름으로 저장하십시오, 예를 들면, TSIs. 새 파일은 터미널 루트 폴더의 the MQL5/Indicators 폴더에 저장되어야합니다.

2. 인디케이터의 속성 변환하기

인디케이터 코드에서 indicator_buffersindicator_plots 속성을 찾아보십시오. indicator_buffers 속성은 인디케이터에서 사용되는 인디케이터 버퍼의 총 수를 결정지으며 indicator_plots 속성은 차트에 표시되는 버퍼의 수를 의미합니다. 현재 표시기에는 8개의 버퍼가 사용되고 있으며, 그 중 하나가 차트에 표시됩니다. 차트에 표시할 버퍼를 하나 더 추가해야 합니다. indicator_buffersindicator_plots 값을 각각 1씩 올려보십시오.

#property indicator_buffers 8 
#property indicator_plots 2

3. 새 버퍼의 디스플레이 속성 판단하기

새 버퍼 표시의 속성을 설정하십시오. 이 인디케이터에서 이미 준비된 코드를 사용하십시오. 마우스를 사용하여 인디케이터의 첫 번째 줄 표시 속성을 결정하는 모든 코드를 복사합니다.

//---- plot TSI
#property indicator_label1 "TSI"
#property indicator_type1 DRAW_LINE
#property indicator_color1 Blue
#property indicator_style1 STYLE_SOLID
#property indicator_width1 1

첫 번째 줄의 속성 아래에 삽입하고 수정합니다.

//---- plot TSI Signal
#property indicator_label2 "TSISignal" // Line name that is displayed in a pop up help when the mouse cursor is put over the line
#property indicator_type2 DRAW_LINE    // Type of buffer 
#property indicator_color2 Red         // Color of the line
#property indicator_style2 STYLE_SOLID // Style
#property indicator_width2 1           // Thickness of the line

우선, 두 번째 버퍼의 속성이기 때문에 속성 수를 1에서 2로 변경합니다. indicator_label2 속성을 TSISignal로 변경합니다 - 이는 마우스 커서가 라인 위에 놓였을 때 노출되는 선의 이름이자 데이터창에 표시되는 것입니다. indicator_type2 속성은 바뀌지 말아야하고, 버퍼는 라인으로 표시되어야합니다. indicator_color2 속성을 빨강으로 바꾸세요 - 새 선은 빨간색이 될 것입니다. indicator_style2 속성은 그대로 둡니다 - 신호 선은 메인과 같은 스타일로 유지됩니다. indicator_width2 속성 역시 그대로 둡니다 - 새 선은 1픽셀 굵기로 남습니다.

4. 외부 변수 선언

인디케이터를 통해 변경할 수 있는 외부 변수 ("입력" 단어로 시작하는 줄들)는 코드에서 선의 속성 아래에 위치합니다. 신호 선에는 평활 주기 및 타입이라는 패러미터도 있어야 합니다.

int 타입에 값 5로 외부 변수를 하나 선언한 후 그 이름을 "sp" (smoothing period, 평활기간)이라고 해두고, ENUM_MA_METHOD 타입, 값은 MODE_EMA인 변수 "sm" (smoothing method, 평활메소드)를 선언합시다 (신호 선은 5의 평활기간과 지수평활을 기본값으로 가집니다). 외부 변수를 포함하는 코드의 섹션은 다음과 같습니다:

input int r=25;
input int s=13;
input int sp=5;
input ENUM_MA_METHOD sm=MODE_EMA;

5. 새 버퍼를 위해 어레이 선언하기

인디케이터 버퍼에서 사용할 어레이를 선언합니다. 코드에서 OnInit() 함수를 찾고, SetIndexBuffer() 함수의 호출값이 어디 위치해있는지 찾아서 인디케이터의 인디케이터 버퍼들 내부의 어레이들을 한 번 둘러보시기 바랍니다. True_Strength_Index_ver3 인디케이터의 경우, 해당 어레이들은 TSIBuffer, MTMBuffer, AbsMTMBuffer, EMA_MTMBuffer, EMA2_MTMBuffer, EMA_AbsMTMBuffer, EMA2_AbsMTMBuffer 입니다.

TSIBuffer의 SetIndexBuffer() 함수는 INDICATOR_DATA 패러미터로 호출되는데 이것은 해당 버퍼가 차트에 표시될거란 의미입니다. 다른 어레이들은 INDICATOR_CALCULATIONS 패러미터로 호출됩니다. 즉, 어레이가 보조적이며 중간 계산에 사용된다는 의미입니다.

새로운 버퍼는 차트에 표시되어야 하므로 TSIBuffer 어레이의 선언 후에 선언하여 논리 순서를 유지하고 지표가 더 개선될 경우 코드의 방향을 쉽게 잡을 수 있도록 합시다.

따라서 먼저 차트에 표시되는 버퍼에 대해 두 개의 배열을 선언한 다음 중간 계산에 사용되는 버퍼에 대한 배열을 선언합니다.

//--- indicator buffers
double TSIBuffer[];
double TSISigBuffer[]; // Array for new buffer of the signal line
double MTMBuffer[];
double AbsMTMBuffer[];
double EMA_MTMBuffer[];
double EMA2_MTMBuffer[];
double EMA_AbsMTMBuffer[];
double EMA2_AbsMTMBuffer[]; 

6. 버퍼와 어레이 연동시키기

이제 어레이와 인디케이터 버퍼의 높은 주의 및 관리 연결을 필요로 하는 매우 중요한 단계입니다. 연결은 SetIndexBuffer() 함수를 통해서 합니다. 함수 호출의 첫 번째 패러미터는 어레이 인덱스, 두 번째 패러미터는 어레이 이름, 세 번째 패러미터는 버퍼의 목적을 나타내는 식별자입니다. 버퍼는 인덱스(첫 번째 패러미터)에 따라 표시기 속성 창의 "색상" 탭에 있으며, 차트에 그려진 순서대로 먼저 0 버퍼, 그 위에 버퍼 1이 표시됩니다.

인덱스 0, 1, 2...가 있는 버퍼에 대해 SetIndexBuffer() 함수를 순차적으로 호출할 필요는 없지만 인덱스 버퍼 설정 기능의 호출 순서를 유지합시다. TSIBuffer 어레이의 함수를 호출한 후 TSISigBuffer 어레이의 호출을 실행합니다. 메인 라인의 버퍼(TSIBuffer 어레이)에는 인덱스 0이 있으며, 이는 다음 버퍼(TSISigBuffer 어레이)에 인덱스 1이 있어야 함을 의미합니다.

TSISigBuffer 어레이 용으로 호출하는 SetIndexBuffer() 함수의 세번째 패러미터는 INDICATOR_DATA 상수입니다(버퍼는 차트 위에 표시).

SetIndexBuffer(0,TSIBuffer,INDICATOR_DATA);
SetIndexBuffer(1,TSISigBuffer,INDICATOR_DATA);

SetIndexBuffer() 함수의 나머지 버퍼들이 첫 패러미터의 순차적으로 증가된 값을 이용해서 불리도록 재 인덱싱처리합시다.

SetIndexBuffer(0,TSIBuffer,INDICATOR_DATA);
SetIndexBuffer(1,TSISigBuffer,INDICATOR_DATA);
SetIndexBuffer(2,MTMBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(3,AbsMTMBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(4,EMA_MTMBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(5,EMA2_MTMBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(6,EMA_AbsMTMBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(7,EMA2_AbsMTMBuffer,INDICATOR_CALCULATIONS);

이러한 특정 상황에서는 증가하는 인덱스에 따라 SetIndexBuffer() 함수를 호출하는 시퀀스를 유지하는 것이 좋습니다. 따라서, 추가적인 개선의 경우, 주의와 노력이 덜 소모되지요.
이제 8개 버퍼가 있고, 그 중 두개는 차트에서 보이는 상태입니다. indicator_buffersindicator_plots 인디케이터들의 속성에 같은 값이 들어가있는지 확인합시다 (스텝 2).

7. 신호 선의 값 계산하기

신호 선은 인디케이터의 주요 라인 데이터에 그려진 이동 평균을 나타냅니다. 클라이언트 터미널 배달에는 일련의 정보에서 이동 평균을 계산할 수 있는 라이브러리가 포함되어 있기때문에; 딱히 우리가 계산할 필요는 없습니다 (MovingAverages.mqh 파일). 그렇다고할까, 이 코드는 이미 인디케이터 코드(라인 14)에 포함되어 있습니다.

#include <MovingAverages.mqh>

남은 일은 해당 기능을 이용하는 것 뿐입니다.
OnCalculate() 함수 안에서 인디케이터 메인 라인의 계산이 끝난 점을 찾습니다 (TSIBuffer 어레이). 검색 기능을 사용하겠습니다. TSBuffer 어레이의 이름을 예를 들어 선언된 코드 부분에서 선택하십시오.(1번 그림). "Main Menu" - "Edit" - "Find and replace" - "Find" 를 실행하거나 Ctrl+F 단축키를 씁시다. 


1번 그림. 선택한 어레이 이름.

TSIBuffer 단어는 열린 "Find" 창의 "Find what" 필드에 이미 입력되어 있습니다. "Direction" 섹션에서 "Up"를 선택합니다. 이제 "Find" 창이 열리면 OnCalculate() 함수 바로 뒤에 커서를 놓고 "Find Next" 버튼을 한 번 누르면 TSIBuffer 어레이의 계산이 끝나는 위치를 바로 찾을 수 있습니다. 계산은 "for" 루프 안에서 이루어집니다. 이 루프 직후 신호 선 계산을 위한 코드를 추가하겠습니다(2번 그림).

TSIBuffer 값의 가장 최신 계산 위치 (빨간 화살표). 계산이 수행되는 주기는 빨간색 프레임으로 표시됩니다.
2번 그림 TSIBuffer 값의 가장 최신 계산 위치 (빨간 화살표). 계산이 수행되는 주기는 빨간색 프레임으로 표시됩니다.

모든 주요 4가지 유형의 이동 평균 계산 기능은 MovingAverages.mqh라이브러리에 포함되어 있습니다:

  • 심플 타입 - SimpleMAOnBuffer(),
  • 지수 타입 - ExponentialMAOnBuffer(),
  • 선형 가중 타입 - LinearWeightedMAOnBuffer(),
  • 평활 타입 - SmoothedMAOnBuffer().

이들 함수들은 모두 같은 패러미터 셋을 공유합니다: 

const int rates_total, const int prev_calculated, const int begin, const int period, const double& price[],double& buffer[]

이 함수의 price[] 패러미터는 초기 데이터가 있는 배열을 결정하며 이동 평균의 계산이 수행됩니다. buffer 패러미터는 이동 평균 값을 저장할 어레이입니다. rates_totalprev_calculated 패러미터는 onCalculate() 함수의 rates_total 과 prev_calculated 패러미터와 동일하며, price[] 어레이의 사이즈를 판단하며 어레이 내부에서 이미 처리된 요소의 수를 알 수 있습니다. begin 패러미터는 어레이 내부에서 실질적인 데이터가 시작되는 요소의 인덱스입니다. 

MovingAverages.mqh 라이브러리의 이동 평균 계산용 알고리즘이 특이한걸 생각하면 (이 기능은 본 문서의 주제와는 다소 어긋납니다), begin 패러미터를 조금 신중하게 설정할 필요가 있습니다.

어떤 경우에도 이 패러미터는 소스 데이터의 값이 시작하는 요소(TSIBuffer 어레이)보다 이전 어레이 요소로 설정해서는 안 됩니다. 계산에 오류가 발생하지 않는 경우 이후 요소를 지정할 수 있습니다.

begin의 승인가능한 값을 판단하려면, TSIBuffer 어레이의 값이 계산되는 - start 변수 값에서부터 시작되는 사이클인 for 사이클에 주의를 기울이십시오, 우리는 start 변수가 첫 인디케이터 계산에 담고있던 값을 찾아내야 합니다 (prev_calculated 값이 0이일 때). "start" 변수의 값은 매 사이클 직전에 계산되는데, 이는prev_calculated=0 일 때 입니다; 해당 계산은 이하의 공식을 통해 이루어집니다:

start=begin+r+s-1;

이동 평균 계산의 함수로 전달된 begin 변수는 해당 값과 동일해야합니다.

TSIBuffer 어레이는 계산 루프 후에 begin2 변수를 선언하고 begin+r+s-1 값을 넣습니다.

int begin2=begin+r+s-1; 

외부 패러미터 "sm"을 기반으로 다른 평활용 함수를 사용하는 가능성을 제공하기 위해서는, switch 연산자를 활용하십시오. sm 변수의 다른 변이형들 용으로는 해당 함수에 해당하는 호출을 쓰시면 됩니다.

switch(sm)
  {
   case MODE_EMA:
      ExponentialMAOnBuffer(rates_total,prev_calculated,begin2,sp,TSIBuffer,TSISigBuffer);
      break;
   case MODE_LWMA:
      LinearWeightedMAOnBuffer(rates_total,prev_calculated,begin2,sp,TSIBuffer,TSISigBuffer);
      break;
   case MODE_SMA:
      SimpleMAOnBuffer(rates_total,prev_calculated,begin2,sp,TSIBuffer,TSISigBuffer);
      break;
   case MODE_SMMA:
      SmoothedMAOnBuffer(rates_total,prev_calculated,begin2,sp,TSIBuffer,TSISigBuffer);
      break;
  }

그 뒤에 인디케이터에 신호 선을 볼 수 있게 됩니다. "Compile" 버튼을 눌러서, 클라이언트 터미널을 열고 차트에 인디케이터를 붙입니다 (3번 그림).



3번 그림 인디케이터 TSI들, 파랑 - 주요 선, 빨강 - 신규, 신호 선.

8. 버퍼 도표 앞부분 잘라내기

인디케이터가 있는 차트를 왼쪽 가장자리로 스크롤하면 인디케이터가 값을 계산하지 않은 부분에서 선을 그립니다. 별로 이뻐보이진 않는군요 (4번 그림).



4번 그림 계산이 수행되지 않은 부분의 인디케이터 그림. 

PLOT_DRAW_BEGIN 식별자로 호출된 PlotIndexSetInteger() 함수를 써서 버퍼가 그려지지않은 첫 바들의 숫자를 확인합니다. 해당 함수 콜은 인디케이터의 OnInit() 함수 안에서 이루어져야합니다. OnInit()함수 콜의 끝자락, 그러나 당연하게도 return(0)의 앞에 콜을 추가하십시오.

PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,r+s+sp);

"Compile" 버튼을 다시 누르고 표시기 도면의 정확한 시작을 확인합니다 (5번 그림).  



5번 그림. 인디케이터 그림의 올바른 도입부 

두번째 방법 이미 존재하는 인디케이터를 기반으로 새 인디케이터 만들기


이번엔 TSI 인디케이터의 메인 및 신호 선의 수렴 및 발산 지표의 생성 예를 사용하여 이러한 방법을 고려할 것입니.다 해당 인디케이터는 히스토그램으로 그려질 것이고 AO, AC 인디케이터들 처럼 두가지 으로 표현될 겁니다. 인디케이터 값이 상승하면 히스토그램은 녹색이 되며; 하락하는 경우 빨간색이 됩니다. 초반 도입부에서 언급되었듯이, 다른 인디케이터 기반으로 하려면 iCustom()IndicatorCreate() 함수를 사용할 수 있습니다. 우선 iCustom() 함수를 통해 인디케이터를 만드는 방법을 살펴봅시다.

iCustom() 함수를 이용하여 인디케이터 만들기


1. 새 인디케이터만들기

새 인디케이터를 만들어 봅시다. MetaEditor에서 새 인디케이터를 만들려면 "Main Menu" - "File" - "New" - "Custom Indicator" 명령을 실행하거나 "Ctrl+N" 키 조합을 눌러야 합니다. 나타나는 창의 "Name" 필드에서 새 표시기의 이름을 TSIsCDiCust로 지정한 다음 "Add" 버튼을 누릅니다. 외부 패러미터를 추가합니다, 외부 패러미터를 사용하니만큼 코드에서 이름은 딱히 중요하지 않습니다; 추가적으로 TSI 표시기에서 모든 외부 매개 변수를 복사하는 것이 더 쉬워집니다 (6번 그림).


마법사에서 커스텀 인디케이터를 만들기 그 첫번째 단계.
6번 그림. 마법사에서 커스텀 인디케이터를 만들기 그 첫번째 단계.

"Next" 버튼을 누르세요.

다음 창에서 인디케이터를 별도의 창에 그리도록 지정합니다. 최소최대값은 설정하지 마십시오. "Add" 버튼을 누르면 새 버퍼가 인디케이터 버퍼 목록에 나타납니다. 이름 - TSIsCD(마우스 커서를 인디케이터 선과 데이터 창에 놓으면 팝업 도움말로 표시됨) 및 유형 - 색상 히스토그램을 지정합니다.

그 뒤에 "Color" 창에 여러 색의 예제가 나타날 것입니다. 첫 예시용으로는 녹색 을, 둘째 예시로 빨강을 지정하고, 나머지는 그대로 둡니다. Tsi 및 TsiSignal이라는 버퍼를 두 개 더 추가합니다, 해당 버퍼들은 TSI 인디케이터의 값을 수신하고 저장하는 데 사용됩니다 (7번 그림).


마법사에서 커스텀 인디케이터를 만들기 그 두번째 단계. 
7번 그림. 마법사에서 커스텀 인디케이터를 만들기 그 두번째 단계.

"Finish" 버튼을 누르면 MetaEditor에서 새 인디케이터 템플릿이 열립니다.

2. 인디케이터와 인디케이터 버퍼들의 속성 수정하기

스텝 1에서 우리는 3개의 버퍼를 확인했습니다, 하지만 #property indicator_buffers의 값은 4입니다. 색상 히스토그램은 두 개의 버퍼를 사용합니다. 하나는 차트에 표시되고 인디케이터 값을 지정하며, 두 번째 버퍼는 첫 번째 버퍼의 표시 색상을 결정하는 데 사용됩니다. #property indicator_buffers 값은 그대로 두십시오. #property indicator_plots 값을 1로 변경합니다 - 차트에 오직 하나의 버퍼만 표시되어야합니다.

Tsi 및 TsiSignal 버퍼는 차트에 표시될 수 없으므로 모든 속성(2 및 3으로 끝나는 인디케이터의 모든 속성)을 삭제합니다.

//--- plot Tsi
#property indicator_label2 "Tsi"
#property indicator_type2 DRAW_LINE
#property indicator_color2 Red
#property indicator_style2 STYLE_SOLID
#property indicator_width2 1
//--- plot TsiSignal
#property indicator_label3 "TsiSignal"
#property indicator_type3 DRAW_LINE
#property indicator_color3 Red
#property indicator_style3 STYLE_SOLID
#property indicator_width3 1
OnInit() 함수에서 이들 버퍼를 위한 SetIndexBuffer() 함수 호출을 찾아 (어레이 이름은 TsiBuffer and TsiSignalBuffer), 세번째 패러미터의 값을 INDICATOR_DATA 에서 INDICATOR_CALCULATIONS로 바꾸십시오.
SetIndexBuffer(2,TsiBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(3,TsiSignalBuffer,INDICATOR_CALCULATIONS);

indicator_color1 속성을 변환하십시오 - 첫 두 색만 남기세요. 

#property indicator_color1 Green,Red

3. 외부 패러미터 선언하기

MetaEditor에서 TSIs 인디케이터를 열고 모든 외부 변수를 카피한 후 현재의 external variable Input1을 이들 패러미터로 교체하십시오.

//--- input parameters
input int r=25;
input int s=13;
input int sp=5;                 // Smoothing period
input ENUM_MA_METHOD sm=MODE_EMA; // Smoothing type

4. 인디케이터 핸들을 위한 변수 선언 및 인디케이터 호출하기

인디케이터의 공통 섹션에서 int 타입 변수를 선언하고 Handle이라 명명합니다. OnInit()의 맨 아래에서 iCustom() 함수를 호출하십시오. 이 함수는 만들어진 인디케이터의 handle을 리턴하는데; 이는 인디케이터의 값들을 받아오는 데에 필요합니다. 함수에서 리턴된 값을 Handle 변수에 넣으십시오.

iCustom() 함수의 처음 두 패러미터는 인디케이터 계산에 사용할 데이터 기호와 시간을 결정합니다. 인디케이터가 부착된 심볼과 타임프레임을 봅시다 - _SymbolPERIOD_CURRENT 입니다. 셋째 패러미터는 커스텀 인디케이터의 이름입니다, 우리의 경우엔 TSIs 입니다. 호출된 인디케이터의 모든 외부 패러미터가 추가로 나열됩니다:

Handle=iCustom(_Symbol,PERIOD_CURRENT,"TSIs",r,s,sp,sm);

5. OnCalculate() 함수 준비하기

OnCalculate() 함수로 넘깁시다. TSIs 인디케이터는 데이터 버퍼 1개로 계산되므로 OnCalculate() 함수의 첫 번째 형식을 사용합니다. 템플릿의 기존 OnCalculate() 함수의 두 번째 형식을 첫 번째 형식으로 변경합니다.

int OnCalculate(const int rates_total,         // size of the price[] array
                const int prev_calculated,   // bars processed during the previous call
                const int begin,             // from where the significant data begin
                const double &price[]        // array for calculation
                )
  {
   return(rates_total);
  }

이 함수 내에서 인디케이터에 대한 추가 작업이 수행됩니다.

6. 인디케이터의 계산 한계 정하기

인디케이터 개발에 있어 최우선 순위 및 제일 중요한 것은 처리된 바의 범위 제한을 결정하는 것입니다. 인디케이터를 시작할 때 각 바가 작동하는 동안 현재 형성된 한 개에 대해서만 인디케이터를 계산해야 합니다. 인디케이터 시작 지점을prev_calculated 변수값으로 확인할 수 있습니다. 만약 이 값이 0이라면, 인디케이터 시작 이래 OnCalculate() 함수의 첫 실행입니다.

OnCalculate() 함수의 첫 번째 실행 시엔 첫 번째 바의 인덱스를 결정해야 합니다. 이 값은 인디케이터 값 계산에 필요한 바 수에 따라 결정됩니다(인덱싱은 왼쪽에서 오른쪽으로 수행됨).

인디케이터 선의 기울기는 두 개의 바에 의해 결정되므로, 우리는 이전의 다른 바가 필요합니다. 바의 인덱스, 즉 price[] 어레이의 중요 데이터가 시작하는 곳, 은 begin 변수의 값입니다; 따라서 start=begin+1 바로부터 바들의 계산을 시작합니다.

이어서, 인디케이터 작업 중에, 바 계산의 인덱스는prev_calculated 변수 값부터 시작하는데 - 이 변수는 이미 처리된 바의 수를 담고 있습니다. 따라서 마지막에 계산된 바 인덱스를 찾으려면 prev_calculated에서 1을 빼야하는거죠.

마지막에 계산된 바가 포밍 바가 될 수 있기때문에 이 바는 다시 계산에 쓰이게 됩니다. 계산 한계는 price[] 어레이의 사이즈에 따라 결정됩니다 - rates_total 변수이죠. 마지막으로 계산된 바의 인덱스는rates_total-1와 같습니다 (어레이 사이즈 -1).

이 인디케이터가 다른 인디케이터를 계산에 사용하기에, 이 데이터를 얻게됩니다. 다른 인디케이터의 데이터는 CopyBuffer() 함수를 통해 얻을 수 있습니다. 함수의 첫 패러미터에서 인디케이터의 핸들을 명시해야하는데, 이는 복사되어야하는 데이터(handle은 스텝 4에서 확보됨)를 일컫는 것입니다; 두번째 패러미터에서는 복사된 버퍼 (복사된 인디케이터의 "Color" 탭에서 확인할 수 있고, 카운트는 0에서 시작)의 인덱스를 명시하게 됩니다.

세 번째 패러미터는 복사가 시작되는 바의 인덱스입니다. 이 경우 인덱싱은 오른쪽에서 왼쪽으로 수행되므로 제일 오른쪽 바가 0이 됩니다. 네 번째 패러미터는 복사할 어레이 요소의 수입니다. 계산에 사용된 바의 범위를 결정하는 것만큼 복사된 요소의 수를 결정하는 데도 주의해야 합니다. 이는 인디케이터의 퍼포먼스에 영향을 줍니다. 인디케이터 계산을 시작하는 바 인덱스는 사전에 결정되며, 복사된 요소의 수는 rates_total-start로 계산됩니다. 인디케이터가 포밍 바를 대상으로만 계산되는 작업 프로세스 중에는 어레이에서 오직 한 요소만이 복사됩니다.

만약 CopyBuffer() 함수들이 정보 복사 과정에 -1을 리턴한다면 이는 데이터가 복사될 수 없다는 의미로, 따라서 계산을 수행할 의미도 없다는 것입니다. 이 에러는 제대로 처리해야합니다. CopyBuffer() 의 초입에 bool 정적 변수를 선언하고 "error"라고 이름지어두십시오. 인디케이터 계산 프로세스 중에 오류가 발생하면, 특히 인디케이터 데이터를 복사하는 과정에서 True 값을 이 변수에 할당하고 OnCalculate() 함수의 실행을 종료합니다.

이전 OnCalculate() 기능을 실행하는 동안 오류가 발생했다고 오류 값이 표시되면 다음 체크 표시에서 전체 인디케이터를 다시 계산합니다. 따라서 OnCalculate() 함수 도입부는 이것처럼 보일 것입니다:

   static bool error=true; 
   int start;
   if(prev_calculated==0) // First execution of the OnCalculate() function after the indicator start
     {
      error=true; // Set the value True for the indicator to be calculated for all bars
     }
   if(error) // If value of error=true, then it is the first execution of the function after 
             // the start of the indicator, or there was an error of copying of data at the previous start
     {
      start=begin+1;
      error=false;
     }
   else
     {
      start=prev_calculated-1;
     }

   if(CopyBuffer(Handle,0,0,rates_total-start,TsiBuffer)==-1) // Copying data of main line of the indicator
     {
      error=true; // Failed to copy data, set the value True for the error variable to recalculate the whole 
                 // indicator at the next call of OnCalculate()
      return(0);  // End working of the function
     }
   if(CopyBuffer(Handle,1,0,rates_total-start,TsiSignalBuffer)==-1) // Copy data of the signal line of the indicator
     {
      error=true; // Failed to copy data, set the value true for the error variable to recalculate the whole
                 // indicator at the next call of the OnCalculate() function
      return(0);  // End working of the function
     }

인디케이터 계산 한계가 결정되었고, 이들 바의 범위에서 계산 루프를 돌립니다.

for(int i=start;i<rates_total;i++)
  {

  }

인디케이터 값을 계산하세요 (코드는 방금 만든 루프 안에 있습니다).

TsiCDBuffer[i]=TsiBuffer[i]-TsiSignalBuffer[i];

이제 가장 신나는 파트 - 버퍼 색칠하기 입니다. 아까 스테이지 1에서 우리는 인디케이터용 색상 히스토그램 의 사용을 확인했습니다. 이 그림 유형에는 두 개의 버퍼가 필요합니다. 하나는 표시기 값용이고 다른 하나는 색상용입니다. 색상 목록은 indicator_color1 속성에 설정됩니다. 버퍼 요소에 대해 값 0을 설정하면 인디케이터가 녹색으로 표시되고, 값 1을 설정하면 인디케이터가 빨간색으로 표시됩니다(목록의 lindicator_color1에 있는 위치에 따라, 번호 매기기 시작).

두 개의 인접한 바에서 인디케이터 값이 동일한 상황을 피할 수 없습니다. 이 경우 인디케이터는 이전 색상으로 표시되어야 합니다(위/아래로 이동할 때 색상이 두 개뿐이기 때문입니다). 따라서 계산을 시작할 때 TsiCDcolors 버퍼 값을 이전 바에 복사합니다. 

TsiCDColors[i]=TsiCDColors[i-1];

만약 상향 국면이면 인디케이터를 녹색으로 칠합니다.

if(TsiCDBuffer[i]>TsiCDBuffer[i-1])TsiCDColors[i]=0;

만약 하향 국면이면 인디케이터를 빨강색으로 칠합니다.

if(TsiCDBuffer[i]<TsiCDBuffer[i-1])TsiCDColors[i]=1;

이로써 우리는 거의 인디케이터 작업을 마칠 수 있게 되었습니다; 이제 인디케이터 그리기의 시작을 결정할 수 있게 되었습니다.

7. 인디케이터에서 작업 완료하기 

인디케이터 계산을 판단할 때에 begin 변수가 사용되긴 하지만, 이것이 begin 변수로 확인된 바에서 인디케이터 데이터가 시작된다는 의미는 아닙니다. 사용자 지정 인디케이터의 알고리즘을 모르는 경우 인디케이터 계산에 필요한 바 수를 확인하는 것이 거의 불가능합니다. 그렇기 때문에 이 단계를 건너뛰거나 경험에 근거하여 값을 탐지해도 된다는 것입니다. 그러나 TSI 인디케이터의 알고리즘을 알기 때문에 인디케이터의 시작점을 정확히 감지할 수 있습니다. PlotIndexSetInteger() 함수 콜을 PLOT_DRAW_BEGIN 인식자와 함께 OnInit() 함수로 넘기십시오. 

PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,r+s+sp);

TSIs 인디케이터는 소숫점 둘째 자리까지 정확히 표기합니다; IndicatorSetInteger() 함수에 INDICATOR_DIGITS 인식자를 썼을 때와 같습니다.

IndicatorSetInteger(INDICATOR_DIGITS,2);

인디케이터를 컴파일하고 차트에 붙이십시오 (8번 그림).

 
8번 그림. 인디케이터 TSIsCDiCust.

IndicatorCreate() 함수를 이용하여 인디케이터 만들기 


IndicatorCreate() 함수를 통한 인디케이터 생성은 스텝 4에서 IndicatorCreate() 함수가 iCustom() 대신 사용되는 점을 제하고는 iCustom() 함수를 통한 생성과정과 동일합니다.

1. TSIsCDiCust 인디케이터의 복사본을 TSIsCDiCreate 라는 이름으로 저장하십시오

2. 코드에서 iCustom() 함수가 어디에 있는지 찾습니다. 이제부터는 iCustom() 대신 IndicatorCreate() 기능의 호출이 수행됩니다. iCustom()과 마찬가지로 IndicatorCreate() 기능의 처음 두 패러미터는 인디케이터 계산에 사용할 심볼과 시간을 결정합니다. 세번째 패러미터는 인디케이터 타입의 인식자로, 커스텀 인디케이터에서는 IND_CUSTOM 입니다. 생성 지시자의 파라미터는 구조 MqlParam 어레이를 사용하여 함수에 전달됩니다.

MqlParam 어레이는 4개의 변수를 담고 있습니다 - 그 중 3개는 값들을 위해 쓰이는 각기 다른 타입의 변수입니다: double_value, integer_value 그리고 string_value; 다른 하나는 type인데, 이는 사용된 변수의 타입을 확인하는데에 쓰입니다. TSIs 인디케이터엔 4개의 외부 패러미터가 있습니다. 이 인디케이터는 커스텀 인디케이터이기때문에 어레이의 첫 요소는 커스텀 인디케이터의 이름을 확인하게 해주므로, 어레이엔 총 5개의 요소가 있습니다. 구조들 (iCustom()이 호출된 곳에 코드 있음)의 어레이를 선언하십시오:

MqlParam Params[5];

어레이에 값을 채우세요:

   Params[0].type=TYPE_STRING;
   Params[0].string_value="TSIs"; // Specify name of the called custom indicator in the first parameter
   
   Params[1].type=TYPE_INT;
   Params[1].integer_value=r;
   
   Params[2].type=TYPE_INT;
   Params[2].integer_value=s;   
   
   Params[3].type=TYPE_INT;
   Params[3].integer_value=sp;      
   
   Params[4].type=TYPE_INT;
   Params[4].integer_value=sm;  

이미 IndicatorCreate() 함수로 전달된 첫 3개의 패러미터를 처리했습니다. 패러미터 어레이의 사이즈가 4번째 패러미터를 통해 전달되었습니다; 마지막은 패러미터 어레이 그 자체입니다:

Handle=IndicatorCreate(_Symbol,PERIOD_CURRENT,IND_CUSTOM,5,Params);

"Compile" 버튼을 누른 후 클라이언트 터미널에서 인디케이터를 확인하십시오.

마치며

다른 인디케이터를 기반으로 커스텀 인디케이터를를 만들 때 주의해야 할 주요 포인트를 간략히 반복해 보겠습니다.

인디케이터를 개선할 때엔 버퍼의 수와 그려질 버퍼의 수 (indicator_buffers, indicator_plots properties )를 올바르게 명시해야합니다; 또한 새 버퍼들(indicator_label, indicator_type, indicator_color, indicator_style, indicator_width properties)의 속성을 확인해야 합니다. 새 버퍼들을 위해 SetIndexBufer() 함수를 호출할 때는 세번째 패러미터(INDICATOR_DATA 혹은 INDICATOR_CALCULATIONS)의 값을 정확히 명시해야 합니다; 또한, 첫 패러미터 (인덱스 혹은 버퍼)의 값을 올바르게 명시하여야하며; 필요할 경우 버퍼의 재-인덱싱을 시행해야합니다.

또다른 커스텀 인디케이터를 이용해 새 인디케이터를 만들 때는 iCustom() 함수에 패러미터들을 올바르게 전달해야합니다; 그리고 IndicatorCreate() 함수를 쓸 때엔 패러미터 구조를 채워야합니다. 또한 여기서 SetIndexBuffer() 함수를 호출할 때 패러미터의 올바른 사양을 확인해야 하며, 가장 중요한 것은 새 버퍼에 대해 SetIndexBuffer() 함수를 호출하는 것을 잊지 말아야 한다는 것입니다.

인디케이터를 다룰 때엔 언제나 바 계산의 범위를 판단할 때 주의를 기울여야합니다 prev_calculated, rates_total, begin 변수들을 쓰는 것. MetaEditor는 프로그래밍동안 나타날 수 있는 다른 오류들(컴파일 중 "Errors" 탭에 나타나는 에러 메세지들)에 대응해줄 것입니다.

MetaQuotes 소프트웨어 사를 통해 러시아어가 번역됨.
원본 기고글: https://www.mql5.com/ru/articles/127

파일 첨부됨 |
tsis.mq5 (7.59 KB)
tsiscdicreate.mq5 (3.46 KB)
tsiscdicust.mq5 (3.11 KB)
20 MQL5에서의 매매 신호들 20 MQL5에서의 매매 신호들
본 문서는 매매시스템이 필요한 매매 신호를 어떻게 받는지 가르쳐줄 것입니다. 이 문서에서 다룰 20개의 매매 신호를 만드는 예시는 Expert Advisor 개발에 쓸 수 있는 별도의 커스텀 함수로 되어있습니다. 편의를 위해서, 본 문서에서 사용된 모든 함수는 미래에 Exper Advisor에 손쉽게 연결할 수 있도록 하나의 mqh include 파일에 들어 있습니다.
Expert Advisor에서의 자금 관리용 함수들 Expert Advisor에서의 자금 관리용 함수들
거래 전략의 개발은 주로 시장 진입과 퇴출을 위한 패턴을 찾는 것뿐만 아니라 포지션을 유지하는 것에 초점을 맞추고 있습니다. 만약 일부 패턴을 자동 트레이딩을 위한 공식으로 만들 수 있다면, 투자자는 자동 투자 모드에서 오픈 포지션을 보장하기 위해서 안전한 수준의 모기지 자금뿐만 아니라 포지션의 양, 마진의 크기를 계산해야하는 문제에 직면하게 됩니다. 이 글에서 우리는 그러한 계산을 할 수 있는 간단한 예시를 보이기 위해 MQL5 언어를 사용할 것입니다.
매매봇 프로토타입 매매봇 프로토타입
본 문서는 매매 시스템의 알고리즘과 요소들을 만드는 원리를 요약하고 체계화합니다. 본 문서는 익스퍼트 알고리즘 디자인을 다룹니다. 예시로서 빠르고 손쉬운 매매 시스템에 쓰일 수 있는 CExpertAdvisor 클래스가 사용될 것입니다.
구글 차트 API와 표준 라이브러리 클래스를 이용하여 정보 보드 만들기 구글 차트 API와 표준 라이브러리 클래스를 이용하여 정보 보드 만들기
MQL5 프로그래밍 언어는 주로 자동화된 거래 시스템과 복잡한 기술 분석 수단을 만드는 것을 목표로 합니다. 하지만 이것 외에도, 그것은 우리가 시장 상황을 추적하기 위한 흥미로운 정보 시스템을 만들 수 있게 해주며, 거래자와의 반품 연결을 제공합니다. 본 문서는 MQL5 표준 라이브러리 구성요소를 다룰 것이며, 목표 달성을 위한 실전 사례 또한 적어두었습니다. 또한 차트 작성에 쓰인 구글 차트 API의 실제 예시 또한 실려있습니다.