MQL5: Kendi Göstergenizi Oluşturma

MetaQuotes | 9 Aralık, 2021

Giriş

Bir gösterge nedir? Ekranda uygun bir şekilde görüntülenmesini istediğimiz bir dizi hesaplanmış değerdir. Değer setleri programlarda bir dizi olarak gösterilir. Böylelikle, bir göstergenin oluşturulması, bazı dizileri (fiyat dizileri) idare eden ve diğer dizilere (gösterge değerleri) devretmenin sonuçlarını kaydeden bir algoritmanın yazılması anlamına gelir.

Bazıları çoktan klasikleşmiş olan çok sayıda hazır gösterge olsa bile kişinin kendi göstergelerini oluşturma ihtiyacı her zaman var olacaktır. Kendi algoritmalarımızı kullanarak oluşturduğumuz bu tür göstergeler, özel göstergeler olarak bilinir. Bu makalede, basit bir özel göstergenin nasıl oluşturulacağını inceleyeceğiz.

Göstergeler Farklıdır

Bir gösterge renkli çizgiler veya alanlar olarak sunulabilir veya pozisyonun girilmesi için tercih edilen anları gösteren özel etiketler olarak görüntülenebilir. Ayrıca bu türler birleştirilebilir, bu da daha da fazla gösterge türü olmasını sağlar. William Blau tarafından geliştirilmiş iyi bilinen Doğru Güç Endeksi örneğinde bir gösterge oluşturulmasını inceleyeceğiz.

Doğru Güç Endeksi

TSI göstergesi, trendleri ve aşırı satılan/aşırı alınan alanları tanımlamak için çift düzleştirilmiş momentuma dayanır. Bunun matematiksel açıklamasını şurada bulabilirsiniz: Momentum, Yön ve Ayrışma, William Blau. Burada sadece hesaplama formülünü ele alıyoruz.

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

Burada:

Bu formülden, gösterge hesaplamasını etkileyebilecek üç parametreyi alabiliriz. Bunlar r ve s dönemleri ve hesaplamalar için kullanılan fiyat türleridir. Kendi örneğimizde KAPANIŞ fiyatını kullanacağız.

MQL5 Sihirbazı

TSI’yi mavi çizgi olarak görüntüleyelim; burada MQL5 Sihirbazını başlatmamız gereklidir. İlk aşamada oluşturmak istediğimiz program türünü belirtmeliyiz - özel gösterge. İkinci aşamada program adını, r ve s parametrelerini ve bunların değerlerini belirlemeliyiz.

MQL5 Sihirbazı: Gösterge adı ve parametresini belirleme

Ardından göstergenin mavi bir çizgi olarak ayı bir pencerede görüntülenmesini belirleyelim ve bu çizgi için TSI etiketini ayarlayalım.

MQL5 Wizard: gösterge türünü belirleme

İlk veriler girildikten sonra Bitti üzerine basarız ve göstergemizin taslağını ediniriz. 

//+------------------------------------------------------------------+
//|                                          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 Sihirbazı, gösterge başlığını oluşturur ve burada aşağıdaki gösterge özellikleri yazılır:

Tüm hazırlıklar tamam, şimdi kodumuzu geliştirelim ve iyileştirelim.

OnCalculate()

OnCalculate() fonksiyonu, Hesapla olayının işleyicisidir, gösterge değerlerini yeniden hesaplamak ve grafikte yeniden çizmek gerektiğinde ortaya çıkar. Bu yeni bir tik alma, sembol geçmişi güncellemesi vs. olayıdır. Bu yüzden gösterge değerlerinin tüm hesaplamalarının ana kodu, bu fonksiyonda kesin olarak konumlandırılmalıdır.

Elbette yardımcı hesaplamalar diğer ayrı fonksiyonlara uygulanabilir ama bu fonksiyonlar OnCalculate işleyicisinde kullanılmalıdır.

Varsayılan olarak MQL5 Sihirbazı, tüm zaman serisi türlerine erişim sağlayan ikinci OnCalculate() formunu sunar:

Bizim örneğimizde sadece bir veri dizisine ihtiyacımız var, bu yüzden OnCalculate() ilk çağrı formunu değiştirelim.

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);
  }  

Bu, göstergeyi sadece fiyat verisine uygulamamızı sağlamakla kalmaz, aynı zamanda göstergeyi diğer göstergelerin değerlerine göre oluşturmamızı da sağlar.

Özel gösterge hesaplaması için veri türünü belirleme

Parametreler sekmesinde (varsayılan olarak sunuluyorsa) Kapanış öğesini seçersek OnCalculate() öğesine iletilen price[] öğesi, kapanış fiyatlarını içerecektir. Örneğin Tipik Fiyat öğesini seçersek, price[]öğesi her bir dönemin fiyatlarını (Yüksek+Düşük+Kapanış)/3 içerecektir.

rates_total parametresi, price[] dizisinin boyutunu belirtir, bir döngüdeki hesaplamaları düzenlemek için faydalı olacaktır. Price[] içindeki öğelerin indislemesi, sıfırdan başlar ve geçmişten geleceğe doğru yönlendirilir. Yani price[0] öğesi en eski değeri içerir, price[rates_total-1] ise son dizi öğesini içerir.

Yardımcı Gösterge Tamponlarının Düzenlenmesi

Bir grafikte yalnızca bir satır, yani bir gösterge dizisinin verisi gösterilecektir. Ancak bundan önce, ara hesaplamaları düzenlemeliyiz. Ara veriler, INDICATOR_CALCULATIONS özniteliği tarafından işaretlenmiş gösterge dizilerinde saklanır. Formül öğesinde ek dizilere ihtiyacımız olduğunu görürüz:

  1. mtm değerleri için - dizi MTMBuffer[];
  2. |mtm| değerleri için - dizi absMTMBuffer[];
  3. EMA(mtm,r) için - dizi EMA_MTMBuffer[];
  4. EMA(EMA(mtm,r),s) için - dizi EMA2_MTMBuffer[];
  5. EMA(|mtm|,r) için - dizi EMA_AbsMTMBuffer[];
  6. EMA(EMA(|mtm|,r),s) için - dizi EMA2_AbsMTMBuffer[].

Toplamda global düzeyde double tipli 6 dizi daha eklememiz ve bu dizileri, OnInit() fonksiyonunda gösterge tamponlarıyla birlikte bağlamamız gereklidir. Gösterge tamponlarının yeni sayısını belirtmeyi unutmayın; indicator_buffers özelliği 7’ye eşit olmalıdır (1 adet vardı ve 6 tampon daha ekledik).

#property indicator_buffers 7

Şimdi gösterge kodu şöyle görünür:

#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);
  }

Ara Hesaplamalar

MTMBuffer[] ve AbsMTMBuffer[] tamponları için değerlerin hesaplamasını düzenlemek çok kolaydır. Döngüde price[1] ile price[rates_total-1] arasındaki değerlere tek tek bakın ve farkı bir diziye, farkın mutlak değerini de ikinci diziye yazın.

//--- 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]);
     }

Sonraki aşama, bu dizilerin üssel ortalamasının hesaplamasıdır. Bunu yapmanın iki yolu vardır. İlkinde hiç hata yapmamaya çalışarak tüm algoritmayı yazarız. İkinci yöntemde zaten hatası ayıklanmış ve tamamen bu amaca yönelik olan hazır fonksiyonları kullanırız.

MQL5’te hareketli ortalamaları dizi değerleriyle hesaplamak için yerleşik fonksiyonlar yoktur ama MovingAverages.mqh adlı bir hazır fonksiyonlar kitaplığı vardır ve buna terminal_directory/MQL5/Include/MovingAverages.mqh yoluyla erişilebilir, burada terminal_directory, MetaTrader 5 terminalinin kurulu olduğu katalogdur. Kitaplık bir içerik dosyasıdır; dört klasik yöntemden birini kullanarak dizilerde hareketli ortalamaları hesaplamak için fonksiyonlar içerir:

Bu fonksiyonları kullanmak için herhangi bir MQL5 programında kod başlığına aşağıdakileri ekleyin:

#include <MovingAverages.mqh>

Değerler dizisinde üssel hareketli ortalamayı hesaplayan ve ortalamanın değerlerini başka bir diziye kaydeden ExponentialMAOnBuffer() fonksiyonuna ihtiyacımız var.

Bir Dizini Düzleştirme Fonksiyonu

Toplamda MovingAverages.mqh içerik dosyası, her birinde 4 adet olan aynı türde iki fonksiyon grubuna bölünebilen sekiz fonksiyonu içerir. İlk grupta bir diziyi alan ve belirtilen pozisyonda hareketli bir ortalamanın değerini veren fonksiyonlar yer alır:

Bu fonksiyonlar, tek seferde bir dizi için bir ortalamanın değerini elde etmek içindir ve birden fazla çağrı için optimize edilmemiştir. Bu gruptaki bir fonksiyonu bir döngüde kullanmanız gerekirse (bir ortalamanın değerlerini hesaplamak ve hesaplanan her değeri bir diziye yazmak için) optimal bir algoritma düzenlemeniz gerekecektir.

İkinci fonksiyonlar grubu, ilk değerlerin dizisine dayanan bir hareketli ortalamanın değerleriyle alıcı diziyi doldurmak içindir:

Buffer[], price[] dizileri ve dönem ortalama dönemi hariç belirtilen tüm fonksiyonlarda 3 parametre daha bulunur ve bunun amacı, OnCalculate() fonksiyonu - rates_total, prev_calculated ve begin parametreleri ile benzeşir. Bu grubun fonksiyonları, indisleme yönünü (AS_SERIES bayrağı) dikkate alarak price[] ve buffer[] öğelerinin iletilen dizilerini doğru şekilde işler.

Begin parametresi, anlamlı verinin, yani işlenmesi gereken verinin başladığı bir kaynak dizisinin indisini belirtir. MTMBuffer[] dizisi için gerçek veri, MTMBuffer[1]=price[1]-price[0] öğesinden dolayı indis 1 ile başlar. MTMBuffer[0] değeri tanımlanmamıştır, bu yüzden begin=1 olmalıdır.

//--- 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);

Ortalama alırken dönem değeri dikkate alınmalıdır çünkü çıktı dizisinde hesaplanan değerler küçük bir gecikmeyle doldurulur ve bu gecikme, daha büyük ortalama dönemlerinde daha büyüktür. Örneğin period=10 ise bunun sonucundaki dizideki değerler begin+period-1=begin+10-1 ile başlayacaktır. Sonraki buffer[] çağrılarında bu durum dikkate alınmalıdır ve işleme, begin+period-1 indisi ile başlamalıdır.

Böylece ikinci üssel ortalamayı MTMBuffer[] ve AbsMTMBuffer dizilerinden kolayca elde edebiliriz:

//--- 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 değeri şimdi r’ye eşittir çünkü begin=1+r-1 şeklindedir (r, birincil üssel ortalamanın dönemidir, işleme indis 1 ile başlar). EMA2_MTMBuffer[] ve EMA2_AbsMTMBuffer[] çıktı dizilerinde hesaplanan değerler r+s-1 indisi ile başlar çünkü girdi dizilerini r indisi ile işlemeye başladık ve ikincil üssel ortalama dönemi s’ye eşittir.

Ön hesaplamaların hepsi hazır olduğuna göre şimdi grafikte çizilecek olan TSIBuffer[] gösterge tamponunun değerlerini hesaplayabiliriz.

//--- 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 tuşuna basarak kodu tamamlayın ve MetaTrader 5 terminalinde başlatın. İşe yarıyor!

Doğru Güç Endeksinin ilk versiyonu

Hala sorulacak sorular var.

Hesaplamaların Optimize Edilmesi

Aslında çalışma göstergesi yazmak için bu kadarı yeterli değil. OnCalculate() öğesinin mevcut uygulamasına dikkatli bakarsak bunun optimal olmadığını görürüz.

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);
  }

Her fonksiyonun başlangıcında MTMBuffer[] ve AbsMTMBuffer[] dizilerindeki değerleri hesaplarız. Bu durumda price[] öğesinin boyutu yüz binlerce veya hatta milyonlarca değere eşitse gereksiz tekrarlanan hesaplamalar, ne kadar güçlü olursa olsun tüm CPU kaynaklarını tüketebilir.

Optimal hesaplamaları düzenlemek için önceki çağrıda OnCalculate() tarafından verilen değere eşit olan prev_calculated giriş parametresini kullanırız. Fonksiyonun ilk çağrısında prev_calculated değeri her zaman 0’a eşittir. Bu durumda gösterge tamponundaki tüm değerleri hesaplarız. Sonraki çağrıda tüm tamponu hesaplamamız gerekmez, sadece son değer hesaplanacaktır. Şöyle yazalım:

//--- 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[] ve EMA2_AbsMTMBuffer[] hesaplama blokları, hesaplamaların optimizasyonunu gerektirmez çünkü ExponentialMAOnBuffer() zaten optimal şekilde yazılmıştır. Yalnızca TSIBuffer[] dizisinin değerlerinin hesaplamasını optimize etmemiz gereklidir. MTMBuffer[] için kullanılan yöntemin aynısını kullanırız.

//--- 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);

Optimizasyon prosedürünün son bilgisi: OnCalculate(), rates_total değerini verir. Bu, gösterge hesaplamaları için kullanılan price[] girdi dizisindeki öğelerin sayısı anlamına gelir.

OnCalculate() tarafından verilen değer terminal belleğe kaydedilir ve sonraki OnCalculate() çağrısında prev_calculated giriş parametresinin değeri olarak fonksiyona iletilir.

Bu, OnCalculate() öğesinin önceki çağrısındaki girdi dizisinin boyutunun her zaman bilinmesini ve gösterge tamponlarının hesaplamasının, gereksiz yeniden hesaplamalar olmadan doğru bir indisten yapılmasını sağlar.

Girdi Verisinin Kontrol Edilmesi

OnCalculate() öğesinin doğru çalışması için yapmamız gereken bir şey daha var. Gösterge değerlerinin hesaplandığı price[] dizisinin kontrolünü ekleyelim. Dizinin boyutu (rates_total) çok küçükse hesaplama gerekmez, yeterli veri olduğunda bir sonraki OnCalculate() çağrısını beklememiz gerekir.

//--- 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;
     }

Doğru Güç Endeksini hesaplamak için üssel düzleştirme sırayla iki defa kullanıldığı için price[] boyutu en az r ve s dönemlerinin toplamına eşit veya bundan büyük olmalıdır; aksi takdirde yürütme sonlandırılır ve OnCalculate(), 0 değerini verir. Verilen sıfır değeri, göstergenin grafikte çizilmeyeceği anlamına gelir çünkü değerler hesaplanmamıştır.

Temsilin Ayarlanması

Hesaplamaların doğruluğu açısından gösterge kullanıma hazırdır. Ancak onu başka bir mql5 programından çağırırsak varsayılan olarak Kapanış fiyatları tarafından oluşturulacaktır. Başka bir varsayılan fiyat türü belirtebiliriz: Göstergenin indicator_applied_price özelliğinde ENUM_APPLIED_PRICE numaralandırmasından bir değer belirtin. 

Örneğin, bir fiyat için tipik bir fiyat ayarlamak amacıyla ( (yüksek+düşük+kapanış)/3) aşağıdakileri yazalım:

#property indicator_applied_price PRICE_TYPICAL


iCustom() veya IndicatorCreate() fonksiyonlarını kullanarak sadece değerlerini kullanmayı planlıyorsak daha fazla geliştirmeye gerek yoktur. Ancak doğrudan kullanılırsa, yani grafikte çizilirse ek ayarlar önerilir:

Bu ayarlar Özel Göstergeler grubundaki fonksiyonlar kullanılarak OnInit() işleyicisinde ayarlanabilir. Yeni çizgiler ekleyin ve göstergeyi True_Strength_Index_ver2.mq5 olarak kaydedin.

//+------------------------------------------------------------------+
//| 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);
  }

Göstergenin her iki versiyonunu da başlatırsak ve grafiği başlangıca getirirsek tüm farkları göreceğiz.


Doğru Güç Endeksi göstergesinin ikinci versiyonu daha iyi görünüyor

Sonuç

Doğru Güç Endeksi göstergesinin oluşturulması örneğine dayanarak MQL5’te herhangi bir göstergeyi yazma sürecindeki temel anları özetleyebiliriz: