English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
Ek Arabellekler Kullanmadan Ara Hesaplamalar için Fiyat Serilerinin Ortalamasını Alma

Ek Arabellekler Kullanmadan Ara Hesaplamalar için Fiyat Serilerinin Ortalamasını Alma

MetaTrader 5Göstergeler | 15 Aralık 2021, 11:09
94 0
Nikolay Kositsin
Nikolay Kositsin

Giriş

"Göstergelerin Ekonomik Hesaplanmasına İlişkin Prensipler" başlıklı makalemde, bir koddaki özel veya teknik göstergenin her bir çağrısının gelişmiş bir göstergede ara hesaplamalar yapmanın en uygun yolu olmadığını kanıtlayan makul derecede ikna edici test yaptım.

Ara hesaplamalar için kodu doğrudan göstergemize yerleştirseydik, son yürütme hızı sahip olacağımızla karşılaştırıldığında çok daha düşük görünebilirdi.

Yeterince basit olsaydı, kod yazmaya bu tür bir yaklaşım çok çekici olurdu. Aslında, bu, ara hesaplama sonuçlarını saklamak için kullanılan ek arabellekleri tanımlayan bir kodun ciddi bir karmaşıklığı gibi görünmektedir.

Ara hesaplamaların çeşitliliğine rağmen, en çok ihtiyaç duyulan farklı ortalama alma algoritmalarıdır. Çoğu durumda, onlar için böyle bir kod yazma görevini önemli ölçüde basitleştiren basit ve evrensel özel işlevleri kullanabiliriz. Bu makalede, bu işlevleri oluşturma ve onlarla çalışma süreci anlatılacaktır.


1. Bir Çubukla Çalışan Ortalama Alma İşlevlerinin Genel Fikri

Mevcut bir çubukta ortalama almaya yönelik klasik yaklaşım, gerekli bilgilerle doldurduğumuz ve ardından ortalama alma süresine eşit olan bir önceki değer aralığını seçip ortalama değeri hesapladığımız bir ara gösterge arabelleğine dayalıdır.

Bu seçimi işleme prosedürü aşağıdaki gibi görünür:

SmoothVar(çubuk) = İşlev(Var(çubuk - (n-1)), Var(çubuk - (n-2)), ......... Var(çubuk)) 

Burada:

  • SmoothVar(çubuk) — ortalaması alınan parametre,
  • çubuk - hesaplamanın yapıldığı çubuk sayısı,
  • Var(çubuk - (n-1)) — (n-1) çubuklarında kayma ile ortalaması alınan parametreler,
  • n - ortalama alma için çubuk sayısı.

Bizim durumumuzda, ortalama almaya böyle bir yaklaşım, iki hesaplama döngüsünün ortaya çıkmasına yol açar. İlk döngüde, veriler hesaplanır ve bir ara belleğe yerleştirilir. İkinci döngüde, gösterge arabelleği hücrelerinin ek aramasına ait başka bir döngü kullanılarak ortalama alma, yukarıda önerilen formül temelinde gerçekleştirilir. Ara veri seçimini işlevin kendi içinde toplarsak bu hesaplama çok daha kolay görünecektir. Bu durumda, ortalama alma işlevi aşağıdaki gibi görünecektir:

SmoothVar(çubuk) = İşlev(Var(çubuk), çubuk)

Mevcut bir çubuk üzerinde işlev içindeki değerlerin seçimine yeni bir Var(çubuk) değeri yazılır ve gereksiz hale gelen Var(çubuk - n) değerleri seçimden silinir. Bu yaklaşımla, bir ortalama alma kodu oldukça önemsiz görünür ve ek gösterge arabellekleri gerektirmez. İşlevin içinde, dizi, tüm geçmiş verilerini değil, bir çubuğun hesaplanması için gereken tam miktarda veriyi saklar.

Bu durumda, ayrıca yalnızca bir veri hesaplama döngüsü vardır. Mevcut bir çubukta ortalama alma işlevini çağırmak için ilk olarak tüm önceki çubuklarda onu çağırmanız gerektiğine dikkat etmelisiniz!


2. Tek Çubukla Çalışan Bir İşlevi Uygulama Örneği Olarak Klasik Ortalama Alma

Bu tür ortalama alma işlevleri, bu işlevlerin çağrıları arasında değerlerini kaybetmemesi gereken değişkenler içermelidir. Ayrıca, farklı parametrelere sahip tek tür ortalama, bir kodda birçok kez kullanılabilir; bu nedenle, paylaşılan bellek kaynaklarını kullanma çakışmasını önlemek için bu işlevleri sınıflar olarak uygulamalıyız, ben de tam olarak bunu yaptım.

Klasik ortalama alma algoritmaları CMoving_Average sınıfında açıklanmıştır:

class CMoving_Average : public CMovSeriesTools
  {
public:  
   double    MASeries  (uint begin,               // Index of start of reliable bars
                       uint prev_calculated,      // Amount of history in bars at a previous tick
                       uint rates_total,          // Amount of history in bars at a current tick
                       int Length,               // Period of averaging
                       ENUM_MA_METHOD MA_Method, // Method of averaging (MODE_SMA, MODE_EMA, MODE_SMMA, MODE_LWMA)
                       double series,              // Value of price series calculated for the bar with the 'bar' number
                       uint bar,                   // Bar index
                       bool set                  // Direction of indexing of arrays.
                      );

   double    SMASeries (uint begin,          // Index of start of reliable bars
                       uint prev_calculated,// Amount of history in bars at a previous tick
                       uint rates_total,     // Amount of history in bars at a current tick
                       int Length,            // Period of averaging
                       double series,         // Value of price series calculated for the bar with the 'bar' number
                       uint bar,              // Bar index
                       bool set              // Direction of indexing of arrays.
                      );
                        
   double    EMASeries (uint begin,            // Index of start of reliable bars
                       uint prev_calculated, // Amount of history in bars at a previous tick
                       uint rates_total,     // Amount of history in bars at a current tick
                       double Length,         // Period of averaging
                       double series,        // Value of price series calculated for the bar with the 'bar' number
                       uint bar,              // Bar index
                       bool set              // Direction of indexing of arrays.
                      );
                        
   double    SMMASeries(uint begin,              // Index of start of reliable bars
                         uint prev_calculated, // Amount of history in bars at a previous tick
                         uint rates_total,     // Amount of history in bars at a current tick
                         int Length,            // Period of averaging
                         double series,         // Value of price series calculated for the bar with the 'bar' number
                         uint bar,              // Bar index
                         bool set              // Direction of indexing of arrays.
                      );

   double    LWMASeries(uint begin,               // Index of start of reliable bars
                         uint prev_calculated, // Amount of history in bars at a previous tick
                         uint rates_total,      // Amount of history in bars at a current tick
                         int Length,             // Period of averaging
                         double series,          // Value of price series calculated the bar with the 'bar' number
                         uint bar,               // Bar index
                         bool set               // Direction of indexing of arrays.
                        );

protected:
   double            m_SeriesArray[];
   int               m_Size_, m_count, m_weight;
   double            m_Moving, m_MOVING, m_Pr;
   double            m_sum, m_SUM, m_lsum, m_LSUM;
  };

Bu sınıf, ek korumalı işlevler-yöntemler ve hareketli ortalamaların döneminin doğruluk kontrolünü içeren temel sınıf olan CMovSeriesTools sınıfından türetilmiştir.

Temel sınıf, önerdiğim tüm sınıflarda kullanılan ek bir evrensel kod içerir ve bunu türetilmiş sınıflara defalarca kopyalamanın bir anlamı yoktur. Ortalama alma kullanımını içeren uygulamalı görevlerde, korumalı sınıf üyeleri açık biçimde kullanılmaz; bu nedenle şimdilik onların genel açıklamasını askıya alalım.

CMoving_Average sınıfı adları kendileri için konuşan ve ayrıntılı olarak açıklanmaları gerekmeyen beş tek tür ortalama alma işlevinden oluşur.

Birinci işlev MASeries() , MA_Method parametresini kullanarak bir ortalama alma algoritması seçmeye olanak tanıyan diğer dört işlevin tamamlayıcı bir koleksiyonudur. Ortalama alma algoritmalarının kodu maksimum performans için optimize edilmiştir ve işlevlerin ana parametrelerinin (Uzunluk, seri, çubuk) işlevi aynı adlara sahip gösterge değişkenleriyle tamamen aynı olan begin, prev_calculated, rates_total ve set ek parametreleriyle desteklenmesinin nedeni budur.

'set' parametresi ortalama alma işlevlerinde bir fiyat serisinin 'series' öğelerinin indeksleme bayrağını değişken dizileri ile aynı olacak şekilde ayarlar.

Bu sınıfın tüm ortalama alma işlevlerinin sabit Uzunluk parametresi içerdiğini ve program kodu yürütülürken değiştirilemeyeceğini göz önünde bulundurmalıyız! CMoving_Average sınıfının EMASeries() işlevi, çift türündeki bu parametreyi içerir!

Artık CMoving_Average sınıfını tanıdığımıza göre, onu göstergelerde kullanmaya başlayabiliriz. Bunu yapmak için, #include yönergesini kullanarak genel kapsamdaki MASeries_Cls.mqh dosyasının içeriğini geliştirdiğiniz gösterge koduna ekleyin:

#include <MASeries_Cls.mqh> 

Bunun ardından, gösterge kodunda gerekli ortalama alma prosedürlerini belirlemelisiniz ve daha sonra OnCalculate() bölümünde (döngü işleçlerinden ve küme ayraçlarından önce) gerekli ortalama alma prosedürü sayısına göre CMoving_Average sınıfının statik değişkenlerini bildirmelisiniz. Her ortalama alma prosedürü için sınıfın ayrı bir değişkeni ve sınıf dizisinde ayrı bir hücre olmalıdır.

//---- declaration of variables of the class CMoving_Average из файла MASeries_Cls.mqh
static CMoving_Average MA1, MA2, MA3, MA4;

OnCalculate() işlevindeki sınıfın değişkenleri, statik olarak bildirilir; zira değerlerinin bu işlevin çağrıları arasında tutulması gerekir. Artık kendi ortalamasını alarak çalışmaya başlayabiliriz. Örnek olarak, fiyat serilerinin ortalamalarının alınmasına ilişkin dört ardışık prosedürü göstereceğim - SMA/EMA/SMMA/LWMA (MAx4.mq5 göstergesi):

//---- The main cycle of indicator calculation 
for(bar = first; bar < rates_total; bar++) 
 {
  //----+ Four calls of the function MASeries.  
  ma1_ = MA1.MASeries(start1, prev_calculated, rates_total, Length1, MODE_SMA,  price[bar], bar, false);
  ma2_ = MA2.MASeries(start2, prev_calculated, rates_total, Length2, MODE_EMA,  ma1_,       bar, false);
  ma3_ = MA3.MASeries(start3, prev_calculated, rates_total, Length3, MODE_SMMA, ma2_,       bar, false);
  ma4_ = MA4.MASeries(start4, prev_calculated, rates_total, Length4, MODE_LWMA, ma3_,       bar, false);
  //----       
  MAx4[bar] = ma4_ + dPriceShift;
 }

Her bir önceki ortalama alma işleminin sonucu (sonuncusu hariç), bir sonraki ortalama alma algoritmasında kullanılır ve nihai sonuç gösterge arabelleğine iletilir.

Bence bu kodun en can alıcı kısmı, güvenilir çubukların başlangıcını gösteren indeks değişkenlerinin çok dikkatli bir şekilde ön başlatmasıdır. Bu, aşağıdaki gibi görünecektir:

//---- Initialization of variables of start of reliable information
start1 = 0 + begin;
start2 = Length1 + begin;
start3 = Length1 + begin; // the previous EMA averaging doesn't change the start of reliable information
start4 = Length1 + Length3 + begin;

Bu durumda, LWMA ortalama alma algoritmasının sonuncusu olduğunu ve hiçbir şeyi etkilemediğini unutmayın ama sonuncusu olmasaydı, o zaman güvenilir bilginin başlangıç kayması Uzunluk4'e değil Uzunluk4+1'e eşit olurdu!

Güvenilir bilginin hangi sayıdan başladığı önceki koddan net değilse, daha büyük bir sayı alın ve gerekirse deneysel olarak azaltın.


3. Sınıflar Kullanılarak Oluşturulan Göstergeyi Teknik ve Özel Göstergeler Kullanan Analogları ile Karşılaştırma

Oluşturulan MAx4.mq5 göstergesinin performansını, iMA() teknik göstergesini kullanan aynı analogu (iMAx4.mq5) ile karşılaştırmak çok ilginç olurdu.

Testi gerçekleştirmeye karar verir vermez, MAx4.mq5'e benzer başka bir göstergeyi (MAx3x1.mq5) test etmek makul olacaktır, ancak ilk ortalamanın teknik gösterge iMA() çağrısı kullanılarak yapılır ve diğer üçü CMoving_Average sınıfını kullanır. Ve istemci terminalinin standart gösterge kümesi, Özel Hareketli Ortalama.mq5 göstergesini içerir içermez, test amacıyla (cMAx4.mq5) temellerinde başka bir benzer gösterge yaptım.

Expert Advisor'ları test etmek için hazırladığım bir sonraki analiz için: Sırasıyla MAx4_Test.mq5, iMAx4_Test.mq5, MAx3x1_Test.mq5 ve cMAx4_Test.mq5. Bu tür testlerin gerçekleştirilme koşulları "Göstergelerin Ekonomik Hesaplanmasına İlişkin Prensipler" makalesinde ayrıntılı olarak açıklanmıştır. Bu makalede, testin ayrıntılarına değinmeyeceğim, ancak son 12 ay boyunca strateji test cihazında dört Expert Advisor'ın çalıştırılmasının nihai sonuçlarını her tick'in modellemesiyle ve 500'e eşit olan tüm EA'ların 'dönem' giriş parametrelerinin değerinin EURUSD Н4 üzerinde göstereceğim.

Şek.1 Göstergeleri test etme sonucu 

Testlerimizdeki en kötü sonuçlar, özel göstergeleri çağıran gösterge tarafından gösterilir; bu nedenle, kod yazmanın bu çeşidi yalnızca tembel kişilere tavsiye edilebilir! Elbette ki, sondan gelen ancak teknik göstergelerin çağrılarına dayanan bir "lider" çok daha iyi sonuçlar veriyor, ancak bir idealden çok uzaklar.

Testlerin gerçek lideri, sınıflar kullanılarak geliştirilen göstergedir!

Sınıfları ve teknik göstergeleri kullanan karma ikinci sırayı aldı, ancak bu her zaman olmuyor; bir göstergenin test zamanı çok önemliyse, bu tür değişkenleri her durum için kişisel olarak kontrol etmek daha iyidir.

Uygulanan Ortalama Alma Sınıflarına Genel Bakış

№  Algoritma Sınıf Adı Dosya Adı Algoritma Uyguladıktan Sonra
Güvenilir Çubukların Başlangıç Kayması
Parametre Uzunluğunun
Dinamik Değişim Olasılığı
   1  Klasik Ortalama Alma  CMoving_Average  MASeries_Cls.mqh Uzunluk/0/Uzunluk/Uzunluk + 1 (SMA/EMA/SMMA/LWMA) hayır
   2  Standart Sapma   CStdDeviation  StdDevSeries_Cls.mqh Uzunluk hayır
   3  JMA Yumuşatma  CJJMA  JJMASeries_Cls.mqh 30 evet
   4  T3 Yumuşatma  CT3  T3Series_Cls.mqh 0 evet
   5  Ultralineer Yumuşatma  CJurX  JurXSeries_Cls.mqh 0 evet
   6  Tushar Chande Yumuşatması   CCMO  CMOSeries_Cls.mqh Uzunluk + 1 hayır
   7  Kaufman Yumuşatması  CAMA  AMASeries_Cls.mqh Uzunluk + 3 hayır
   8  Parabolik Ortalama Alma  CParMA  ParMASeries_Cls.mqh Uzunluk hayır
   9  Değişim Hızı  CMomentum  MomSeries_Cls.mqh                                             Uzunluk + 1                               hayır
  10  Normalize Edilmiş Değişim Hızı  CnMomentum  nMomSeries_Cls.mqh                                             Uzunluk + 1                               hayır
  11  Değişim Oranı  CROC  ROCSeries_Cls.mqh                                             Uzunluk + 1                               hayır

Daha önce açıklanan CMoving_Average sınıfı, beş ortalama alma algoritması içerir.

CCMO sınıfı, ortalama alma ve osilatör algoritmalarını içerir.

Diğer sınıflar, tekli ortalama alma algoritmalarını içerir. Önerilen sınıflardan herhangi birini kullanma ideolojisi, yukarıda açıklanan CMoving_Average sınıfını kullanma prosedürüyle kesinlikle aynıdır. Tüm ortalama alma algoritmalarının kodu (parabolik olan hariç), maksimum yürütme hızı için optimize edilmiştir. Bu sürecin karmaşıklığı nedeniyle parabolik ortalama alma kodu optimize edilmemiştir. Son üç algoritma bir ortalama alma işlemini temsil etmez. Bunları yüksek popülerlikleri ve popüler teknik analistlerin çalışmalarıyla uyumlulukları nedeniyle ekledim.

Bilgileri daha kolay anlamak için, ortalama alma algoritmalarını ayrı .mqh dosyalarında temsil etmek daha iyidir ve pratik kullanım için en iyi seçenek, bunları tek bir dosyada bulundurmaktır.

Göstergelerde kullanmak için, önerilen tüm sınıflar tek bir SmoothAlgorithms.mqh dosyasına toplanır. Buna ek olarak, dosya iPriceSeries.mqh dosyasının işlevleriyle desteklenir. Bu makaledeki örneklerde yalnızca PriceSeries() işlevi kullanılmıştır:

double PriceSeries
 (
  uint applied_price,  // Price constant
  uint   bar,          // Index of shift for a specified number of periods back or forward
                          // relatively to a current bar.
  const double& Open [],
  const double& Low  [],
  const double& High [],
  const double& Close[]
 )

Bu işlev, OnCalculate() işlevinin ikinci çağrı türünün kullanımına dayalı göstergelerle çalışacak şekilde tasarlanmıştır.

Bu işlevi oluşturmanın ana fikri, ENUM_APPLIED_PRICE numaralandırmasının fiyat zaman serisi kümesini özel değişkenlerle genişletmektir. İşlev, 1 ila 11 aralığında değişen sayısına göre bir fiyat zaman serisinin değerini döndürür.


4. Ortalama Alma Sınıflarını Kullanarak Bir Program Kodunun Uygulanmasına İlişkin Pratik Örnekler

Diğer sınıfları kullanmanın başka bir örneğini göstermek yeterliyse her şeyin dörtlü ortalama ile aynı şekilde yapıldığından emin olmak gerekir. CJJMA ve CJurX (JCCX.mq5) sınıflarını kullanarak CCI göstergesinin bir analogunda OnCalculate() işlevinin uygulamasının bir varyantını göstereceğim.

int OnCalculate(const int rates_total,       // amount of history in bars on a current tick
              const int prev_calculated,   // amount of history in bars on a previous tick
              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[]
             )
  {
//----+   
   //---- Checking whether there are enough bars for calculation
   if (rates_total < 0) return(0);
    
   //---- Declaration of variables  with floating point  
   double price_, jma, up_cci, dn_cci, up_jccx, dn_jccx, jccx;
   //----+ Declaration of integer variables
   int first, bar;
   
   //---- calculation of start number 'first' for the cycle of recalculation of bars
   if (prev_calculated == 0) // checking for the first start of calculation of indicator
        first = 0;           // starting number for calculation of all bars
   else first = prev_calculated - 1; // starting number for calculation of new bars
   
   //---- declaration of variables of the class CJurX from the file SmoothAlgorithms.mqh
   static CJurX Jur1, Jur2;
   //---- declaration of variables of the class CJMA from the file SmoothAlgorithms.mqh
   static CJJMA JMA;
   
   //---- Main cycle of calculation of the indicator
   for(bar = first; bar < rates_total; bar++)
    {
     //----+ Calling the PriceSeries function to get the input price price_
     price_ = PriceSeries(IPC, bar, open, low, high, close); 

     //----+ One call of the JJMASeries function to get JMA
     jma = JMA.JJMASeries(0, prev_calculated, rates_total, 0, JMAPhase, JMALength, price_, bar, false); 

     //----+ Determine the deviation of price from the value of JMA
     up_cci = price_ - jma;         
     dn_cci = MathAbs(up_cci);

     //----+ Two calls of the JurXSeries function.  
     up_jccx = Jur1.JurXSeries(30, prev_calculated, rates_total, 0, JurXLength, up_cci, bar, false);
     dn_jccx = Jur2.JurXSeries(30, prev_calculated, rates_total, 0, JurXLength, dn_cci, bar, false); 

     //---- Preventing zero divide in empty values
     if (dn_jccx == 0) jccx = EMPTY_VALUE;
     else
      {
       jccx = up_jccx / dn_jccx;
       
       //---- Limitation of the indicator from the top and from the bottom
       if (jccx > +1)jccx = +1;
       if (jccx < -1)jccx = -1;
      }

     //---- Loading the obtained value to the indicator buffer
     JCCX[bar] = jccx;
    }
//----+     
   return(rates_total);
  }

Şek.2 JCCX göstergesi 

Ancak bu kez genel kapsamdaki başka bir dosyadan uygun sınıfları gösterge koduna ekledim:

#include <SmoothAlgorithms.mqh>

Şimdi dikkatinizi başka bir noktaya çekmek istiyorum. Mesele şu ki, çok sayıda gösterge, sınıfları kullanarak çalışmak için gerçekten rahat olan bir çubuğun işlevleri olarak temsil edilebilir.

Örneğin, Bollinger kanalını Tushar Chande'nin hareketli ortalaması Vidya temelinde çizmek ilginç olurdu. Bu durumda, iki sınıf CCMO ve CStdDeviation kullanılır. Birinci sınıfı kullanarak, hareketli ortalama VIDYA'nın değerini elde ederiz; ikincisini kullanarak, hareketli ortalama için fiyat serisinin standart sapma değerini hesaplıyoruz.

Bunun ardından, bu sapmayı kanalın üst ve alt sınırının hesaplanması için kullanırız:

//+------------------------------------------------------------------+
// Description of the classes CStdDeviation{}; and CCMO{};           | 
//+------------------------------------------------------------------+ 
#include <SmoothAlgorithms.mqh> 
//+==================================================================+
//|  The algorithm of getting the Bollinger channel from             |
//|  the moving average VIDYA                                        |
//+==================================================================+
class CVidyaBands
{
public:
  double VidyaBandsSeries(uint begin,                // number of the start of reliable calculation of bars
                         uint prev_calculated,      // amount of history on a previous tick in bars
                         uint rates_total,          // amount of history on a current tick in bars
                         int CMO_period,            // the period of averaging of the oscillator CMO
                         double EMA_period,         // the period of averaging of EMA
                         ENUM_MA_METHOD MA_Method, // the type of averaging
                         int BBLength,             // the period of averaging of the Bollinger channel
                         double deviation,          // Deviation
                         double series,             // Value of the price series calculated for a bar with the number 'bar'
                         uint bar,                  // Bar index
                         bool set,                  // Direction of indexing of arrays
                         double& DnMovSeries,       // Value of the lower border of the channel for a current bar
                         double& MovSeries,         // Value of the middle line of the channel for a current bar
                         double& UpMovSeries        // Value of the upper border of the channel for a current bar 
                        ) 
   {
//----+
    //----+ Calculation of the middle line    
    MovSeries = m_VIDYA.VIDYASeries(begin, prev_calculated, rates_total, 
                                    CMO_period, EMA_period, series, bar, set); 
    //----+ Calculation of the Bollinger channel
    double StdDev = m_STD.StdDevSeries(begin+CMO_period+1, prev_calculated, rates_total, 
                                      BBLength, deviation, series, MovSeries, bar, set);
    DnMovSeries = MovSeries - StdDev;
    UpMovSeries = MovSeries + StdDev;
//----+
    return(StdDev); 
   }

  protected:
    //---- declaration of variables of the classes CCMO and CStdDeviation
    CCMO           m_VIDYA;
    CStdDeviation  m_STD;
};

Yani, basit ve küçük bir sınıf elde ettik!

VidyaBandsSeries() işlevinin son üç giriş parametresi, kanalın gerekli değerlerini bir bağlantı üzerinden iletir.

Bu durumda sınıfların değişkenlerini VidyaBandsSeries() işlevi içerisinde tanımlayıp statik hale getiremeyeceğinizi bildirmek isterim; zira sınıflardaki statik değişkenler çok farklı anlamlara sahiptir. Bu nedenle, sınıfın genel kapsamına ilişkin bu bildirim yapılmalıdır:

protected: 
  //---- declaration of variables of the classes CCMO and CStdDeviation 
  CCMO           m_VIDYA; 
  CStdDeviation  m_STD;

Normal bir Bollinger kanalında, hareketli ortalamanın ortalama alma dönemi ile kanalın kendisinin ortalama alma dönemi her zaman eşittir.

Bu sınıfta, size daha fazla özgürlük tanımak için bu parametreleri ayrı yaptım (EMA_period ve BBLength). Bu sınıf temelinde yapılan göstergenin kendisi (VidyaBBands.mq5) CVidyaBands sınıfının kullanımında o kadar basittir ki, makaledeki kodunu analiz etmemize gerek yoktur.

Bu tür gösterge işlevlerinin sınıfları ayrı bir mqh dosyasına yerleştirilmelidir. Bu tür işlevleri IndicatorsAlgorithms.mqh dosyasına yerleştirdim.

Şek.3 VidyaBBands göstergesi 


5. Sınıfları Kullanan Bir Göstergenin Performansını Sınıfları Kullanmayan Bir Göstergeyle Karşılaştırma 

Öncelikle, bir göstergenin kodunu yazarken sınıfların kullanılmasının performansını nasıl düşürdüğünü öğrenmek istiyorum.

Bu amaçla, JJMA.mq5 göstergesinin kodu (JMA.mq5) sınıfları kullanılmadan yazılmış, daha sonra önceki testte olduğu gibi aynı koşullarda test edilmiştir. Testlerin nihai sonuçlarında büyük bir fark yoktur:

Şek.4 JMA ve JJMA göstergelerinin test sonuçları 

Tabii ki, sınıfları kullanmanın bazı ek ücretleri var, ancak sağladıkları avantajlarla karşılaştırıldığında önemli değil. 


6. Ortalama Alma Sınıflarını Kullanmanın Avantajları

Gerçekten ikna edici olan bu algoritmaları kullanmanın bir avantajı, teknik ve özel göstergelerin çağrılarının değiştirilmesinin, yukarıda açıklanan geliştirilmiş kodun performansında büyük bir artışa yol açmasıdır.

Bu tür sınıfların bir başka pratik avantajı, onları kullanmanın büyük bir kolaylık sağlamasıdır. Örneğin, William Blau'nun "Momentum, Direction and Divergence" adlı popüler kitabında açıklanan her şey, gösterge yazmaya yönelik bu tür bir yaklaşım için gerçek bir test alanı gibi görünüyor. Göstergelerin kodu, maksimum düzeyde sıkıştırılmış, anlaşılabilir ve genellikle çubukların tek bir yeniden hesaplama döngüsünden oluşur.

Alternatif ortalama alma yöntemlerini kullanarak klasik veya teknik herhangi bir göstergeyi kolayca geliştirebilirsiniz. Ortalama alma algoritmalarının çok çeşitli olması, genellikle trendlerin erken tespiti ve daha az sayıda yanlış tetikleme ile geleneksel olmayan alım satım sistemleri oluşturmak için büyük olanaklar sağlar.


7. Ortalama Alma Algoritmalarını Belirli Bir Gösterge Kodunda Kullanmaya İlişkin Bazı Öneriler

Burada açıklanan farklı ortalama alma algoritmaları kullanılarak geliştirilen herhangi bir göstergeye tek bir hızlı bakış, bu algoritmaların ne kadar farklı olduğunu anlamak için yeterlidir.

 

 Şek. 5 Farklı ortalama alma algoritmaları kullanan hareketli ortalamalar

Bu nedenle, önerilen algoritmaların tümünün her durumda eşit düzeyde iyi olmadığını varsaymak mantıklı olacaktır. Bir veya başka bir algoritmanın kullanımı için kesin bir sınır belirlemek zor olsa da, bunları kullanma konusunda size bazı genel önerilerde bulunmak mümkündür.

Örneğin, Tushar Chande ve Kaufman'ın algoritmaları, trend durumlarını belirlemeye yöneliktir ve gürültü filtreleme amacıyla ek yumuşatma için uygun değildir. Bu nedenle, bu algoritmalara işlenmemiş fiyat serilerini veya gösterge değerlerini ortalama almadan girmek daha iyidir. Kaufman algoritması kullanılarak Momentum göstergesi değerlerinin işlenmesinin sonucu (4c_Momentum_AMA.mq5 göstergesi) şu şekildedir:

Şek.6 Kaufman Algoritması kullanılarak Momentum göstergesinin değerlerinin işlenmesinin sonucu 

Klasik ortalama alma algoritmaları için herhangi bir özel tavsiyenin gerekli olduğunu düşünmüyorum. Uygulama alanları oldukça geniştir. Bu algoritmaların kullanıldığı her yerde soldaki dört algoritmayı (JMA, T3, ultralineer ve parabolik) başarıyla kullanabilirsiniz. EMA ve SMA'nın JMA ortalaması ile değiştirildiği MACD göstergesine bir örnek (JMACD.mq5 göstergesi):

 Şek.7 JMA ortalamasını kullanan MACD grafiği

Ve mevcut eğilimi daha iyi kalitede belirlemek için ortalama alma algoritmasını değiştirmek yerine hesaplanan göstergenin yumuşatılmasının sonucu şu şekildedir (JMomentum.mq5 göstergesi):

Şek.8 Momentum göstergesinin JMA yumuşatmasının sonucu

Piyasaların davranışlarının sürekli değişmesi sürpriz değil; bu nedenle, finansal piyasanın belirli bir bölümü için tek ideal algoritmayı şimdi ve sonsuza kadar bulabileceğinizi düşünmek saflık olur! Ne yazık! Bu dünyada hiçbir şey sonsuza kadar sürmez! Yine de, örneğin, bu sürekli değişen piyasada, JFATL.mq5 ve J2JMA.mq5 gibi hızlı ve orta vadeli trendlerin göstergelerini sıklıkla kullanıyorum. Onlara dayalı tahminlerden oldukça memnunum.

Eklemek istediğim başka bir husus daha var. Ortalama alma algoritmaları yeniden kullanılabilir. Halihazırda ortalaması alınmış değerlere tekrarlanan ortalama alma uygularken iyi sonuçlar elde edilebilir. Aslına bakılırsa, bu makalede ondan gösterge çizme sürecini analiz etmeye başladım (MAx4.mq5 göstergesi).


8. Ortalama Alma Algoritmalarının Kodunu Oluşturma Genel Fikri

Ve şimdi, makalenin sonunda, kendi kendilerine ortalama alma işlevlerinin mekanizmasına dikkatinizi çekmek istiyorum.

Her şeyden önce, ortalama alma algoritmalarının çoğu, 'series' giriş parametresinin değerlerini saklamak için m_SeriesArray[] türünün dinamik değişken dizilerini içerir.

Hesaplama için önemli olan bilgiler gelir gelmez, bu dizi için tek seferlik bellek ayırmanız gerekir. Bu, CMovSeriesTools sınıfının SeriesArrayResize() işlevi kullanılarak yapılır.

//----+ Changing the size of the array of variables
if(bar==begin && !SeriesArrayResize(__FUNCTION__, Length, m_SeriesArray, m_Size_))
   return(EMPTY_VALUE);

Daha sonra her çubukta 'series' fiyat serisinin mevcut değerini dizinin en eski değerine yazmalı ve m_count değişkenindeki pozisyon numarasını belleğe almalısınız. Bu, CMovSeriesTools sınıfının Recount_ArrayZeroPos() işlevi kullanılarak yapılır.

//----+ transposition and initialization of cells of the array m_SeriesArray 
Recount_ArrayZeroPos(m_count, Length_, prev_calculated, series, bar, m_SeriesArray);

Ve şimdi, mevcut öğeye göreli kayması olan bir öğe bulmamız gerekirse CMovSeriesTools sınıfının Recount_ArrayNumber() işlevini kullanmalıyız:

for(iii=1; iii<=Length; iii++, rrr--)
   {
    kkk = Recount_ArrayNumber(m_count, Length_, iii);
    m_sum += m_SeriesArray[kkk] * rrr;
    m_lsum += m_SeriesArray[kkk];
    m_weight += iii;
   }

Genellikle bu gibi durumlarda, en yeni öğe sıfır pozisyonuna yazılır ve diğerleri (en eskisi hariç) sırayla sonraki pozisyonlara ön üzerine yazılır ancak, bu, bilgisayar kaynaklarını korumuyor ve yukarıda açıklanan daha karmaşık yaklaşım daha mantıklı görünüyor!

Ortalama alma algoritmalarına ek olarak, bu işlevlerin gövdeleri, çubukların hesaplanma başlangıcına göre çubuk pozisyonlarının belirlenmesi için kullanılan işlevlerin çağrılarını içerir:

//----+ Checking the start of reliable calculation of bars
if(BarCheck1(begin, bar, set)) return(EMPTY_VALUE);

Değişkenlerin başlatılması için yeterli bilginin olduğu an:

//----+ Initialization of zero
if(BarCheck2(begin, bar, set, Length))

ve son çubuğun kapatıldığı durumlar:

//----+ Saving values of the variables 
if(BarCheck4(rates_total, bar, set))

veya kapatılmadığı:

//----+ Restoring values of the variables
if(BarCheck5(rates_total, bar, set))

İlk kontrol, ortalama alma işlevinin çalışması için yeterli çubuk olmadığında bir durumu belirler ve boş bir sonuç döndürür. İkinci kontrol başarılı bir şekilde iletildiğinde ve ilk hesaplama için yeterli veri olduğunda, değişkenlerin başlatılması bir kez gerçekleştirilir. Geçerli kapatılmamış çubuktaki değerlerin doğru çoklu işlenmesi için son iki kontrol gereklidir. Bunu program kodunun optimizasyonuna ayrılmış makalemde zaten anlatmıştım.

Ve şimdi, maksimum performans için bu tür işlevlerin program kodunun optimizasyonu hakkında birkaç şey söyleyeceğim. Örneğin, SMA algoritması, her çubukta bir fiyat serisinin bir dönemine ait seçilen değerlerin ortalamasının alınmasını gerektirir. Bu değerler tamı tamına toplanır ve her bir çubuktaki döneme bölünür.

Ancak, önceki çubuktaki toplam ile mevcut çubuktaki toplam arasındaki fark, ilkinin, cari döneme göre bir dönemdeki kaymayı içeren fiyat serisinin değeri ile ve ikincisinin cari değerle toplanmasıdır. Bu nedenle, işlevlerin başlatılması sırasında böyle bir toplamı yalnızca bir kez hesaplamak ve daha sonra her bir çubukta bu toplama fiyat serisinin yalnızca yeni değerlerini eklemek ve en eski değerleri bundan çıkarmak çok mantıklı olacaktır. Bu, tam olarak böyle bir işlevde yapılır.


Sonuç

Makalede önerilen sınıfları kullanarak ortalama alma algoritmalarının uygulamaları basit, tek tip ve evrenseldir; bu nedenle onları incelerken herhangi bir sorun yaşamayacaksınız.

Makaleye eklenmiş arşivler, göstergelerin kodunun yazılmasına yönelik bu yaklaşımın daha kolay anlaşılması için birçok örnek içermektedir. Include__en.zip arşivinde tüm sınıflar dosyalar halinde dağıtılır. Include_en.zip arşivi, Indicators.zip arşivindeki tüm göstergeleri derlemek için yeterli olan yalnızca iki dosya içerir. Test için Expert Advisor'lar, Experts.zip arşivindedir.


MetaQuotes Ltd tarafından Rusçadan çevrilmiştir.
Orijinal makale: https://www.mql5.com/ru/articles/180

Ekli dosyalar |
experts-en.zip (3.88 KB)
include__en.zip (40.84 KB)
include-en.zip (17.82 KB)
indicators_en.zip (90.93 KB)
Spektrum Analizörü Oluşturma Spektrum Analizörü Oluşturma
Bu makale, okuyucularını MQL5 dilinin grafik nesnelerini kullanmanın olası bir varyantı hakkında bilgilendirmeyi amaçlamaktadır. Ayrıca, grafik nesneleri kullanarak basit bir spektrum analizörü yönetme panelini uygulayan bir gösterge analiz edilmektedir. Makale, MQL5'in temelleri hakkında bilgi sahibi olan okuyuculara yöneliktir.
Standart Kitaplık Sınıflarını kullanarak kendi Piyasa İzlemenizi oluşturun Standart Kitaplık Sınıflarını kullanarak kendi Piyasa İzlemenizi oluşturun
Yeni MetaTrader 5 istemci terminali ve MQL5 Dili, yatırımcıya görsel bilgi sunmak için yeni fırsatlar sunar. Bu makalede, grafik üzerinde rastgele seçilmiş metin bilgilerinin görüntülenmesini düzenlemeye ilişkin tüm işleri yürüten evrensel ve genişletilebilir bir sınıflar kümesi öneriyoruz. Piyasa İzleme göstergesi örneği sunulmuştur.
William Blau'nun MQL5'teki Göstergeleri ve Alım Satım Sistemleri. Bölüm 1: Göstergeler William Blau'nun MQL5'teki Göstergeleri ve Alım Satım Sistemleri. Bölüm 1: Göstergeler
Makalede, William Blau'nun "Momentum, Direction, and Divergence" kitabında açıklanan göstergeler sunulmaktadır. William Blau'nun yaklaşımı, fiyat eğrisindeki dalgalanmaları yaklaşık olarak hızlı ve doğru bir şekilde tahmin etmemize, fiyat hareketleri trendini ve dönüm noktalarını belirlememize ve fiyat gürültüsünü ortadan kaldırmamıza olanak tanır. Aynı zamanda, piyasanın aşırı alım/aşırı satım durumlarını ve bir trendin sona erdiğini ve fiyat hareketinin tersine döndüğünü gösteren sinyalleri de tespit edebiliyoruz.
Bulanık Mantık Kullanarak Gösterge Oluşturmanın Basit Örneği Bulanık Mantık Kullanarak Gösterge Oluşturmanın Basit Örneği
Makale, finansal piyasalar analizi için bulanık mantık kavramının pratik uygulamasına ayrılmıştır. Zarflar göstergesine dayalı iki bulanık kural temeline dayanan sinyal üreten gösterge örneğini öneriyoruz. Geliştirilen gösterge birkaç gösterge arabelleği kullanır: Hesaplamalar için 7 arabellek, grafikler için 5 arabellek ve 2 renk arabelleği.