English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
MQL5: 나만의 인디케이터를 만들기

MQL5: 나만의 인디케이터를 만들기

MetaTrader 5 | 1 7월 2021, 10:32
390 0
MetaQuotes
MetaQuotes

시작하며

인디케이터란 무엇인가? 이는 우리가 간편하게 스크린에 표시하고싶은 계산값들의 집합을 일컫는 것 입니다. 값의 집합은 프로그램에서는 어레이로 표현되어있습니다. 따라서, 인디케이터의 생성이란 몇몇 어레이 (가격 어레이) 와 다른 어레이 (인디케이터 값) 를 다루는 알고리즘을 짜는 것을 말하는 것입니다..

이미 고전이 된 레디 인디케이터가 여럿 존재하지만, 나만의 인디케이터를 만들어야할 필요성은 언제나 존재하고 있습니다. 자기만의 알고리즘을 써서 그러한 인디케이터를 만드는 데, 이를 커스텀 인디케이터라고 합니다. 이 글에서 우리는 간략한 커스텀 인디케이터를 어떻게 만드는지 알아볼 것입니다.

인디케이터는 다릅니다

인디케이터는 색의 선이나 영역으로 표현되거나, 포지션 진입을 위한 지점을 가리키는 특별한 레이블로서 표현될 수 있습니다. 또한 이러한 타입들은 합쳐질 수 있기에 실제로는 더욱 다양한 인디케이터 타입이 있습니다. 우리는 인디케이터 생성을 윌리엄 블라우가 개발한 실제강도지수의 실례로 간주하고 있습니다.

실제강도지수

실제강도지수(TSI) 인디케이터는 트렌드, 과매수/과매도를 구분하기 위해 이중 평활 모멘텀에 기반을 두고 있습니다. 이의 수학적 해석은 윌리엄 블라우의 모멘텀, 방향, 분기에서 확인할 수 있습니다. 여기서는 계산식만을 인용하도록 하겠습니다.

TSI(CLOSE,r,s) =100*EMA(EMA(mtm,r),s) / EMA(EMA(|mtm|,r),s)

해설:

  • mtm = CLOSE현재 – CLOS이전, 현재 바와 이전 바 간의 가격 차이를 나타내는 값의 어레이;
  • EMA(mtm,r) = r 기간에 기반을 둔 mtm 값의 지수평활처리;
  • EMA(EMA(mtm,r),s) = s 기간에 기반을 둔 EMA(mtm,r) 값의 지수평활처리;
  • |mtm| = mtm 절대값;
  • r = 25,
  • s = 13.

본 공식으로 우리는 인디케이터 계산에 영향을 미치는 3개의 패러미터를 추출할 수 있습니다. 바로 기간 r, s와 계산에 쓰이는 가격의 타입입니다. 우리는 CLOSE 가격을 쓰겠습니다

MQL5 위자드

TSI를 파란 선으로 표시해봅시다 - 이를 위해 MQL5 위자드를 시작해야합니다. At the first stage we should indicated the type of a program we want to create - custom indicator. 두번째 단계에서는 프로그램의 이름을, 그리고 rs 패러미터와 값을 정합시다

MQL5 위자드: 인디케이터 이름과 패러미터 정하기

그 후 인디케이터가 별도의 창에 파란 선으로 표시되게끔, 그리고 이 선을 위한 TSI 레이블을 정합시다.

MQL5 위자드: 인디케이터 타입 세팅하기

초기 데이터가 전부 입력된 이후, Done을 눌러 인디케이터 드래프트를 완료합니다. 

//+------------------------------------------------------------------+
//|                                          True Strength Index.mq5 |
//|                        Copyright 2009, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2009, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1
//---- plot TSI
#property indicator_label1  "TSI"
#property indicator_type1   DRAW_LINE
#property indicator_color1  Blue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- input parameters
input int      r=25;
input int      s=13;
//--- indicator buffers
double         TSIBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,TSIBuffer,INDICATOR_DATA);
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {
//---
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

MQL5 위자드가 인디케이터 속성값을 쓰는 인디케이터 헤더를 만드는데, 예를 들자면:

  • 인디케이터가 다른 창에 표시되었는가;
  • 인디케이터 버퍼 수, indicator_buffers=1;
  • 플롯 수, indicator_plots= 1;
  • 1번 플롯 이름, indicator_label1="TSI";
  • 첫 플롯 스타일 - 선, indicator_type1=DRAW_LINE;
  • 1번 플롯 색상, indicator_color1=Blue;
  • 선 스타일, indicator_style1=STYLE_SOLID;
  • 1번 플롯 선 너비, indicator_width1=1.

모든 준비를 마쳤으니 이제 가다듬은 후 코드를 발전시킵니다.

OnCalculate()

OnCalculate() 함수는 Calculate 이벤트의 핸들러로, 인디케이터 값을 재계산하거나 해당 값을 차트에 다시 그리는 것이 필요할 때에 등장합니다. 새 틱 수령, 심볼 이력 업데이트, 등의 이벤트입니다. 이 때문에 인디케이터 값 계산의 모든 메인 코드가 바로 이 함수 속에 위치하여야 합니다.

당연하게도, 보조계산은 다른 별도의 함수로 실행될 수 있지만, 이 펑션들 모두 OnCalculate 핸들러 안에서 사용되어야합니다.

기본 값에서 MQL5 위자드는 모든 타임시리즈 타입에 액세스할 수 있는 OnCalculate()의 세컨 폼을 생성합니다:

  • 시가, 고가, 저가, 종가;
  • 거래량 (실물 및/혹은 틱);
  • 스프레드;
  • 기간 오픈 시간.

하지만 이 경우엔 데이터 어레이 단 하나면 되기 때문에OnCalculate() 첫번째 형태 를 바꿉니다.

int OnCalculate (const int rates_total,      // size of the price[] array
                 const int prev_calculated,  // number of available bars at the previous call
                 const int begin,            // from what index in price[] authentic data start
                 const double& price[])      // array, on which the indicator will be calculated
  {
//---
//--- return value of prev_calculated for next call
   return(rates_total);
  }  

이를 통해 지표를 가격 데이터에 추가로 적용 할 수있을 뿐만 아니라 다른 지표의 값을 기반으로 지표를 생성 할 수도 있습니다..

커스텀 인디케이터 계산을 위한 데이터 유형 지정

만약 우리가 패러미터 탭 (기본으로 제공됨)에서 Close를 선택하면 OnCalculate() 로 패싱된 price[] 에 종가를 포함합니다. 만약 Typical Price를 선택할 경우, price[] 는 대신 각 기간의 (고가+저가+종가)/3 를 포함합니다.

rates_total 매개 변수는 price[] 어레이의 크기를 나타내며, 사이클로 계산을 구성하는데에 쓸모있습니다. 가격[] 요소의 인덱싱은 0에서 시작하여 과거에서 미래로 이동합니다. 다시 말해, price[0] 요소는 가장 오래된 값을 포함하는 반면 price[rates_total-1]는 최신 어레이 요소를 포함합니다.

보조 인디케이터 버퍼 정리하기

하나의 선만 차트에 표시됩니다. 즉, 하나의 인디케이터 어레이의 데이터입니다. 하지만 그 전에 중간 계산을 정리해야 합니다. 중간 데이터는 INDICATOR_CALCULATIONS 속성으로 표시되는 인디케이터 어레이에 저장됩니다.. 공식에서 우리는 추가적인 어레이를 필요로 한다는걸 알 수 있습니다:

  1. mtm 값을 위해선 - 어레이 MTMBuffer[];
  2. |mtm| 값을 위해선 - 어레이 AbsMTMBuffer[];
  3. EMA(mtm,r)를 위해선 - 어레이 EMA_MTMBuffer[];
  4. EMA(EMA(mtm,r),s)를 위해선 - 어레이 EMA2_MTMBuffer[];
  5. EMA(|mtm|,r)를 위해선 - 어레이 EMA_AbsMTMBuffer[];
  6. EMA(EMA(|mtm|,r),s)를 위해선 - 어레이 EMA2_AbsMTMBuffer[].

총 합쳐서 6개의 더블 타입 어레이를 글로벌 레벨에 더해야하며, 이 어레이들을 OnInit() 함수에서 인디케이터 버퍼에 바인드해야합니다. 인디케이터 버퍼의 수를 명시하는 것을 잊지 마십시오; indicator_buffers 속성은 딱 7이어야합니다 (원래 1개가 있었고 6개가 더해졌기때문).

#property indicator_buffers 7

이 단계에서 인디케이터 코드는 이렇게 보입니다:

#property indicator_separate_window
#property indicator_buffers 7
#property indicator_plots   1
//---- plot TSI
#property indicator_label1  "TSI"
#property indicator_type1   DRAW_LINE
#property indicator_color1  Blue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- input parameters
input int      r=25;
input int      s=13;
//--- indicator buffers
double         TSIBuffer[];
double         MTMBuffer[];
double         AbsMTMBuffer[];
double         EMA_MTMBuffer[];
double         EMA2_MTMBuffer[];
double         EMA_AbsMTMBuffer[];
double         EMA2_AbsMTMBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,TSIBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,MTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(2,AbsMTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(3,EMA_MTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(4,EMA2_MTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(5,EMA_AbsMTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(6,EMA2_AbsMTMBuffer,INDICATOR_CALCULATIONS);
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate (const int rates_total,    // size of the price[] array;
                 const int prev_calculated,// number of available bars;
                                           // during the previous call;
                 const int begin,          // from what index in  
                                           // price[] authentic data start;
                 const double& price[])    // array, on which the indicator will be calculated;
  {
//---
//--- return value of prev_calculated for next call
   return(rates_total);
  }

중간 계산

MTMBuffer[] and AbsMTMBuffer[] 버퍼들을 위해 값 계산을 정리하는 것은 매우 쉽습니다. price[1] 에서 price[rates_total-1] 까지 루프를 통해 값을 하나씩 체크하며, 다른 하나의 어레이에 값 간의 차를 기재하며, 또 다른 어레이에 그 절대값을 기재합니다.

//--- calculate values of mtm and |mtm|
   for(int i=1;i<rates_total;i++)
     {
      MTMBuffer[i]=price[i]-price[i-1];
      AbsMTMBuffer[i]=fabs(MTMBuffer[i]);
     }

다음 단계는 이러한 어레이의 지수 평균 계산입니다. 이에는 두가지 방법이 있습니다 첫 방법은 실수를 피하기 위해 알고리즘을 통째로 쓰는 것입니다. 두번째 방법은 이미 디버깅 되어있으며, 정확히 이런 용도를 위해 준비된 함수를 쓰는 것입니다.

MQL5에 어레이 값으로 평균을 뽑는 내장 함수는 없지만 MovingAverages.mqh 같은 레디 라이브러리 함수가 있으며, 완전 경로는 terminal_directory/MQL5/Include/MovingAverages.mqh, 이고 이 안의 terminal_directory 는 MetaTrader5가 터미널이 설치된 카탈로그를 뜻합니다. 본 라이브러리는 파일을 포함하고 있으며; 이에는 4가지의 고전적 방법 중 하나를 이용하여 어레이에서 이동 평균을 산출해내는 함수가 들어있습니다:

  • 단순 평균화
  • 지수 평균화
  • 평활 평균화
  • 선형 가중 평균화

이들 함수를 이용하기 위해서는 아무 MQL5 프로그램에서 다음의 코드 헤딩을 추가하십시오:

#include <MovingAverages.mqh>

또한 값 어레이에서 지수 이동 평균을 계산하고 해당 값을 다른 어레이에 보존하는 ExponentialMAOnBuffer() 함수가 필요합니다.

어레이 평활화 처리 함수

MovingAverages.mqh 인클루드 파일에는 같은 타입 함수 2 그룹으로 각기 나뉠 수 있는 총 8개의 함수 (그룹당 각 4개씩) 가 들어있습니다. 첫 번째 그룹은 어레이를 받아서 지정된 위치에서 이동 평균의 값을 반환하는 함수를 포함합니다:

  • SimpleMA() - 단순 평균값 계산을 위하여;
  • ExponentialMA() - 지수 평균값 계산을 위하여;
  • SmoothedMA() - 평활 평균값 계산을 위하여;
  • LinearWeightedMA() - 선형 가중 평균값 계산을 위하여.

본 함수들은 어레이 하나에 대해 평균을 한 번 받기 위한 것으로, 여러번 호출되도록 상정되지 않았습니다. 이 그룹의 함수를 루프에서 사용하고자 하는 경우(평균 값을 계산하고 각 계산된 값을 어레이에 추가로 넣기 위하여), 최적화된 알고리즘을 구성해야 합니다.

두번째 그룹에 속하는 함수들은 초기 값 어레이로 계산된 이동 평균값으로 다른 어레이를 채우는 용도입니다:

  • SimpleMAOnBuffer() - 출력 어레이 buffer[] 를 price[] 어레이의 단순 평균값으로 채움;
  • ExponentialMAOnBuffer() - 출력 어레이 buffer[] 를 price[] 어레이의 지수 평균값으로 채움;
  • SmoothedMAOnBuffer() - 출력 어레이 buffer[] 를 price[] 어레이의 평활 평균값으로 채움;
  • LinearWeightedMAOnBuffer() -출력 어레이 buffer[] 를 price[] 어레이의 선형 가중 평균값으로 채움.

상술된 함수들은 buffer[] price[] 어레이 그리고 period 평균 기간을 제외하고는 추가적으로 OnCalculate() 함수의 패러미터와 비슷한 용도의 3개의 패러미터를 얻습니다. 본 그룹의 함수들은 price[] 및 buffer[] 를 패스받아 인덱스 방향을 고려해가며 (AS_SERIES 플래그) 올바르게 처리합니다.

begin 패러미터는 소스 어레이 내부에서 의미있는 스타팅 포인트, 즉 처리해야하는 데이터가 시작되는 인덱스를 나타냅니다. MTMBuffer[] 어레이의 경우 MTMbuffer[1]= price[1]-price[0] 이므로 실 데이터는 인덱스 1로 시작합니다. MTMBuffer[0]의 값은 정해져있지 않습니다. 그게 begin=1인 이유죠.

//--- calculate the first moving
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         1,  // index, starting from which data for smoothing are available 
                         r,  // period of the exponential average
                         MTMBuffer,       // buffer to calculate average
                         EMA_MTMBuffer);  // into this buffer locate value of the average
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         1,r,AbsMTMBuffer,EMA_AbsMTMBuffer);

출력 어레이에서 계산된 값은 더 큰 평균 주기보다 큰 작은 지연으로 채워지기 때문에 평균화할 때는 주기 값을 고려해야 합니다. 예를 들어, period=10인 경우 결과 어레이의 값은 begin+period-1=period+10-1로 시작합니다. buffer[] 추가 호출 시 이를 고려해야하며, begin+period-1에서부터 처리해야합니다

이런 이유로 MTMBuffer[] and AbsMTMBuffer: 어레이들에서 두번째 지수 평균을 손쉽게 뽑아낼 수 있습니다.

//--- calculate the second moving average on arrays
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         r,s,EMA_MTMBuffer,EMA2_MTMBuffer);
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         r,s,EMA_AbsMTMBuffer,EMA2_AbsMTMBuffer);

begin 값은 이 시점에서 r과 같은 값이 되는데, 이는 begin=1+r-1 (r은 기본 지수 평균의 주기이며 처리가 인덱스 1에서부터 시작되기에) 이기 때문입니다. EMA2_MTMBuffer[] 와 EMA2_AbsMTMBuffer[]의 출력 어레이에서, 계산된 값들은 r+s-1 인덱스부터 시작되는데, 이는 우리가 인풋 어레이를 인덱스 r부터 처리하기 시작하였으며, 두번째 지수 평균화 주기가 s와 같기 때문입니다.

모든 사전 계산이 끝났습니다. 이제 차트에 표시될 인디케이터 버퍼 TSIBuffer[]의 값들을 계산할 수 있습니다.

//--- now calculate values of the indicator
   for(int i=r+s-1;i<rates_total;i++)
     {
      TSIBuffer[i]=100*EMA2_MTMBuffer[i]/EMA2_AbsMTMBuffer[i];
     }
F5를 눌러 코드를 컴파일하고 MetaTrader5 터미널에서 기동시켜봅시다 잘 되네요!

실제강도지수의 첫 버전

아직 풀리지않은 궁금증이 몇 개 남아있습니다.

계산 최적화하기

사실, 작업지표를 작성하는 것만으로는 충분하지 않습니다. OnCalculate()의 현 구현버전을 보면 최적화된 상태가 아니란 것을 알 수 있습니다.

int OnCalculate (const int rates_total,    // size of the price[] array;
                 const int prev_calculated,// number of available bars;
                 // at the previous call;
                 const int begin,// from what index of the 
                 // price[] array true data start;
                 const double &price[]) // array, at which the indicator will be calculated;
  {
//--- calculate values of mtm and |mtm|
   MTMBuffer[0]=0.0;
   AbsMTMBuffer[0]=0.0;
   for(int i=1;i<rates_total;i++)
     {
      MTMBuffer[i]=price[i]-price[i-1];
      AbsMTMBuffer[i]=fabs(MTMBuffer[i]);
     }
//--- calculate the first moving average on arrays
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         1,  // index, starting from which data for smoothing are available 
                         r,  // period of the exponential average
                         MTMBuffer,       // buffer to calculate average
                         EMA_MTMBuffer);  // into this buffer locate value of the average
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         1,r,AbsMTMBuffer,EMA_AbsMTMBuffer);

//--- calculate the second moving average on arrays
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         r,s,EMA_MTMBuffer,EMA2_MTMBuffer);
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         r,s,EMA_AbsMTMBuffer,EMA2_AbsMTMBuffer);
//--- now calculate values of the indicator
   for(int i=r+s-1;i<rates_total;i++)
     {
      TSIBuffer[i]=100*EMA2_MTMBuffer[i]/EMA2_AbsMTMBuffer[i];
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }

각 함수 시작 시 MTMBuffer[] 및 AbsMTMBuffer[] 어레이의 값을 계산합니다. 이 경우 price[] 의 크기가 수십만 또는 수백만에 달하는 경우 불필요한 반복 계산으로 인해 아무리 강력한 성능의 CPU라도 그 모든 리소스가 소모될 수 있습니다.

최적의 계산을 구성하기 위해, 우리는 이전 통화에서 OnCalculate()가 반환한 값과 동일한 prev_calculated 입력 패러미터를 사용한다. 함수의 첫 번째 호출에서 prev_calculated의 값은 항상 0과 같습니다. 이 경우 표시기 버퍼의 모든 값을 계산합니다. 다음 호출 중에는 전체 버퍼를 계산할 필요가 없습니다. 마지막 값만 계산됩니다. 이렇게 적어봅시다:

//--- if it is the first call 
   if(prev_calculated==0)
     {
      //--- set zero values to zero indexes
      MTMBuffer[0]=0.0;
      AbsMTMBuffer[0]=0.0;
     }
//--- calculate values of mtm and |mtm|
   int start;
   if(prev_calculated==0) start=1;  // start filling out MTMBuffer[] and AbsMTMBuffer[] from the 1st index 
   else start=prev_calculated-1;    // set start equal to the last index in the arrays 
   for(int i=start;i<rates_total;i++)
     {
      MTMBuffer[i]=price[i]-price[i-1];
      AbsMTMBuffer[i]=fabs(MTMBuffer[i]);
     }

EMA_MTMBuffer[], EMA_AbsMTMBuffer[], EMA2_MTMBuffer[] 및 EMA2_AbsMTMbuffer[]의 계산 블록은 ExponentialMAOnBuffer()가 이미 최적화되어있기 때문에 계산의 최적화를 추가로 진행할 필요가 없습니다. TSIBuffer[] 어레이에 대한 값 계산만 최적화하면 됩니다. MTMBuffer[]에 사용한 것과 같은 방법을 사용합니다.

//--- now calculate the indicator values
   if(prev_calculated==0) start=r+s-1; // set the starting index for input arrays
   for(int i=start;i<rates_total;i++)
     {
      TSIBuffer[i]=100*EMA2_MTMBuffer[i]/EMA2_AbsMTMBuffer[i];
     }
//--- return value of prev_calculated for next call
   return(rates_total);

최적화 절차에 대한 마지막 포인트: OnCalculate()는 rates_total의 값을 반환합니다. 이는 price[] 인풋 어레이의 요소 수를 의미하며, 인디케이터 계산에 사용됩니다.

OnCalculate()에 의해 반환된 값은 종점 메모리에 저장되며, 다음 OnCalculate() 호출 시 인풋 패러미터 prev_calculated의 값으로서 함수에 전달됩니다.

이를 통해 OnCalculate()의 이전 호출 시 입력 어레이의 크기를 항상 파악할 수 있으며 불필요한 재계산 없이 올바른 인덱스에서 표시기 버퍼 계산을 시작할 수 있습니다.

인풋 데이터 체크하기

OnCalculate()가 완벽하게 작동하기 위해 우리가 해야 할 일이 한 가지 더 있습니다. 인디케이터 값이 산출되는 price[] 어레이에 대한 체크를 추가해 봅시다. 만약 어레이 사이즈 (rates_total) 이 지나치게 작다면, 계산은 불필요합니다 - 데이터가 충분하다면, 우리는 OnCalculate()의 다음 호출까지 대기하면 될 뿐입니다.

//--- if the size of price[] is too small
  if(rates_total<r+s) return(0); // do not calculate or draw anything
//--- if it's the first call 
   if(prev_calculated==0)
     {
      //--- set zero values for zero indexes
      MTMBuffer[0]=0.0;
      AbsMTMBuffer[0]=0.0;
     }

지수 평활은 두 번 연속해서 참 강도 지수를 계산하는 데 사용되므로 price[]의 크기는 r과 s 기간의 합과 같거나 더 커야 합니다. 그렇지 않으면 실행이 종료되고 OnCalculate()는 0을 반환합니다. 반환된 0 값은 인디케이터의 값이 계산되지 않기 때문에 인디케이터가 차트에 표시되지 않음을 의미합니다.

표현 설정

계산의 정확성에 대해서는 인디케이터를 사용할 준비가 되었습니다. 그러나 다른 mql5 프로그램에서 호출하면 기본적으로 Close price에 의해 빌드됩니다. 다른 기본 가격 타입을 설정할 수 있습니다 - 인디케이터 내 indicator_applied_price 프로퍼티의 ENUM_APPLIED_PRICE 열거 중에서 한가지 값을 고르세요.

예를 들어, 가격을 ((고가+저가+종가)/3)으로 설정하려면 이렇게 쓰면 됩니다:

#property indicator_applied_price PRICE_TYPICAL


iCustom() 또는 IndicatorCreate() 함수 만을 사용하여 해당 값만 사용하려한다면, 더 이상 수정할 필요가 없습니다. 그러나 직접 사용할 경우(즉, 차트에 표시된 경우) 추가 설정이 권장됩니다:

  • 막대 번호, 인디케이터가 표시되는 시작점;
  • DataWindow에 표시될 TSIBuffer[]의 값에 붙일 레이블;
  • 인디케이터 라인 위에 마우스 커서를 놓을 때 별도의 창과 팝업 도움말에 표시된 표시기의 간략한 이름;
  • 인디케이터 값에 보이는 소숫점의 자리 수 (정확도에 영향을 주지는 않음).

이러한 설정은 Custom Indicators 그룹의 기능을 사용하여 OnInit() 핸들러에서 조정할 수 있습니다.. 새 줄을 추가하고 인디케이터를 True_Strength_Index_ver2.mq5라는 이름으로 저장합니다.

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,TSIBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,MTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(2,AbsMTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(3,EMA_MTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(4,EMA2_MTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(5,EMA_AbsMTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(6,EMA2_AbsMTMBuffer,INDICATOR_CALCULATIONS);
//--- bar, starting from which the indicator is drawn
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,r+s-1);
   string shortname;
   StringConcatenate(shortname,"TSI(",r,",",s,")");
//--- set a label do display in DataWindow
   PlotIndexSetString(0,PLOT_LABEL,shortname);   
//--- set a name to show in a separate sub-window or a pop-up help
   IndicatorSetString(INDICATOR_SHORTNAME,shortname);
//--- set accuracy of displaying the indicator values
   IndicatorSetInteger(INDICATOR_DIGITS,2);
//---
   return(0);
  }

두 가지 버전의 인디케이터를 시작하고 차트를 처음부터 끝까지 스크롤하면 모든 차이를 확인할 수 있을겁니다.


두번째 버전의 실제강도지수가 더 보기 좋네요

마치며

실제강도지수 인디케이터 생성 예제를 기반으로 MQL5에서 인디케이터를 쓰는 과정에서의 기본 단계를 간단하게 설명할 수 있습니다.

  • 커스텀 인디케이터를 만들려면 표시기 설정에서 예비 루틴 작업을 수행하는 데 도움이 되는 MQL5 위자드를 사용하십시오. OnCalculate() 기능의 필요한 변형을 선택합니다.
  • 필요한 경우 중간 계산을 위해 배열을 더 추가하고 SetIndexBuffer() 함수를 사용하여 해당 표시기 버퍼로 배열을 바인딩합니다. 이들 버퍼들에 대해 INDICATOR_CALCULATIONS 타입을 표시합니다.
  • OnCalculate()에서 계산을 최적화합니다. 이 함수는 가격 데이터가 변경될 때마다 호출됩니다.. 코드 쓰기를 쉽게 하고 읽기 쉽도록 준비 디버깅 함수를 사용합니다.
  • 다른 mql5 프로그램과 사용자에 의해 프로그램을 쉽게 사용할 수 있도록 표시기의 추가 시각적 조정을 수행합니다.

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

MQL5의 객체 생성 및 파괴 순서 MQL5의 객체 생성 및 파괴 순서
사용자 지정 개체, 동적 배열 또는 개체 배열 등 모든 개체는 특정 방식으로 MQL5 프로그램에서 생성 및 삭제됩니다. 종종 일부 개체는 다른 개체의 일부이며 초기화 해제시 개체 삭제 순서가 특히 중요합니다. 이 글에서는 개체 작업 메커니즘을 다루는 몇 가지 예를 제공합니다.
새로운 기능: MQL5의 커스텀 인디케이터 새로운 기능: MQL5의 커스텀 인디케이터
MetaTrader5와 MQL5의 새로운 기능 전체를 나열하지는 않겠습니다. 종류도 많은 데다가, 별도의 설명이 필요한 기능들도 있거든요. 객체 지향 프로그래밍을 이용한 코드 작성법 또한 다음에 알아보도록 하겠습니다. 다른 기능들과 함께 설명하기에는 조금 어려운 이야기일 수 있으니까요. 이 글에서는 인디케이터와 인디케이터의 구조, 드로잉 타입과 프로그래밍 디테일을 MQL4와 비교해 볼게요. 초보자 분들께 많은 도움이 되면 좋겠고 기존에 사용하시던 개발자 분들도 뭔가 새로운 걸 얻어 가실 수 있길 바랍니다.
초보자를 위한 MQL5 : Expert Adviser의 기술 지표 사용 가이드 초보자를 위한 MQL5 : Expert Adviser의 기술 지표 사용 가이드
Expert Advisor에서 내장 또는 사용자 지정 인디케이터의 값을 얻으려면 먼저 해당 기능을 사용하여 핸들을 만들어야 합니다. 이 글에서의 예는 자신의 프로그램을 만드는 동안 이 또는 해당 기술 지표를 사용하는 방법을 보여줍니다. 이 글에서는 MQL5 언어로 빌드된 인디케이터에 대해 설명합니다. 트레이딩 전략 개발에 대한 경험이 많지 않은 사람들을 위해 제공되는 기능 라이브러리를 사용하여 지표로 작업하는 간단하고 명확한 방법을 제공합니다.
새 MetaTrader 와 MQL5를 소개해드립니다 새 MetaTrader 와 MQL5를 소개해드립니다
본 문서는 MetaTrader5의 간략 리뷰입니다. 짧은 시간 내에 시스템의 모든 세부 사항을 안내해드리기는 어렵습니다 - 테스트는 2009.09.09에 시작되었습니다. 이는 상징적인 일자로, 전 이것이 행운의 숫자가 될거라 믿어 의심치않습니다. 제가 새 MetaTrader 5 터미널과 MQL5 베타버전을 받은지 며칠이 지났습니다. 아직 모든 기능을 사용해본 것은 아니지만, 벌써부터 감명깊네요.