English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
MQL5 Programlama Temelleri: Listeler

MQL5 Programlama Temelleri: Listeler

MetaTrader 5Örnekler | 14 Ocak 2022, 10:20
312 0
Denis Kirichenko
Denis Kirichenko

Giriş

MQL dilinin yeni versiyonu, otomatik alım satım sistemlerinin geliştiricilerine karmaşık görevlerin uygulanması için etkili araçlar sağladı. Dilin programlama işlevlerinin önemli ölçüde genişletildiği gerçeği inkar edilemez. Tek başına MQL5 OOP özellikleri bile son derece değerlidir. Dahası, Standart Kitaplık'tan da bahsetmeden geçmemek gerekir. 359 numaralı hata koduna bakılırsa sınıf şablonları yakında desteklenecektir.

Bu makalede, veri türlerini ve kümelerini anlatan konuların bir şekilde genişletilmesi veya devamı olabilecek şeyleri gündeme getirmek istiyorum. Burada MQL5.community web sitesinde yayınlanan bir makaleye atıfta bulunmak istiyorum. Dizilerle çalışmanın ilkeleri ve mantığının çok ayrıntılı ve kapsamlı bir açıklaması Dmitry Fedoseev (Tamsayı) tarafından "MQL5 Programlama Temelleri: Diziler" makalesinde verilmiştir.

Bu yüzden bugün listelere ve daha doğrusu bağlantılı doğrusal listelere dönmeyi öneriyorum. Liste yapısı, anlamı ve mantığı ile başlayacağız. Bundan sonra, Standart Kitaplıkta zaten mevcut olan ilgili araçları ele alacağız. Sonuç olarak, MQL5 ile çalışırken listelerin nasıl kullanılabileceğine dair örnekler vereceğim.

  1. Liste ve Düğüm Kavramı: Teori
  2. Liste ve Düğüm Kavramı: Programlama
  3. MQL5 Standart Kitaplığındaki Listeler
  4. MQL5'te Liste Kullanım Örnekleri


1. Liste ve Düğüm Kavramı: Teori

Peki bir geliştirici için liste nedir ve bu konuda nasıl bir yol izlersiniz? Bu terimin genel bir tanımı için genel bilgi kaynağı Wikipedia'ya atıfta bulunacağım:

Bilgisayar biliminde liste, aynı değerin birden çok kez meydana gelebileceği, sonlu sıralı bir değerler koleksiyonunu uygulayan soyut bir veri türüdür. Listenin bir örneği, sonlu bir dizinin matematiksel kavramının bilgisayar temsilidir; bir demet. Listedeki her değer örneğine genellikle listenin bir parçası, girişi veya öğesi denir; aynı değer birden çok kez ortaya çıkarsa, her oluşum ayrı bir öğe olarak kabul edilir.

'Liste' terimi aynı zamanda soyut listeleri, özellikle bağlantılı listeleri uygulamak için kullanılabilecek birkaç somut veri yapısı için de kullanılır.

Bu tanımın biraz fazla bilimsel olduğunu kabul edeceğinize inanıyorum.

Bu makalenin amacı doğrultusunda, bu tanımın son cümlesiyle daha çok ilgileniyoruz. O halde üzerinde duralım:

Bilgisayar biliminde, bağlantılı liste, her düğümün veriden ve listenin bir sonraki ve/veya önceki düğümüne bir veya iki referanstan ("bağlantılar") oluştuğu düğümlerden oluşan temel bir dinamik veri yapısıdır. [1] Bir bağlantılı listenin geleneksel bir diziye göre başlıca yararı yapısal bir esnekliktir: bağlantılı listenin öğelerinin sırasının bilgisayar belleğindeki veri öğelerinin sırasıyla eşleşmesi gerekmez, liste öğelerinin dahili bağlantıları ise her zaman liste geçişi için korunur.

Adım adım incelemeye çalışalım.

Bilgisayar biliminde, liste başlı başına bir veri türüdür. Bunu pekiştirdik. Diğer veri türlerini içerdiği için daha çok sentetik bir veri türüdür. Liste, biraz diziye benzer. Tek tür bir veri dizisi yeni bir veri türü olarak sınıflandırılmışsa bu bir liste olacaktır. Ancak tamamen öyle değildir.

Bir listenin başlıca yararı, ihtiyaca göre listenin herhangi bir noktasında düğümlerin eklenmesine veya çıkarılmasına izin vermesidir. Burada liste dinamik bir diziye benzer ancak liste için her zaman ArrayResize() işlevini kullanmanız gerekmez.

Bellek öğelerinin sırası açısından konuşursak, liste düğümleri depolanmaz ve dizi öğelerinin bitişik bellek alanlarında depolandığı gibi depolanmaları da gerekmez.

Konu aşağır yukarı bundan ibaret. Devam ediyoruz.


1.1 Tek Bağlantılı Listedeki Düğüm

Listeler, öğeler yerine düğümleri depolamanıza izin verir. Düğüm, iki bölümden oluşan bir veri türüdür.

İlk kısım bir veri alanıdır ve ikinci kısım diğer düğümler ile bağlantılar için kullanılır (Şekil 1). Listedeki ilk düğüme "baş", listedeki son düğüme "kuyruk" denir. Kuyruk bağlantısı alanı bir NULL referansı içerir. Temel olarak listede daha fazla düğüm bulunmadığını belirtmek için kullanılır. Belirli bir amaç için üretilen diğer kaynaklar, listenin baştan sonra geri kalanını 'kuyruk' olarak adlandırır.

Şek. 1 Tek bağlantılı listedeki düğümler

Şek. 1 Tek bağlantılı listedeki düğümler

Tek bağlantılı liste düğümlerinin yanı sıra, başka düğüm türleri de vardır. Çiftli bağlantılı bir listedeki bir düğüm belki de en yaygın olanıdır.


1.2 Çift Bağlantılı Listedeki Düğüm

Ayrıca çift bağlantılı bir listenin ihtiyaçlarına hizmet edecek bir düğüme ihtiyacımız olacak. Önceki türden farklıdır çünkü önceki düğüme işaret eden başka bir bağlantı içerir. Doğal olarak, listenin başındaki düğüm bir NULL referansı içerecektir. Bu tür düğümleri içeren listenin yapısını gösteren diyagramda (Şekil 2), önceki düğümlere işaret eden bağlantılar kırmızı oklarla gösterilir.

Şek. 2 Çift bağlantılı bir listedeki düğümler

Şek. 2 Çift bağlantılı bir listedeki düğümler


Bu nedenle, çift bağlantılı bir listedeki düğümün yetenekleri, tek bağlantılı bir liste düğümününkine benzer olacaktır. Sadece önceki düğüme bir bağlantı daha işlemeniz gerekecek.


1.3 Dairesel Çift Bağlantılı Listedeki Düğüm

Yukarıdaki düğümlerin doğrusal olmayan listelerde de kullanılabileceği durumlar vardır. Ayrıca makale öncelikle doğrusal listeleri anlatacak olsa da, dairesel bir liste örneğini de vereceğim.

Şek. 3 Dairesel bir çift bağlantılı listedeki düğümler

Şek. 3 Dairesel bir çift bağlantılı listedeki düğümler


Dairesel çift bağlantılı liste diyagramı (Şekil 3), iki bağlantı alanına sahip düğümlerin basitçe dairesel olarak bağlı olduğunu gösterir. Bu, turuncu ve yeşil oklar kullanılarak yapılır. Böylece, baş düğüm (önceki öğe gibi) kuyruğa bağlanacaktır. Kuyruk düğümünün bağlantı alanı, başa işaret edeceği için boş olmayacaktır.


1.4 Ana Liste İşlemleri

Belirli bir amaç için üretilen literatürde belirtildiği gibi, tüm liste işlemleri 3 temel gruba ayrılabilir:

  1. Ekleme (listeye yeni düğüm eklenmesi);
  2. Silme (listeden düğümün silinmesi);
  3. Kontrol etme (düğüm verilerinin kontrolü).

Ekleme yöntemleri şunları içerir:

  • listenin başına yeni bir düğüm ekleme;
  • listenin sonuna yeni bir düğüm ekleme;
  • listede belirtilen konuma bir düğüm ekleme;
  • boş bir listeye bir düğüm ekleme;
  • parametreli kurucu.

Silme işlemleri söz konusu olduğunda, bunlar ek grubun karşılık gelen işlemlerini sanal olarak yansıtır:

  • baş düğümün silinmesi;
  • kuyruk düğümünün silinmesi;
  • listede belirtilen konumdan bir düğümün silinmesi;
  • yıkıcı.

Burada, yıkıcının sadece liste işlemini doğru bir şekilde tamamlamaya ve sonlandırmaya değil, aynı zamanda tüm öğelerini düzgün bir şekilde silmeye de hizmet ettiğini belirtmek isterim.

Çeşitli kontrol işlemlerinin üçüncü grubu aslında listedeki düğümlere veya düğüm değerlerine erişim sağlar:

  • verilen bir değeri arama;
  • listenin boş olup olmadığını kontrol etmek;
  • listedeki ith düğümünün değerini almak;
  • listedeki ith düğümünün işaretçisini almak;
  • liste boyutunu almak;
  • liste öğelerinin yazdırma değerleri.

Temel gruplara ek olarak, dördüncü hizmet grubunu da ayırırdım. Önceki gruplara hizmet eder:

  • belirleme operatörü;
  • kopya kurucu;
  • dinamik işaretçi ile çalışma;
  • listenin değerlere göre kopyalanması;
  • sıralama.

Bu kadar. Elbette geliştirici, herhangi bir zamanda gerektiği gibi liste sınıfının işlevselliğini ve özelliklerini genişletebilir.


2. Liste ve Düğüm Kavramı: Programlama

Bu bölümde, doğrudan programlama düğümlerine ve listelerine geçmemizi öneriyorum. Gerektiğinde koda ilişkin çizimler sağlanacaktır.

2.1 Tek Bağlantılı Listedeki Düğüm

Tek bağlantılı bir listenin ihtiyaçlarına hizmet eden düğüm sınıfının (Şekil 4) temelini atalım. "UML Araçlarını Kullanarak Expert Advisor Nasıl Geliştirilir" başlıklı makalede sınıf diyagramı gösterimi (modeli) hakkında bilgi edinebilirsiniz (bkz. Şekil 5. CTradeExpert sınıfının UML modeli).

CiSingleNode sınıf modeli

Şek. 4 CiSingleNode sınıf modeli

Şimdi kodla çalışmayı deneyelim. Art Friedman ve diğer yazarlar tarafından kitapta verilen örneğe dayanmaktadır. "C/C++ Açıklamalı Arşivler".

//+------------------------------------------------------------------+
//|                     CiSingleNode class                           |
//+------------------------------------------------------------------+
class CiSingleNode
  {
protected:
   int               m_val;   // data
   CiSingleNode     *m_next;  // pointer to the next node
public:
   void              CiSingleNode(void);                             // default constructor
   void              CiSingleNode(int _node_val);                    // parameterized constructor
   void             ~CiSingleNode(void);                             // destructor
   void              SetVal(int _node_val);                          // set-method for data
   void              SetNextNode(CiSingleNode *_ptr_next);           // set-method for the next node
   virtual void      SetPrevNode(CiSingleNode *_ptr_prev){};         // set-method for the previous node
   virtual CiSingleNode *GetPrevNode(void) const {return NULL;};     // get-method for the previous node
   CiSingleNode     *GetNextNode(void) const;                        // get-method for the next node 
   int               GetVal(void){TRACE_CALL(_t_flag) return m_val;} // get-method for data 
  };

CiSingleNode sınıfının her yöntemini açıklamayacağım. Ekli CiSingleNode.mqh dosyasında bunlara daha yakından bakabileceksiniz. Ancak, dikkatinizi ilginç bir nüansa çekmek istiyorum. Sınıf, önceki düğümlerle çalışan sanal yöntemler içerir. Aslında bunlar birer kukladır ve varlıkları daha çok gelecekteki alt öğeler için polimorfizm amaçlarına yöneliktir.

Kod, kullanılan her yöntemin çağrılarını izlemek için gereken TRACE_CALL(f) önişlemci yönergesini kullanır.

#define TRACE_CALL(f) if(f) Print("Calling: "+__FUNCSIG__);

Yalnızca CiSingleNode sınıfının mevcut olmasıyla, tek bağlantılı bir liste oluşturabilecek konumdasınız. Kodun bir örneğini vereyim.

//=========== Example 1 (processing the CiSingleNode type )
 
   CiSingleNode *p_sNodes[3];                             // #1
   p_sNodes[0]=NULL;
   srand(GetTickCount()); // initialize a random number generator
//--- create nodes
   for(int i=0;i<ArraySize(p_sNodes);i++)
      p_sNodes[i]=new CiSingleNode(rand());               // #2
//--- links
   for(int j=0;j<(ArraySize(p_sNodes)-1);j++)
      p_sNodes[j].SetNextNode(p_sNodes[j+1]);             // #3
//--- check values
   for(int i=0;i<ArraySize(p_sNodes);i++)
     {
      int val=p_sNodes[i].GetVal();                       // #4
      Print("Node #"+IntegerToString(i+1)+                // #5
            " value = "+IntegerToString(val));
     }
//--- check next-nodes
   for(int j=0;j<(ArraySize(p_sNodes)-1);j++)
     {
      CiSingleNode *p_sNode_next=p_sNodes[j].GetNextNode(); // #9
      int snode_next_val=p_sNode_next.GetVal();             // #10
      Print("Next-Node #"+IntegerToString(j+1)+             // #11
            " value = "+IntegerToString(snode_next_val));
     }
//--- delete nodes
   for(int i=0;i<ArraySize(p_sNodes);i++)
      delete p_sNodes[i];                                   // #12 

#1 dizesinde, CiSingleNode türündeki nesnelere yönelik bir dizi işaretçi bildiririz. #2 dizesinde, dizi oluşturulan işaretçilerle doldurulur. Her düğümün verisi için rand() işlevini kullanarak 0 ila 32767 aralığında yalancı rasgele bir tamsayı alırız. Düğümler, #3 dizesindeki bir sonraki işaretçi ile bağlantılıdır. #4-5 dizelerinde düğümlerin değerlerini kontrol ediyoruz ve #9-11 dizelerinde bağlantıların performansını kontrol ediyoruz. İşaretçiler #12 dizesinde silinir.

Günlüğe yazdırılan budur.

DH      0       23:23:10        test_nodes (EURUSD,H4)  Node #1 value = 3335
KP      0       23:23:10        test_nodes (EURUSD,H4)  Node #2 value = 21584
GI      0       23:23:10        test_nodes (EURUSD,H4)  Node #3 value = 917
HQ      0       23:23:10        test_nodes (EURUSD,H4)  Next-Node #1 value = 21584
HI      0       23:23:10        test_nodes (EURUSD,H4)  Next-Node #2 value = 917

Ortaya çıkan düğüm yapısı şematik olarak aşağıdaki gibi gösterilebilir (Şekil 5).

Şek. 5 CiSingleNode *p_sNodes[3] dizisindeki düğümler arasındaki bağlantılar

Şek. 5 CiSingleNode *p_sNodes[3] dizisindeki düğümler arasındaki bağlantılar

Şimdi çift bağlantılı bir listedeki düğümlere geçelim.


2.2 Çift Bağlantılı Listedeki Düğüm

İlk olarak, çift bağlantılı listedeki bir düğümün iki işaretçisi olması bakımından farklı olduğu bilgisini yenilemeliyiz: sonraki düğüm işaretçisi ve önceki düğüm işaretçisi. Yani, sonraki düğüm bağlantısının yanı sıra, tek bağlantılı bir liste düğümüne önceki düğüme bir işaretçi eklemeniz gerekir.

Bunu yaparken, kalıtımı bir sınıf ilişkisi olarak kullanmayı öneriyorum. Daha sonra çift bağlantılı listedeki bir düğüm için sınıf modeli aşağıdaki gibi görünebilir (Şekil 6).

CDoubleNode sınıf modeli

Şek. 6 CDoubleNode sınıf modeli

Şimdi koda bir göz atma zamanı.

//+------------------------------------------------------------------+
//|                    CDoubleNode class                             |
//+------------------------------------------------------------------+
class CDoubleNode : public CiSingleNode
  {
protected:
   CiSingleNode     *m_prev;  // pointer to the previous node 

public:
   void              CDoubleNode(void);                     // default constructor
   void              CDoubleNode(int node_val);             // parameterized constructor
   void             ~CDoubleNode(void){TRACE_CALL(_t_flag)};// destructor
   virtual void      SetPrevNode(CiSingleNode *_ptr_prev);  // set-method for the previous node
   virtual CiSingleNode *GetPrevNode(void) const;           // get-method for the previous node CDoubleNode
  };

Çok az ek yöntem vardır; bunlar sanaldır ve önceki düğümle çalışmakla ilgilidir. Tam sınıf açıklaması CDoubleNode.mqh içinde sağlanır.

CDoubleNode sınıfına dayalı çift bağlantılı bir liste oluşturmaya çalışalım. Kodun bir örneğini vereyim.

//=========== Example 2 (processing the CDoubleNode type)

   CiSingleNode *p_dNodes[3];                             // #1
   p_dNodes[0]=NULL;
   srand(GetTickCount()); // initialize a random number generator
//--- create nodes
   for(int i=0;i<ArraySize(p_dNodes);i++)
      p_dNodes[i]=new CDoubleNode(rand());                // #2
//--- links
   for(int j=0;j<(ArraySize(p_dNodes)-1);j++)
     {
      p_dNodes[j].SetNextNode(p_dNodes[j+1]);             // #3
      p_dNodes[j+1].SetPrevNode(p_dNodes[j]);             // #4
     }
//--- check values
   for(int i=0;i<ArraySize(p_dNodes);i++)
     {
      int val=p_dNodes[i].GetVal();                       // #4
      Print("Node #"+IntegerToString(i+1)+                // #5
            " value = "+IntegerToString(val));
     }
//--- check next-nodes
   for(int j=0;j<(ArraySize(p_dNodes)-1);j++)
     {
      CiSingleNode *p_sNode_next=p_dNodes[j].GetNextNode(); // #9
      int snode_next_val=p_sNode_next.GetVal();             // #10
      Print("Next-Node #"+IntegerToString(j+1)+             // #11
            " value = "+IntegerToString(snode_next_val));
     }
//--- check prev-nodes
   for(int j=0;j<(ArraySize(p_dNodes)-1);j++)
     {
      CiSingleNode *p_sNode_prev=p_dNodes[j+1].GetPrevNode(); // #12
      int snode_prev_val=p_sNode_prev.GetVal();               // #13
      Print("Prev-Node #"+IntegerToString(j+2)+               // #14
            " value = "+IntegerToString(snode_prev_val));
     }
//--- delete nodes
   for(int i=0;i<ArraySize(p_dNodes);i++)
      delete p_dNodes[i];                                     // #15 

Prensipte bu, tek başına bağlantılı bir liste oluşturmaya benzer ancak birkaç tuhaflık vardır. p_dNodes[] işaretçileri dizisinin #1 dizesinde nasıl bildirildiğine dikkat edin. İşaretçilerin türü, temel sınıfla aynı şekilde ayarlanabilir. #2 dizesindeki polimorfizm ilkesi, gelecekte onları tanımamıza yardımcı olacaktır. Önceki düğümler #12-14 dizelerinde kontrol edilir.

Aşağıdaki bilgiler günlüğe eklendi.

GJ      0       16:28:12        test_nodes (EURUSD,H4)  Node #1 value = 17543
IQ      0       16:28:12        test_nodes (EURUSD,H4)  Node #2 value = 1185
KK      0       16:28:12        test_nodes (EURUSD,H4)  Node #3 value = 23216
DS      0       16:28:12        test_nodes (EURUSD,H4)  Next-Node #1 value = 1185
NH      0       16:28:12        test_nodes (EURUSD,H4)  Next-Node #2 value = 23216
FR      0       16:28:12        test_nodes (EURUSD,H4)  Prev-Node #2 value = 17543
LI      0       16:28:12        test_nodes (EURUSD,H4)  Prev-Node #3 value = 1185

Ortaya çıkan düğüm yapısı şematik olarak aşağıdaki gibi gösterilebilir (Şekil 7):

Şek. 7 CDoubleNode *p_sNodes[3] dizisindeki düğümler arasındaki bağlantılar

Şek. 7 CDoubleNode *p_sNodes[3] dizisindeki düğümler arasındaki bağlantılar

Şimdi, teşhir edilmemiş çift bağlantılı bir liste oluşturmak için gerekli olacak bir düğümü düşünmemizi öneriyorum.


2.3 Teşhir Edilmiş Çift Bağlantılı Listedeki Düğüm

Tek bir değer yerine tüm diziye atfedilebilen, yani tüm diziyi içeren ve tanımlayan bir veri üyesi içeren bir düğüm düşünün. Böyle bir düğüm daha sonra teşhir edilmemiş bir liste oluşturmak için kullanılabilir. Bu düğüm, çift bağlantılı bir listedeki standart bir düğümle tamamen aynı olduğundan burada herhangi bir örnek vermemeye karar verdim. Tek fark, ‹veri' özniteliğinin tüm diziyi kapsamasıdır.

Kalıtımı tekrar kullanacağım. CDoubleNode sınıfı, teşhir edilmemiş çift bağlantılı listedeki bir düğüm için temel sınıf olarak hizmet edecektir. Teşhir edilmemiş çift bağlantılı listedeki bir düğümün sınıf modeli aşağıdaki gibi görünecektir (Şekil 8).

CiUnrollDoubleNode sınıf modeli

Şek. 8 CiUnrollDoubleNode sınıf modeli

CiUnrollDoubleNode sınıfı aşağıdaki kod kullanılarak tanımlanabilir:

//+------------------------------------------------------------------+
//|                    CiUnrollDoubleNode class                      |
//+------------------------------------------------------------------+
class CiUnrollDoubleNode : public CDoubleNode
  {
private:
   int               m_arr_val[]; // data array

public:
   void              CiUnrollDoubleNode(void);               // default constructor 
   void              CiUnrollDoubleNode(int &_node_arr[]);   // parameterized constructor
   void             ~CiUnrollDoubleNode(void);               // destructor
   bool              GetArrVal(int &_dest_arr_val[])const;   // get-method for data array
   bool              SetArrVal(const int &_node_arr_val[]);  // set-method for data array
  };

CiUnrollDoubleNode.mqh içinde her yöntemi daha ayrıntılı olarak inceleyebilirsiniz.

Örnek olarak parametreli bir oluşturucu ele alalım.

//+------------------------------------------------------------------+
//|                   Parameterized constructor                      |
//+------------------------------------------------------------------+
void CiUnrollDoubleNode::CiUnrollDoubleNode(int &_node_arr[])
   : CDoubleNode(ArraySize(_node_arr))
  {
   ArrayCopy(this.m_arr_val,_node_arr);
   TRACE_CALL(_t_flag)
  }

Burada, başlatma listesini kullanarak, this.m_val veri üyesine tek boyutlu bir dizinin boyutunu giriyoruz.

Bundan sonra, 'manuel' olarak teşhir edilmemiş bir çift bağlantılı liste oluşturuyoruz ve içindeki bağlantıları kontrol ediyoruz.

//=========== Example 3 (processing the CiUnrollDoubleNode type)

//--- data arrays
   int arr1[],arr2[],arr3[];                                  // #1
   int arr_size=15;
   ArrayResize(arr1,arr_size);
   ArrayResize(arr2,arr_size);
   ArrayResize(arr3,arr_size);
   srand(GetTickCount()); // initialize a random number generator
   
//--- fill the arrays with pseudorandom integers   
   for(int i=0;i<arr_size;i++)
     {
      arr1[i]=rand();                                         // #2
      arr2[i]=rand();
      arr3[i]=rand();
     }
//--- create nodes
   CiUnrollDoubleNode *p_udNodes[3];                          // #3
   p_udNodes[0]=new CiUnrollDoubleNode(arr1);
   p_udNodes[1]=new CiUnrollDoubleNode(arr2);
   p_udNodes[2]=new CiUnrollDoubleNode(arr3);
//--- links
   for(int j=0;j<(ArraySize(p_udNodes)-1);j++)
     {
      p_udNodes[j].SetNextNode(p_udNodes[j+1]);               // #4
      p_udNodes[j+1].SetPrevNode(p_udNodes[j]);               // #5
     }
//--- check values
   for(int i=0;i<ArraySize(p_udNodes);i++)
     {
      int val=p_udNodes[i].GetVal();                          // #6
      Print("Node #"+IntegerToString(i+1)+                    // #7
            " value = "+IntegerToString(val));
     }
//--- check array values
   for(int i=0;i<ArraySize(p_udNodes);i++)
     {
      int t_arr[]; // destination array 
      bool isCopied=p_udNodes[i].GetArrVal(t_arr);            // #8
      if(isCopied)
        {
         string arr_str=NULL;
         for(int n=0;n<ArraySize(t_arr);n++)
            arr_str+=IntegerToString(t_arr[n])+", ";
         int end_of_string=StringLen(arr_str);
         arr_str=StringSubstr(arr_str,0,end_of_string-2);
         Print("Node #"+IntegerToString(i+1)+                 // #9
               " array values = "+arr_str);
        }
     }
//--- check next-nodes
   for(int j=0;j<(ArraySize(p_udNodes)-1);j++)
     {
      int t_arr[]; // destination array 
      CiUnrollDoubleNode *p_udNode_next=p_udNodes[j].GetNextNode(); // #10
      bool isCopied=p_udNode_next.GetArrVal(t_arr);
      if(isCopied)
        {
         string arr_str=NULL;
         for(int n=0;n<ArraySize(t_arr);n++)
            arr_str+=IntegerToString(t_arr[n])+", ";
         int end_of_string=StringLen(arr_str);
         arr_str=StringSubstr(arr_str,0,end_of_string-2);
         Print("Next-Node #"+IntegerToString(j+1)+
               " array values = "+arr_str);
        }
     }
//--- check prev-nodes
   for(int j=0;j<(ArraySize(p_udNodes)-1);j++)
     {
      int t_arr[]; // destination array 
      CiUnrollDoubleNode *p_udNode_prev=p_udNodes[j+1].GetPrevNode(); // #11
      bool isCopied=p_udNode_prev.GetArrVal(t_arr);
      if(isCopied)
        {
         string arr_str=NULL;
         for(int n=0;n<ArraySize(t_arr);n++)
            arr_str+=IntegerToString(t_arr[n])+", ";
         int end_of_string=StringLen(arr_str);
         arr_str=StringSubstr(arr_str,0,end_of_string-2);
         Print("Prev-Node #"+IntegerToString(j+2)+
               " array values = "+arr_str);
        }
     }
//--- delete nodes
   for(int i=0;i<ArraySize(p_udNodes);i++)
      delete p_udNodes[i];                                            // #12
  }

Kod miktarı biraz daha büyüdü. Bu, her düğüm için bir dizi oluşturmamız ve doldurmamız gerektiğiyle bağlantılıdır.

Veri dizileriyle çalışmak, #1 dizesindede başlar. Temelde, ele alınan önceki düğümlerde sahip olduğumuza benzer. Sadece tüm dizi için her düğümün veri değerlerini yazdırmamız gerekiyor (örneğin, dize #9).

Elimdeki bu:

IN      0       00:09:13        test_nodes (EURUSD.m,H4)        Node #1 value = 15
NF      0       00:09:13        test_nodes (EURUSD.m,H4)        Node #2 value = 15
CI      0       00:09:13        test_nodes (EURUSD.m,H4)        Node #3 value = 15
FQ      0       00:09:13        test_nodes (EURUSD.m,H4)        Node #1 array values = 31784, 4837, 25797, 29079, 4223, 27234, 2155, 32351, 12010, 10353, 10391, 22245, 27895, 3918, 12069
EG      0       00:09:13        test_nodes (EURUSD.m,H4)        Node #2 array values = 1809, 18553, 23224, 20208, 10191, 4833, 25959, 2761, 7291, 23254, 29865, 23938, 7585, 20880, 25756
MK      0       00:09:13        test_nodes (EURUSD.m,H4)        Node #3 array values = 18100, 26358, 31020, 23881, 11256, 24798, 31481, 14567, 13032, 4701, 21665, 1434, 1622, 16377, 25778
RP      0       00:09:13        test_nodes (EURUSD.m,H4)        Next-Node #1 array values = 1809, 18553, 23224, 20208, 10191, 4833, 25959, 2761, 7291, 23254, 29865, 23938, 7585, 20880, 25756
JD      0       00:09:13        test_nodes (EURUSD.m,H4)        Next-Node #2 array values = 18100, 26358, 31020, 23881, 11256, 24798, 31481, 14567, 13032, 4701, 21665, 1434, 1622, 16377, 25778
EH      0       00:09:13        test_nodes (EURUSD.m,H4)        Prev-Node #2 array values = 31784, 4837, 25797, 29079, 4223, 27234, 2155, 32351, 12010, 10353, 10391, 22245, 27895, 3918, 12069
NN      0       00:09:13        test_nodes (EURUSD.m,H4)        Prev-Node #3 array values = 1809, 18553, 23224, 20208, 10191, 4833, 25959, 2761, 7291, 23254, 29865, 23938, 7585, 20880, 25756

Düğümlerle çalışmanın altına bir çizgi çekmemizi ve doğrudan farklı listelerin sınıf tanımlarına geçmemizi öneriyorum. 1-3 arasındaki örnekler test_nodes.mq5 script dosyasında bulunabilir.


2.4 Tek Bağlantılı Liste

Ana liste işlem gruplarından tek bağlantılı bir listenin sınıf modelini yapmanın zamanı geldi (Şekil 9).

CiSingleList sınıf modeli

Şek. 9 CiSingleList sınıf modeli

CiSingleList sınıfının CiSingleNode türü düğümü kullandığı kolayca görülebilir. Sınıflar arasındaki ilişki türlerinden bahsederken şunu söyleyebiliriz:

  1. CiSingleList sınıfı, CiSingleNode sınıfını (kompozisyon) içerir;
  2. CiSingleList sınıfı, CiSingleNode sınıf yöntemlerini (bağımlılık) kullanır.

Yukarıdaki ilişkilerin gösterimi Şekil 10'da verilmiştir.

Şek. 10 CiSingleList sınıfı ve CiSingleNode sınıfı arasındaki ilişki türleri

Şekil 10 CiSingleList sınıfı ve CiSingleNode sınıfı arasındaki ilişki türleri

Yeni bir sınıf oluşturalım - CiSingleList. İleriye bakıldığında, makalede kullanılan diğer tüm liste sınıfları bu sınıfa dayalı olacaktır. Bu yüzden bu kadar 'zengin'.

//+------------------------------------------------------------------+
//|                     CiSingleList class                           |
//+------------------------------------------------------------------+
class CiSingleList
  {
protected:
   CiSingleNode     *m_head;    // head
   CiSingleNode     *m_tail;    // tail
   uint              m_size;    // number of nodes in the list
public:
   //--- constructor and destructor
   void              CiSingleList();                              // default constructor 
   void              CiSingleList(int _node_val);                 // parameterized constructor 
   void             ~CiSingleList();                              // destructor                

   //--- adding nodes   
   void              AddFront(int _node_val);                         // add a new node to the beginning of the list
   void              AddRear(int _node_val);                          // add a new node to the end of the list   
   virtual void      AddFront(int &_node_arr[]){TRACE_CALL(_t_flag)}; // add a new node to the beginning of the list
   virtual void      AddRear(int &_node_arr[]){TRACE_CALL(_t_flag)};  // add a new node to the end of the list
   //--- deleting nodes     
   int               RemoveFront(void);                           // delete the head node       
   int               RemoveRear(void);                            // delete the node from the end of the list
   void              DeleteNodeByIndex(const uint _idx);          // delete the ith node from the list

   //--- checking   
   virtual bool      Find(const int _node_val) const;             // find the required value    
   bool              IsEmpty(void) const;                         // check the list for being empty
   virtual int       GetValByIndex(const uint _idx) const;        // value of the ith node in the list
   virtual CiSingleNode *GetNodeByIndex(const uint _idx) const;   // get the ith node in the list
   virtual bool      SetNodeByIndex(CiSingleNode *_new_node,const uint _idx); // insert the new ith node in the list
   CiSingleNode     *GetHeadNode(void) const;                     // get the head node
   CiSingleNode     *GetTailNode(void) const;                     // get the tail node
   virtual uint      Size(void) const;                            // list size
   //--- service
   virtual void      PrintList(string _caption=NULL);             // print the list
   virtual bool      CopyByValue(const CiSingleList &_sList);     // copy the list by values
   virtual void      BubbleSort(void);                            // bubble sorting
   //---templates
   template<typename dPointer>
   bool              CheckDynamicPointer(dPointer &_p);           // template for checking a dynamic pointer
   template<typename dPointer>
   bool              DeleteDynamicPointer(dPointer &_p);          // template for deleting a dynamic pointer

protected:
   void              operator=(const CiSingleList &_sList) const; // assignment operator
   void              CiSingleList(const CiSingleList &_sList);    // copy constructor
   virtual bool      AddToEmpty(int _node_val);                   // add a new node to an empty list
   virtual void      addFront(int _node_val);                     // add a new "native" node to the beginning of the list
   virtual void      addRear(int _node_val);                      // add a new "native" node to the end of the list
   virtual int       removeFront(void);                           // delete the "native" head node
   virtual int       removeRear(void);                            // delete the "native" node from the end of the list
   virtual void      deleteNodeByIndex(const uint _idx);          // delete the "native" ith node from the list
   virtual CiSingleNode *newNode(int _val);                       // new "native" node
   virtual void      CalcSize(void) const;                        // calculate the list size
  };

Sınıf yöntemlerinin tam tanımı CiSingleList.mqh içinde verilmiştir.

Bu sınıfı geliştirmeye yeni başladığımda, sadece 3 veri üyesi ve birkaç yöntem vardı. Ancak bu sınıf diğer sınıflar için temel teşkil ettiğinden, birkaç sanal üye işlevi eklemek zorunda kaldım. Bu yöntemleri ayrıntılı olarak anlatmayacağım. Bu tek bağlantılı liste sınıfını kullanmanın bir örneği, test_sList.mq5 script dosyasında bulunabilir.

İzleme bayrağı olmadan çalıştırılırsa günlükte aşağıdaki girişler görünür:

KG      0       12:58:32        test_sList (EURUSD,H1)  =======List #1=======
PF      0       12:58:32        test_sList (EURUSD,H1)  Node #1, val=14 
RL      0       12:58:32        test_sList (EURUSD,H1)  Node #2, val=666 
MD      0       12:58:32        test_sList (EURUSD,H1)  Node #3, val=13 
DM      0       12:58:32        test_sList (EURUSD,H1)  Node #4, val=11 
QE      0       12:58:32        test_sList (EURUSD,H1)  
KN      0       12:58:32        test_sList (EURUSD,H1)  
LR      0       12:58:32        test_sList (EURUSD,H1)  =======List #2=======
RE      0       12:58:32        test_sList (EURUSD,H1)  Node #1, val=14 
DQ      0       12:58:32        test_sList (EURUSD,H1)  Node #2, val=666 
GK      0       12:58:32        test_sList (EURUSD,H1)  Node #3, val=13 
FP      0       12:58:32        test_sList (EURUSD,H1)  Node #4, val=11 
KF      0       12:58:32        test_sList (EURUSD,H1)  
MK      0       12:58:32        test_sList (EURUSD,H1)  
PR      0       12:58:32        test_sList (EURUSD,H1)  =======renewed List #2=======
GK      0       12:58:32        test_sList (EURUSD,H1)  Node #1, val=11 
JP      0       12:58:32        test_sList (EURUSD,H1)  Node #2, val=13 
JI      0       12:58:32        test_sList (EURUSD,H1)  Node #3, val=14 
CF      0       12:58:32        test_sList (EURUSD,H1)  Node #4, val=34 
QL      0       12:58:32        test_sList (EURUSD,H1)  Node #5, val=35 
OE      0       12:58:32        test_sList (EURUSD,H1)  Node #6, val=36 
MR      0       12:58:32        test_sList (EURUSD,H1)  Node #7, val=37 
KK      0       12:58:32        test_sList (EURUSD,H1)  Node #8, val=38 
MS      0       12:58:32        test_sList (EURUSD,H1)  Node #9, val=666 
OF      0       12:58:32        test_sList (EURUSD,H1)  
QK      0       12:58:32        test_sList (EURUSD,H1)  

Script dosyası, tek bağlantılı 2 listeyi doldurdu ve ardından ikinci listeyi genişletip sıraladı.


2.5 Çift Bağlantılı Liste

Şimdi önceki türün listesine dayalı olarak çift bağlantılı bir liste oluşturmaya çalışalım. Çift bağlantılı bir listenin sınıf modelinin gösterimi Şekil 11'de verilmiştir:

CDoubleList sınıf modeli

Şek. 11 CDoubleList sınıf modeli

Veri üyeleri hiç yokken, alt sınıf çok daha az yöntem içerir. Aşağıda CDoubleList sınıf tanımı verilmiştir.

//+------------------------------------------------------------------+
//|                      CDoubleList class                           |
//+------------------------------------------------------------------+
class CDoubleList : public CiSingleList
  {
public:
   void              CDoubleList(void);                  // default constructor    
   void              CDoubleList(int _node_val);         // parameterized constructor   
   void             ~CDoubleList(void){};                // destructor                  
   virtual bool      SetNodeByIndex(CiSingleNode *_new_node,const uint _idx); // insert the new ith node in the list  

protected:
   virtual bool      AddToEmpty(int _node_val);          // add a node to an empty list
   virtual void      addFront(int _node_val);            // add a new "native" node to the beginning of the list
   virtual void      addRear(int _node_val);             // add a new "native" node to the end of the list 
   virtual int       removeFront(void);                  // delete the "native" head node
   virtual int       removeRear(void);                   // delete the "native" tail node
   virtual void      deleteNodeByIndex(const uint _idx); // delete the "native" ith node from the list
   virtual CiSingleNode *newNode(int _node_val);         // new "native" node
  };

CDoubleList sınıf yöntemlerinin tam açıklaması CDoubleList.mqh içinde verilmiştir.

Genel konuşursak, sanal işlevler burada yalnızca, tek bağlantılı listelerde mevcut olmayan bir önceki düğüme yönelik işaretçinin ihtiyaçlarına hizmet etmek için kullanılır.

CDoubleList türünün listesini kullanma örneği test_dList.mq5 script dosyasında bulunabilir. Bu liste türüyle ilgili tüm yaygın liste işlemlerini gösterir. Script dosyası kodu bir tane garip dize içerir:

CiSingleNode *_new_node=new CDoubleNode(666);     // create a new node of CDoubleNode type

Hata yoktur çünkü temel sınıf işaretçisinin alt sınıfın bir nesnesini tanımladığı durumlarda bu tür yapı oldukça kabul edilebilirdir. Bu, mirasın avantajlarından biridir.

MQL5'te ve С++'da, temel sınıfa yönelik işaretçi, o temel sınıftan türetilen alt sınıfın nesnesine işaret edebilir. Ama tersi geçersizdir.

Dizeyi aşağıdaki gibi yazarsanız:

CDoubleNode*_new_node=new CiSingleNode(666);

derleyici bir hata veya uyarı bildirmez ancak program bu dizeye ulaşana kadar çalışır. Bu durumda, işaretçiler tarafından atıfta bulunulan türlerin yanlış çevrimi hakkında bir mesaj göreceksiniz. Geç bağlama mekanizması yalnızca program çalışırken devreye girdiğinden, sınıflar arasındaki ilişkilerin hiyerarşisini dikkatlice düşünmemiz gerekir.

Script dosyasını çalıştırdıktan sonra günlük aşağıdaki girişleri içerecektir:

DN      0       13:10:57        test_dList (EURUSD,H1)  =======List #1=======
GO      0       13:10:57        test_dList (EURUSD,H1)  Node #1, val=14 
IE      0       13:10:57        test_dList (EURUSD,H1)  Node #2, val=666 
FM      0       13:10:57        test_dList (EURUSD,H1)  Node #3, val=13 
KD      0       13:10:57        test_dList (EURUSD,H1)  Node #4, val=11 
JL      0       13:10:57        test_dList (EURUSD,H1)  
DG      0       13:10:57        test_dList (EURUSD,H1)  
CK      0       13:10:57        test_dList (EURUSD,H1)  =======List #2=======
IL      0       13:10:57        test_dList (EURUSD,H1)  Node #1, val=14 
KH      0       13:10:57        test_dList (EURUSD,H1)  Node #2, val=666 
PR      0       13:10:57        test_dList (EURUSD,H1)  Node #3, val=13 
MI      0       13:10:57        test_dList (EURUSD,H1)  Node #4, val=11 
DO      0       13:10:57        test_dList (EURUSD,H1)  
FR      0       13:10:57        test_dList (EURUSD,H1)  
GK      0       13:10:57        test_dList (EURUSD,H1)  =======renewed List #2=======
PR      0       13:10:57        test_dList (EURUSD,H1)  Node #1, val=11 
QI      0       13:10:57        test_dList (EURUSD,H1)  Node #2, val=13 
QP      0       13:10:57        test_dList (EURUSD,H1)  Node #3, val=14 
LO      0       13:10:57        test_dList (EURUSD,H1)  Node #4, val=34 
JE      0       13:10:57        test_dList (EURUSD,H1)  Node #5, val=35 
HL      0       13:10:57        test_dList (EURUSD,H1)  Node #6, val=36 
FK      0       13:10:57        test_dList (EURUSD,H1)  Node #7, val=37 
DR      0       13:10:57        test_dList (EURUSD,H1)  Node #8, val=38 
FJ      0       13:10:57        test_dList (EURUSD,H1)  Node #9, val=666 
HO      0       13:10:57        test_dList (EURUSD,H1)  
JR      0       13:10:57        test_dList (EURUSD,H1)  

Tek bağlantılı listede olduğu gibi, script dosyası ilk (çift bağlantılı) listeyi doldurdu, kopyaladı ve ikinci listeye geçirdi. Ardından ikinci listedeki düğüm sayısını artırdı, listeyi sıraladı ve yazdırdı.


2.6 Teşhir Edilmiş Çift Bağlantılı Liste

Bu liste türü, yalnızca bir değeri değil, tüm bir diziyi depolamanıza izin verdiği için uygundur.

CiUnrollDoubleList türü listenin temelini atalım (Şekil 12).

CiUnrollDoubleList sınıf modeli

Şek. 12 CiUnrollDoubleList sınıf modeli

Burada bir veri dizisiyle ilgileneceğimiz için CiSingleList dolaylı temel sınıfında tanımlanan yöntemleri yeniden tanımlamamız gerekecek.

CiUnrollDoubleList sınıf tanımı aşağıdadır.

//+------------------------------------------------------------------+
//|                     CiUnrollDoubleList class                     |
//+------------------------------------------------------------------+
class CiUnrollDoubleList : public CDoubleList
  {
public:
   void              CiUnrollDoubleList(void);                      // default constructor
   void              CiUnrollDoubleList(int &_node_arr[]);          // parameterized constructor
   void             ~CiUnrollDoubleList(void){TRACE_CALL(_t_flag)}; // destructor
   //---
   virtual void      AddFront(int &_node_arr[]);                    // add a new node to the beginning of the list
   virtual void      AddRear(int &_node_arr[]);                     // add a new node to the end of the list
   virtual bool      CopyByValue(const CiSingleList &_udList);      // copy by values
   virtual void      PrintList(string _caption=NULL);               // print the list
   virtual void      BubbleSort(void);                              // bubble sorting

protected:
   virtual bool      AddToEmpty(int &_node_arr[]);                  // add a node to an empty list
   virtual void      addFront(int &_node_arr[]);                    // add a new "native" node to the beginning of the list
   virtual void      addRear(int &_node_arr[]);                     // add a new "native" node to the end of the list
   virtual int       removeFront(void);                             // delete the "native" node from the beginning of the list
   virtual int       removeRear(void);                              // delete the "native" node from the end of the list
   virtual void      deleteNodeByIndex(const uint _idx);            // delete the "native" ith node from the list
   virtual CiSingleNode *newNode(int &_node_arr[]);                 // new "native" node
  };

Sınıf yöntemlerinin tam tanımı CiUnrollDoubleList.mqh içinde verilmiştir.

Sınıf yöntemlerinin çalışmasını kontrol etmek için test_UdList.mq5 script dosyasını çalıştıralım. Burada, düğüm işlemleri önceki script dosyalarında kullanılanlara benzerdir. Sıralama ve yazdırma yöntemleri hakkında belki birkaç kelam etmeliyiz. Sıralama yöntemi, düğümleri öğe sayısına göre sıralar, böylece en küçük boyuttaki değerler dizisini içeren düğüm listenin başında olur.

Yazdırma yöntemi, belirli bir düğümde bulunan bir dizi dizesi değeri yazdırır.

Script dosyasını çalıştırdıktan sonra günlükte aşağıdaki girişler olacaktır:

II      0       13:22:23        test_UdList (EURUSD,H1) =======List #1=======
FN      0       13:22:23        test_UdList (EURUSD,H1) List node #1, array: 55, 12, 1, 2, 11, 114, 33, 113, 14, 15, 16, 17, 18, 19, 20
OO      0       13:22:23        test_UdList (EURUSD,H1) List node #2, array: 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
GG      0       13:22:23        test_UdList (EURUSD,H1) 
GP      0       13:22:23        test_UdList (EURUSD,H1) 
GR      0       13:22:23        test_UdList (EURUSD,H1) =======List #2 before sorting=======
JO      0       13:22:23        test_UdList (EURUSD,H1) List node #1, array: 55, 12, 1, 2, 11, 114, 33, 113, 14, 15, 16, 17, 18, 19, 20
CH      0       13:22:23        test_UdList (EURUSD,H1) List node #2, array: 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
CF      0       13:22:23        test_UdList (EURUSD,H1) List node #3, array: -89, -131, -141, -139, -129, -25, -105, -24, -122, -120, -118, -116, -114, -112, -110
GD      0       13:22:23        test_UdList (EURUSD,H1) 
GQ      0       13:22:23        test_UdList (EURUSD,H1) 
LJ      0       13:22:23        test_UdList (EURUSD,H1) =======List #2 after sorting=======
FN      0       13:22:23        test_UdList (EURUSD,H1) List node #1, array: 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
CJ      0       13:22:23        test_UdList (EURUSD,H1) List node #2, array: 55, 12, 1, 2, 11, 114, 33, 113, 14, 15, 16, 17, 18, 19, 20
II      0       13:22:23        test_UdList (EURUSD,H1) List node #3, array: -89, -131, -141, -139, -129, -25, -105, -24, -122, -120, -118, -116, -114, -112, -110
MD      0       13:22:23        test_UdList (EURUSD,H1) 
MQ      0       13:22:23        test_UdList (EURUSD,H1) 

Görüldüğü gibi udList2 listesi sıralandıktan sonra en küçük diziye sahip düğümden başlayarak en büyük diziyi içeren düğüme kadar yazdırılmıştır.


2.7 Dairesel Çift Bağlantılı Liste

Bu makalede doğrusal olmayan listeler ele alınmasa da, onlarla da çalışmamızı öneririm. Düğümleri dairesel olarak nasıl bağlayabileceğiniz yukarıda zaten gösterilmiştir (Şekil 3).

CiCircleDoubleList sınıfı (Şekil 13) için bir model oluşturalım. Bu sınıf, CDoubleList sınıfının alt sınıfı olacaktır.

CiCircleDoubleList sınıf modeli

Şek. 13 CiCircleDoubleList sınıf modeli

Bu listedeki düğümlerin belirli bir karaktere sahip olması nedeniyle (baş ve kuyruk bağlantılıdır), CiSingleList kaynak temel sınıfının neredeyse tüm yöntemlerinin sanal yapılması gerekecektir.

//+------------------------------------------------------------------+
//|                      CiCircleDoubleList class                    |
//+------------------------------------------------------------------+
class CiCircleDoubleList : public CDoubleList
  {
public:
   void              CiCircleDoubleList(void);                       // default constructor
   void              CiCircleDoubleList(int _node_val);              // parameterized constructor
   void             ~CiCircleDoubleList(void){TRACE_CALL(_t_flag)};  // destructor
   //---
   virtual uint      Size(void) const;                                        // list size
   virtual bool      SetNodeByIndex(CiSingleNode *_new_node,const uint _idx); // insert the new ith node in the list
   virtual int       GetValByIndex(const uint _idx) const;           // value of the ith node in the list
   virtual CiSingleNode *GetNodeByIndex(const uint _idx) const;      // get the ith node in the list
   virtual bool      Find(const int _node_val) const;                // find the required value
   virtual bool      CopyByValue(const CiSingleList &_sList);        // copy the list by values

protected:
   virtual void      addFront(int _node_val);                        // add a new "native" node to the beginning of the list
   virtual void      addRear(int _node_val);                         // add a new "native" node to the end of the list
   virtual int       removeFront(void);                              // delete the "native" head node
   virtual int       removeRear(void);                               // delete the "native" tail node
   virtual void      deleteNodeByIndex(const uint _idx);             // delete the "native" ith node from the list

protected:
   void              CalcSize(void) const;                           // calculate the list size
   void              LinkHeadTail(void);                             // link head to tail
  };

Tam sınıf açıklaması CiCircleDoubleList.mqh içinde verilmektedir.

Sınıfın bazı yöntemlerini ele alalım. CiCircleDoubleList::LinkHeadTail() yöntemi, kuyruk düğümünü baş düğüme bağlar. Yeni bir kuyruk veya baş olduğunda ve önceki bağlantı kaybolduğunda çağrılmalıdır.

//+------------------------------------------------------------------+
//|                  Linking head to tail                            |
//+------------------------------------------------------------------+
void CiCircleDoubleList::LinkHeadTail(void)
  {
   TRACE_CALL(_t_flag)
   this.m_head.SetPrevNode(this.m_tail);      // link head to tail
   this.m_tail.SetNextNode(this.m_head);      // link tail to head
  }

Dairesel tek bağlantılı bir listeyle uğraşıyor olsaydık, bu yöntemin nasıl olacağını bir düşünün.

Örneğin CiCircleDoubleList::addFront() yöntemini düşünün.

//+------------------------------------------------------------------+
//|                New "native" node to the beginning of the list    |
//+------------------------------------------------------------------+
void CiCircleDoubleList::addFront(int _node_val)
  {
   TRACE_CALL(_t_flag)
   CDoubleList::addFront(_node_val); // call a similar method of the base class
   this.LinkHeadTail();              // link head and tail
  }

Yöntem gövdesinde, CDoubleList temel sınıfının benzer bir yönteminin çağrıldığını görebilirsiniz. Bu noktada, tek bir şeyden dolayı olmasaydı yöntem işlemini tamamlayabilirdik (burada olduğu gibi yönteme temelde ihtiyaç yoktur). Baş ve kuyruk arasındaki bağlantı kaybolur ve liste onsuz dairesel olarak bağlanamaz. Bu yüzden baş ve kuyruğu birbirine bağlama yöntemini çağırmamız gerekiyor.

Dairesel çift bağlantılı liste ile çalışmak test_UdList.mq5 script dosyasında kontrol edilir.

Görevler ve hedefler açısından, kullanılan diğer yöntemler önceki örneklerle aynıdır.

Sonuç olarak, günlük aşağıdaki girişleri içerir:

PR      0       13:34:29        test_CdList (EURUSD,H1) =======List #1=======
QS      0       13:34:29        test_CdList (EURUSD,H1) Node #1, val=14 
QI      0       13:34:29        test_CdList (EURUSD,H1) Node #2, val=666 
LQ      0       13:34:29        test_CdList (EURUSD,H1) Node #3, val=13 
OH      0       13:34:29        test_CdList (EURUSD,H1) Node #4, val=11 
DP      0       13:34:29        test_CdList (EURUSD,H1) 
DK      0       13:34:29        test_CdList (EURUSD,H1) 
DI      0       13:34:29        test_CdList (EURUSD,H1) =======List #2 before sorting=======
MS      0       13:34:29        test_CdList (EURUSD,H1) Node #1, val=38 
IJ      0       13:34:29        test_CdList (EURUSD,H1) Node #2, val=37 
IQ      0       13:34:29        test_CdList (EURUSD,H1) Node #3, val=36 
EH      0       13:34:29        test_CdList (EURUSD,H1) Node #4, val=35 
EO      0       13:34:29        test_CdList (EURUSD,H1) Node #5, val=34 
FF      0       13:34:29        test_CdList (EURUSD,H1) Node #6, val=14 
DN      0       13:34:29        test_CdList (EURUSD,H1) Node #7, val=666 
GD      0       13:34:29        test_CdList (EURUSD,H1) Node #8, val=13 
JK      0       13:34:29        test_CdList (EURUSD,H1) Node #9, val=11 
JM      0       13:34:29        test_CdList (EURUSD,H1) 
JH      0       13:34:29        test_CdList (EURUSD,H1) 
MS      0       13:34:29        test_CdList (EURUSD,H1) =======List #2 after sorting=======
LE      0       13:34:29        test_CdList (EURUSD,H1) Node #1, val=11 
KL      0       13:34:29        test_CdList (EURUSD,H1) Node #2, val=13 
QS      0       13:34:29        test_CdList (EURUSD,H1) Node #3, val=14 
NJ      0       13:34:29        test_CdList (EURUSD,H1) Node #4, val=34 
NQ      0       13:34:29        test_CdList (EURUSD,H1) Node #5, val=35 
NH      0       13:34:29        test_CdList (EURUSD,H1) Node #6, val=36 
NO      0       13:34:29        test_CdList (EURUSD,H1) Node #7, val=37 
NF      0       13:34:29        test_CdList (EURUSD,H1) Node #8, val=38 
JN      0       13:34:29        test_CdList (EURUSD,H1) Node #9, val=666 
RJ      0       13:34:29        test_CdList (EURUSD,H1) 
RE      0       13:34:29        test_CdList (EURUSD,H1)

Bu nedenle, tanıtılan liste sınıfları arasındaki son kalıtım diyagramı aşağıdaki gibidir (Şekil 14).

Tüm sınıfların miras yoluyla ilişkilendirilmesi gerekip gerekmediğinden emin değilim ama her şeyi olduğu gibi bırakmaya karar verdim.

Liste sınıfları arasında kalıtım

Şek. 14 Liste sınıfları arasında devralma

Özel listelerin tanımını ele alan makalenin bu bölümünün altınaltını çizerken, doğrusal olmayan listeler grubuna, çoklu bağlantılı listelere ve diğerlerine çok az değindiğimizi belirtmek isterim. İlgili bilgileri topladıkça ve bu tür dinamik veri yapıları ile daha fazla deneyim kazandıkça, başka bir makale yazmaya çalışacağım.


3. MQL5 Standart Kitaplığındaki Listeler

Standart Kitaplıkta bulunan liste sınıfına bir göz atalım (Şekil 15).

Veri Sınıflarına aittir.

CList sınıfı modeli

Şek. 15 CList sınıf modeli

İlginçtir ki, CList, CObject sınıfının soyundan gelmektedir. Yani liste, bir düğüm olan sınıfın verilerini ve yöntemlerini devralır.

Liste sınıfı, etkileyici bir dizi yöntem içerir. Dürüst olmak gerekirse Standart Kitaplık'da bu kadar büyük bir sınıf bulmayı beklemiyordum.

CList sınıfı 8 veri üyesine sahiptir. Birkaç şeye dikkat çekmek istiyorum. Sınıf öznitelikleri, geçerli (int m_curr_idx) düğümünün indeksini ve geçerli (CObject* m_curr_node) düğümünün işaretçisini içerir. Listenin "akıllı" olduğu söylenebilir; kontrolün lokalize olduğu yeri gösterebilir. Dahası, bellek yönetim mekanizması (bir düğümü fiziksel olarak silebilir veya basitçe listeden hariç tutabiliriz), sıralı liste bayrağı ve sıralama modu içerir.

Yöntemlerden bahsetmişken, CList sınıfının tüm yöntemleri aşağıdaki gruplara ayrılır:

  • Özellikler;
  • Oluşturma yöntemleri;
  • Ekleme yöntemleri;
  • Silme yöntemleri;
  • Navigasyon;
  • Talimat yöntemleri;
  • Karşılaştırma yöntemleri;
  • Arama yöntemleri;
  • Giriş/Çıkış.

Her zamanki gibi, standart bir oluşturucu ve yok edici vardır.

İlki tüm işaretçileri boşaltır (NULL). Bellek yönetimi bayrak durumu silmeye ayarlı. Yeni liste sıralanmamış olacaktır.

Yıkıcı, gövdesinde düğüm listesini boşaltmak için yalnızca Clear() yöntemini çağırır. Listenin varlığının sonu, mutlaka öğelerinin (düğümlerin) "ölmesini" gerektirmez. Böylece, liste öğeleri silinirken ayarlanan bellek yönetimi bayrağı, sınıf ilişkisini kompozisyondan toplamaya dönüştürür.

Bu bayrağı set- ve get-methods FreeMode() kullanarak işleyebiliriz.

Sınıfta listeyi genişletmenize izin veren iki yöntem vardır: Add() ve Insert(). İlki, makalenin ilk bölümünde kullanılan AddRear() yöntemine benzer. İkinci yöntem, SetNodeByIndex() yöntemine benzer.

Küçük bir örnekle başlayalım. Önce, CObject arabirim sınıfının soyundan gelen bir CNodeInt düğüm sınıfı oluşturmamız gerekiyor. Tamsayı türünün değerini depolayacaktır.

//+------------------------------------------------------------------+
//|                        CNodeInt class                            |
//+------------------------------------------------------------------+
class  CNodeInt : public CObject
  {
private:
   int               m_val;  // node data

public:
   void              CNodeInt(void){this.m_val=WRONG_VALUE;}; // default constructor
   void              CNodeInt(int _val);                      // parameterized constructor
   void             ~CNodeInt(void){};                        // destructor
   int               GetVal(void){return this.m_val;};        // get-method for node data
   void              SetVal(int _val){this.m_val=_val;};      // set-method for node data
  };
//+------------------------------------------------------------------+
//|                    Parameterized constructor                     |
//+------------------------------------------------------------------+
void CNodeInt::CNodeInt(int _val):m_val(_val)
  {

  };

test_MQL5_List.mq5 script dosyasındaki CList listesiyle çalışacağız.

Örnek 1, liste ve düğümlerin dinamik bir şekilde oluşturulmasını gösterir. Liste daha sonra düğümlerle doldurulur ve liste silinmeden önce ve sonra ilk düğümün değeri kontrol edilir.

//--- Example 1 (testing memory management)
   CList *myList=new CList;
// myList.FreeMode(false);  // reset flag
   bool _free_mode=myList.FreeMode();
   PrintFormat("\nList \"myList\" - memory management flag: %d",_free_mode);
   CNodeInt *p_new_nodes_int[10];
   p_new_nodes_int[0]=NULL;
   for(int i=0;i<ArraySize(p_new_nodes_int);i++)
     {
      p_new_nodes_int[i]=new CNodeInt(rand());
      myList.Add(p_new_nodes_int[i]);
     }
   PrintFormat("List \"myList\" has as many nodes as: %d",myList.Total());
   Print("=======Before deleting \"myList\"=======");
   PrintFormat("The 1st node value is: %d",p_new_nodes_int[0].GetVal());
   delete myList;
   int val_to_check=WRONG_VALUE;
   if(CheckPointer(p_new_nodes_int[0]))
      val_to_check=p_new_nodes_int[0].GetVal();
   Print("=======After deleting \"myList\"=======");
   PrintFormat("The 1st node value is: %d",val_to_check);

Bayrağı sıfırlayan dize derleme dışı bırakılırsa (etkin değil), günlükte aşağıdaki girişleri alırız:

GS      0       14:00:16        test_MQL5_List (EURUSD,H1)      
EO      0       14:00:16        test_MQL5_List (EURUSD,H1)      List "myList" - memory management flag: 1
FR      0       14:00:16        test_MQL5_List (EURUSD,H1)      List "myList" has as many nodes as: 10
JH      0       14:00:16        test_MQL5_List (EURUSD,H1)      =======Before deleting "myList"=======
DO      0       14:00:16        test_MQL5_List (EURUSD,H1)      The 1st node value is: 7189
KJ      0       14:00:16        test_MQL5_List (EURUSD,H1)      =======After deleting "myList"=======
QK      0       14:00:16        test_MQL5_List (EURUSD,H1)      The 1st node value is: -1

Lütfen myList listesini dinamik olarak sildikten sonra, içindeki tüm düğümlerin de bellekten silindiğini unutmayın.

Ancak, sıfırlama bayrağı dizesini kaldırırsak

// myList.FreeMode(false); // reset flag

günlüğün çıktısı aşağıdaki gibi olacaktır:

NS      0       14:02:11        test_MQL5_List (EURUSD,H1)      
CN      0       14:02:11        test_MQL5_List (EURUSD,H1)      List "myList" - memory management flag: 0
CS      0       14:02:11        test_MQL5_List (EURUSD,H1)      List "myList" has as many nodes as: 10
KH      0       14:02:11        test_MQL5_List (EURUSD,H1)      =======Before deleting "myList"=======
NL      0       14:02:11        test_MQL5_List (EURUSD,H1)      The 1st node value is: 20411
HJ      0       14:02:11        test_MQL5_List (EURUSD,H1)      =======After deleting "myList"=======
LI      0       14:02:11        test_MQL5_List (EURUSD,H1)      The 1st node value is: 20411
QQ      1       14:02:11        test_MQL5_List (EURUSD,H1)      10 undeleted objects left
DD      1       14:02:11        test_MQL5_List (EURUSD,H1)      10 objects of type CNodeInt left
DL      1       14:02:11        test_MQL5_List (EURUSD,H1)      400 bytes of leaked memory

Baş düğümün, liste silindikten önceki ve sonra olan değerini koruduğunu fark etmek kolaydır. Bu durumda, script dosyası bunları doğru şekilde silmek için kod içermiyorsa, silinmemiş nesneler de kalacaktır.

Şimdi sıralama yöntemiyle çalışmayı deneyelim.

//--- Example 2 (sorting)

   CList *myList=new CList;
   CNodeInt *p_new_nodes_int[10];
   p_new_nodes_int[0]=NULL;
   for(int i=0;i<ArraySize(p_new_nodes_int);i++)
     {
      p_new_nodes_int[i]=new CNodeInt(rand());
      myList.Add(p_new_nodes_int[i]);
     }
   PrintFormat("\nList \"myList\" has as many nodes as: %d",myList.Total());
   Print("=======List \"myList\" before sorting=======");
   for(int i=0;i<myList.Total();i++)
     {
      CNodeInt *p_node_int=myList.GetNodeAtIndex(i);
      int node_val=p_node_int.GetVal();
      PrintFormat("Node #%d is equal to: %d",i+1,node_val);
     }
   myList.Sort(0);
   Print("\n=======List \"myList\" after sorting=======");
   for(int i=0;i<myList.Total();i++)
     {
      CNodeInt *p_node_int=myList.GetNodeAtIndex(i);
      int node_val=p_node_int.GetVal();
      PrintFormat("Node #%d is equal to: %d",i+1,node_val);
     }
   delete myList;

Sonuç olarak, günlük aşağıdaki girişleri içerir:

OR      0       22:47:01        test_MQL5_List (EURUSD,H1)      
FN      0       22:47:01        test_MQL5_List (EURUSD,H1)      List "myList" has as many nodes as: 10
FH      0       22:47:01        test_MQL5_List (EURUSD,H1)      =======List "myList" before sorting=======
LG      0       22:47:01        test_MQL5_List (EURUSD,H1)      Node #1 is equal to: 30511
CO      0       22:47:01        test_MQL5_List (EURUSD,H1)      Node #2 is equal to: 17404
GF      0       22:47:01        test_MQL5_List (EURUSD,H1)      Node #3 is equal to: 12215
KQ      0       22:47:01        test_MQL5_List (EURUSD,H1)      Node #4 is equal to: 31574
NJ      0       22:47:01        test_MQL5_List (EURUSD,H1)      Node #5 is equal to: 7285
HP      0       22:47:01        test_MQL5_List (EURUSD,H1)      Node #6 is equal to: 23509
IH      0       22:47:01        test_MQL5_List (EURUSD,H1)      Node #7 is equal to: 26991
NS      0       22:47:01        test_MQL5_List (EURUSD,H1)      Node #8 is equal to: 414
MK      0       22:47:01        test_MQL5_List (EURUSD,H1)      Node #9 is equal to: 18824
DR      0       22:47:01        test_MQL5_List (EURUSD,H1)      Node #10 is equal to: 1560
OR      0       22:47:01        test_MQL5_List (EURUSD,H1)      
OM      0       22:47:01        test_MQL5_List (EURUSD,H1)      =======List "myList" after sorting=======
QM      0       22:47:01        test_MQL5_List (EURUSD,H1)      Node #1 is equal to: 26991
RE      0       22:47:01        test_MQL5_List (EURUSD,H1)      Node #2 is equal to: 23509
ML      0       22:47:01        test_MQL5_List (EURUSD,H1)      Node #3 is equal to: 18824
DD      0       22:47:01        test_MQL5_List (EURUSD,H1)      Node #4 is equal to: 414
LL      0       22:47:01        test_MQL5_List (EURUSD,H1)      Node #5 is equal to: 1560
IG      0       22:47:01        test_MQL5_List (EURUSD,H1)      Node #6 is equal to: 17404
PN      0       22:47:01        test_MQL5_List (EURUSD,H1)      Node #7 is equal to: 30511
II      0       22:47:01        test_MQL5_List (EURUSD,H1)      Node #8 is equal to: 31574
OQ      0       22:47:01        test_MQL5_List (EURUSD,H1)      Node #9 is equal to: 12215
JH      0       22:47:01        test_MQL5_List (EURUSD,H1)      Node #10 is equal to: 7285

Herhangi bir sıralama yapılmış olsa bile, sıralama tekniği benim için bir sır olarak kaldı. Nedenini açıklayacağım. Çağrı sırası ile ilgili fazla ayrıntıya girmeden, CList::Sort() yöntemi, bir temel sınıfta herhangi bir şekilde uygulanmayan CObject::Compare() sanal yöntemini çağırır. Bu nedenle, programcı bir sıralama yönteminin uygulanmasıyla kendi başına uğraşmak zorundadır.

Ve şimdi, Total() yöntemi hakkında birkaç kelam. m_data_total veri üyesinin sorumlu olduğu öğelerin (düğümlerin) sayısını verir. Çok kısa ve öz bir yöntemdir. Bu uygulamada öğe sayısı, daha önce önerdiğimden çok daha hızlı olacaktır. Gerçekten de, neden her zaman listeden geçer ve düğümleri sayar, oysa listedeki tam düğüm sayısı düğüm eklenirken veya silinirken ayarlanabilir.

Örnek 3, CList ve CiSingleList türündeki listelerin doldurulma hızını karşılaştırır ve her bir listenin boyutunu alma süresini hesaplar.

//--- Example 3 (nodes number)

   int iterations=1e7;   // 10 million iterations
//--- the new CList 
   CList *p_mql_List=new CList;
   uint start=GetTickCount(); // starting value
   for(int i=0;i<iterations;i++)
     {
      CNodeInt *p_node_int=new CNodeInt(rand());
      p_mql_List.Add(p_node_int);
     }
   uint time=GetTickCount()-start; // time spent, msec
   Print("\n=======the CList type list=======");
   PrintFormat("Filling the list of %.3e nodes has taken %d msec",iterations,time);
//--- get the size
   start=GetTickCount();
   int list_size=p_mql_List.Total(); 
   time=GetTickCount()-start;
   PrintFormat("Getting the size of the list has taken %d msec",time);

   delete p_mql_List;

//---  the new CiSingleList 
   CiSingleList *p_sList=new CiSingleList;

   start=GetTickCount(); // starting value
   for(int i=0;i<iterations;i++)
      p_sList.AddRear(rand());
   time=GetTickCount()-start; // time spent, msec
   Print("\n=======the CiSingleList type list=======");
   PrintFormat("Filling the list of %.3e nodes has taken %d msec",iterations,time);
//--- get the size
   start=GetTickCount();
   list_size=(int)p_sList.Size();  
   time=GetTickCount()-start;
   PrintFormat("Getting the size of the list has taken %d msec",time);
   delete p_sList;   

Günlükte şu var:

KO      0       22:48:24        test_MQL5_List (EURUSD,H1)      
CK      0       22:48:24        test_MQL5_List (EURUSD,H1)      =======the CList type list=======
JL      0       22:48:24        test_MQL5_List (EURUSD,H1)      Filling the list of 1.000e+007 nodes has taken 2606 msec
RO      0       22:48:24        test_MQL5_List (EURUSD,H1)      Getting the size of the list has taken 0 msec
LF      0       22:48:29        test_MQL5_List (EURUSD,H1)      
EL      0       22:48:29        test_MQL5_List (EURUSD,H1)      =======the CiSingleList type list=======
KK      0       22:48:29        test_MQL5_List (EURUSD,H1)      Filling the list of 1.000e+007 nodes has taken 2356 msec
NF      0       22:48:29        test_MQL5_List (EURUSD,H1)      Getting the size of the list has taken 359 msec

Boyutu alma yöntemi, CList listesinde anında çalışır. Bu arada, listeye düğüm eklemek de oldukça hızlı.

Bir sonraki blokta (Örnek 4), listenin bir veri kapsayıcı olarak en önemli dezavantajlarından birine, öğelere erişim hızına dikkat etmenizi öneriyorum. Mesele şu ki, liste öğelerine doğrusal olarak erişiliyor. CList sınıfında, bunlara ikili bir şekilde erişilir, bu da algoritma zahmetini biraz azaltır.

Doğrusal olarak arama yaparken, zahmet O(N) olur. İkili bir şekilde uygulanan bir arama, log2(N)'nin zahmetli olmasına neden olur.

Bu, bir veri kümesinin öğelerine erişim kodunun bir örneğidir:

//--- Example 4 (speed of accessing the node)

   const uint Iter_arr[]={1e3,3e3,6e3,9e3,1e4,3e4,6e4,9e4,1e5,3e5,6e5};
   for(uint i=0;i<ArraySize(Iter_arr);i++)
     {
      const uint cur_iterations=Iter_arr[i]; // iterations number     
      uint randArr[];                        // array of random numbers
      uint idxArr[];                         // array of indexes
      //--- set the arrays size    
      ArrayResize(randArr,cur_iterations);
      ArrayResize(idxArr,cur_iterations);
      CRandom myRand;                        // random number generator
      //--- fill the array of random numbers
      for(uint t=0;t<cur_iterations;t++)
         randArr[t]=myRand.int32();
      //--- fill the array of indexes with random numbers (from 0 to 10 million)
      int iter_log10=(int)log10(cur_iterations);
      for(uint r=0;r<cur_iterations;r++)
        {
         uint rand_val=myRand.int32(); // random value (from 0 to 4 294 967 295)
         if(rand_val>=cur_iterations)
           {
            int val_log10=(int)log10(rand_val);
            double log10_remainder=val_log10-iter_log10;
            rand_val/=(uint)pow(10,log10_remainder+1);
           }
         //--- check the limit
         if(rand_val>=cur_iterations)
           {
            Alert("Random value error!");
            return;
           }
         idxArr[r]=rand_val;
        }
      //--- time spent for the array
      uint start=GetTickCount();
      //--- accessing the array elements 
      for(uint p=0;p<cur_iterations;p++)
         uint random_val=randArr[idxArr[p]];

      uint time=GetTickCount()-start; // time spent, msec
      Print("\n=======the uint type array=======");
      PrintFormat("Random accessing the array of elements %.1e has taken %d msec",cur_iterations,time);

      //--- the CList type list
      CList *p_mql_List=new CList;
      //--- fill the list
      for(uint q=0;q<cur_iterations;q++)
        {
         CNodeInt *p_node_int=new CNodeInt(randArr[q]);
         p_mql_List.Add(p_node_int);
        }
      start=GetTickCount();
      //--- accessing the list nodes
      for(uint w=0;w<cur_iterations;w++)
         CNodeInt *p_node_int=p_mql_List.GetNodeAtIndex(idxArr[w]);
      time=GetTickCount()-start; // time spent, msec
      Print("\n=======the CList type list=======");
      PrintFormat("Random accessing the list of nodes %.1e has taken %d msec",cur_iterations,time);

      //--- free the memory
      ArrayFree(randArr);
      ArrayFree(idxArr);
      delete p_mql_List;
     }

Blok işlemi sonuçlarına göre, aşağıdaki girişler günlüğe yazdırıldı: 

MR      0       22:51:22        test_MQL5_List (EURUSD,H1)      
QL      0       22:51:22        test_MQL5_List (EURUSD,H1)      =======the uint type array=======
IG      0       22:51:22        test_MQL5_List (EURUSD,H1)      Random accessing the array of elements 1.0e+003 has taken 0 msec
QF      0       22:51:22        test_MQL5_List (EURUSD,H1)      
IQ      0       22:51:22        test_MQL5_List (EURUSD,H1)      =======the CList type list=======
JK      0       22:51:22        test_MQL5_List (EURUSD,H1)      Random accessing the list of nodes 1.0e+003 has taken 0 msec
MJ      0       22:51:22        test_MQL5_List (EURUSD,H1)      
QD      0       22:51:22        test_MQL5_List (EURUSD,H1)      =======the uint type array=======
GO      0       22:51:22        test_MQL5_List (EURUSD,H1)      Random accessing the array of elements 3.0e+003 has taken 0 msec
QN      0       22:51:22        test_MQL5_List (EURUSD,H1)      
II      0       22:51:22        test_MQL5_List (EURUSD,H1)      =======the CList type list=======
EP      0       22:51:22        test_MQL5_List (EURUSD,H1)      Random accessing the list of nodes 3.0e+003 has taken 16 msec
OR      0       22:51:22        test_MQL5_List (EURUSD,H1)      
OL      0       22:51:22        test_MQL5_List (EURUSD,H1)      =======the uint type array=======
FG      0       22:51:22        test_MQL5_List (EURUSD,H1)      Random accessing the array of elements 6.0e+003 has taken 0 msec
CF      0       22:51:22        test_MQL5_List (EURUSD,H1)      
GQ      0       22:51:22        test_MQL5_List (EURUSD,H1)      =======the CList type list=======
CH      0       22:51:22        test_MQL5_List (EURUSD,H1)      Random accessing the list of nodes 6.0e+003 has taken 31 msec
QJ      0       22:51:22        test_MQL5_List (EURUSD,H1)      
MD      0       22:51:22        test_MQL5_List (EURUSD,H1)      =======the uint type array=======
MO      0       22:51:22        test_MQL5_List (EURUSD,H1)      Random accessing the array of elements 9.0e+003 has taken 0 msec
EN      0       22:51:22        test_MQL5_List (EURUSD,H1)      
MJ      0       22:51:22        test_MQL5_List (EURUSD,H1)      =======the CList type list=======
CP      0       22:51:22        test_MQL5_List (EURUSD,H1)      Random accessing the list of nodes 9.0e+003 has taken 47 msec
CR      0       22:51:22        test_MQL5_List (EURUSD,H1)      
KL      0       22:51:22        test_MQL5_List (EURUSD,H1)      =======the uint type array=======
JG      0       22:51:22        test_MQL5_List (EURUSD,H1)      Random accessing the array of elements 1.0e+004 has taken 0 msec
GF      0       22:51:22        test_MQL5_List (EURUSD,H1)      
KR      0       22:51:22        test_MQL5_List (EURUSD,H1)      =======the CList type list=======
MK      0       22:51:22        test_MQL5_List (EURUSD,H1)      Random accessing the list of nodes 1.0e+004 has taken 343 msec
GJ      0       22:51:22        test_MQL5_List (EURUSD,H1)      
GG      0       22:51:22        test_MQL5_List (EURUSD,H1)      =======the uint type array=======
LO      0       22:51:22        test_MQL5_List (EURUSD,H1)      Random accessing the array of elements 3.0e+004 has taken 0 msec
QO      0       22:51:24        test_MQL5_List (EURUSD,H1)      
MJ      0       22:51:24        test_MQL5_List (EURUSD,H1)      =======the CList type list=======
NP      0       22:51:24        test_MQL5_List (EURUSD,H1)      Random accessing the list of nodes 3.0e+004 has taken 1217 msec
OS      0       22:51:24        test_MQL5_List (EURUSD,H1)      
KO      0       22:51:24        test_MQL5_List (EURUSD,H1)      =======the uint type array=======
CP      0       22:51:24        test_MQL5_List (EURUSD,H1)      Random accessing the array of elements 6.0e+004 has taken 0 msec
MG      0       22:51:26        test_MQL5_List (EURUSD,H1)      
ER      0       22:51:26        test_MQL5_List (EURUSD,H1)      =======the CList type list=======
PG      0       22:51:26        test_MQL5_List (EURUSD,H1)      Random accessing the list of nodes 6.0e+004 has taken 2387 msec
GK      0       22:51:26        test_MQL5_List (EURUSD,H1)      
OG      0       22:51:26        test_MQL5_List (EURUSD,H1)      =======the uint type array=======
NH      0       22:51:26        test_MQL5_List (EURUSD,H1)      Random accessing the array of elements 9.0e+004 has taken 0 msec
JO      0       22:51:30        test_MQL5_List (EURUSD,H1)      
NK      0       22:51:30        test_MQL5_List (EURUSD,H1)      =======the CList type list=======
KO      0       22:51:30        test_MQL5_List (EURUSD,H1)      Random accessing the list of nodes 9.0e+004 has taken 3619 msec
HS      0       22:51:30        test_MQL5_List (EURUSD,H1)      
DN      0       22:51:30        test_MQL5_List (EURUSD,H1)      =======the uint type array=======
RP      0       22:51:30        test_MQL5_List (EURUSD,H1)      Random accessing the array of elements 1.0e+005 has taken 0 msec
OD      0       22:52:05        test_MQL5_List (EURUSD,H1)      
GS      0       22:52:05        test_MQL5_List (EURUSD,H1)      =======the CList type list=======
DE      0       22:52:05        test_MQL5_List (EURUSD,H1)      Random accessing the list of nodes 1.0e+005 has taken 35631 msec
NH      0       22:52:06        test_MQL5_List (EURUSD,H1)      
RF      0       22:52:06        test_MQL5_List (EURUSD,H1)      =======the uint type array=======
FI      0       22:52:06        test_MQL5_List (EURUSD,H1)      Random accessing the array of elements 3.0e+005 has taken 0 msec
HL      0       22:54:20        test_MQL5_List (EURUSD,H1)      
PD      0       22:54:20        test_MQL5_List (EURUSD,H1)      =======the CList type list=======
FN      0       22:54:20        test_MQL5_List (EURUSD,H1)      Random accessing the list of nodes 3.0e+005 has taken 134379 msec
RQ      0       22:54:20        test_MQL5_List (EURUSD,H1)      
JI      0       22:54:20        test_MQL5_List (EURUSD,H1)      =======the uint type array=======
MR      0       22:54:20        test_MQL5_List (EURUSD,H1)      Random accessing the array of elements 6.0e+005 has taken 15 msec
NE      0       22:58:48        test_MQL5_List (EURUSD,H1)      
FL      0       22:58:48        test_MQL5_List (EURUSD,H1)      =======the CList type list=======
GE      0       22:58:48        test_MQL5_List (EURUSD,H1)      Random accessing the list of nodes 6.0e+005 has taken 267589 msec

Liste boyutu büyüdükçe liste öğelerine rastgele erişimin daha fazla zaman aldığını görebilirsiniz (Şekil 16).

Dizi ve liste öğelerine rastgele erişim için harcanan süre

Şek. 16 Dizi ve liste öğelerine rastgele erişim için harcanan süre

Şimdi verileri kaydetme ve yükleme yöntemlerini ele alalım.

Temel liste sınıfı CList bu tür yöntemleri içerir ancak bunlar sanaldır. Bu nedenle, bir örnek kullanarak çalışmalarını test etmek için biraz hazırlık yapmamız gerekiyor.

CIntList alt sınıfını kullanarak CList sınıfı yeteneklerini devralmalıyız. İkincisi, yeni bir CIntList::CreateElement() öğesi oluşturmak için yalnızca 1 yönteme sahip olacaktır.

//+------------------------------------------------------------------+
//|                      CIntList class                              |
//+------------------------------------------------------------------+
class CIntList : public CList
  {

public:
   virtual CObject *CreateElement(void);
  };
//+------------------------------------------------------------------+
//|                    New element of the list                       |
//+------------------------------------------------------------------+
CObject *CIntList::CreateElement(void)
  {
   CObject *new_node=new CNodeInt();
   return new_node;
  }

Ayrıca CNodeInt::Save() ve CNodeInt::Load() sanal yöntemlerini CNodeInt türetilmiş düğüm türüne eklememiz gerekecek. Bunlar, sırasıyla CList::Save() ve CList::Load() üye işlevlerinden çağrılacak.

Sonuç olarak örnek aşağıdaki gibi olacaktır (Örnek 5):

//--- Example 5 (saving list data)
//--- the CIntList type list
   CList *p_int_List=new CIntList;
   int randArr[1000];                        // array of random numbers
   ArrayInitialize(randArr,0);
//--- fill the array of random numbers 
   for(int t=0;t<1000;t++)
      randArr[t]=(int)myRand.int32();
//--- fill the list
   for(uint q=0;q<1000;q++)
     {
      CNodeInt *p_node_int=new CNodeInt(randArr[q]);
      p_int_List.Add(p_node_int);
     }
//--- save the list to the file 
   int  file_ha=FileOpen("List_data.bin",FILE_WRITE|FILE_BIN);
   p_int_List.Save(file_ha);
   FileClose(file_ha);             
   p_int_List.FreeMode(true);    
   p_int_List.Clear();           
//--- load the list from the file  
   file_ha=FileOpen("List_data.bin",FILE_READ|FILE_BIN);
   p_int_List.Load(file_ha);
   int Loaded_List_size=p_int_List.Total();
   PrintFormat("Nodes loaded from the file: %d",Loaded_List_size);
//--- free the memory     
   delete p_int_List;

Script dosyasını grafikte çalıştırdıktan sonra, Günlüğe aşağıdaki giriş eklenecektir:

ND      0       11:59:35        test_MQL5_List (EURUSD,H1)      As many as 1000 nodes loaded from the file.

Böylece, CNodeInt düğüm türünün bir veri üyesi için giriş/çıkış yöntemlerinin uygulanmasını görmüş olduk.

Bir sonraki bölümde, MQL5 ile çalışırken sorunları çözmek için listelerin nasıl kullanılabileceğine dair örnekler göreceğiz.


4. MQL5'te Liste Kullanım Örnekleri

Bir önceki bölümde Standard Kitaplık sınıfı CList yöntemlerini ele alırken birkaç örnek vermiştim.

Şimdi, belirli bir sorunu çözmek için listenin kullanıldığı durumları ele alacağım. Burada bir kapsayıcı veri türü olarak listenin faydasını bir kez daha belirtmekten geçemeyeceğim. Bir listenin esnekliğinden yararlanarak kodla çalışmayı daha verimli hale getirebiliriz.


4.1 Grafik Nesneleri İşleme

Grafikte programlı olarak grafik nesneler oluşturmamız gerektiğini hayal edin. Bunlar, çeşitli nedenlerle grafikte görünebilecek farklı nesneler olabilir.

Zamanında, listenin bir meseleyi grafik nesnelerle çözmeme nasıl yardımcı olduğunu hatırlıyorum. Bu hatıramı sizinle paylaşmak istiyorum.

Belirtilen koşula göre dikey çizgiler oluşturma görevim vardı. Koşula göre, dikey çizgiler, uzunlukları duruma göre değişen belirli bir zaman aralığı için sınır görevi gördü. Bununla birlikte, aralık her zaman oluşmuş durumda değildi.

EMA21'in davranışını inceliyordum ve bu amaçla istatistik toplamam gerekiyordu.

Özellikle hareketli ortalamanın eğiminin uzunluğuyla ilgileniyordum. Örneğin, aşağı doğru bir harekette, dikey bir çizgi çizilen hareketli ortalamanın negatif hareketi (yani değer düşüşü) kaydedilerek başlangıç noktası belirlendi. Şekil 17, bir mum grafiğinin açılması üzerine EURUSD, H1 için 5 Eylül 2013 16:00 olarak tanımlanan bu noktayı göstermektedir.

Şek. 17 Aşağı doğru aralığın ilk noktası

Şek. 17 Aşağı doğru aralığın ilk noktası


Aşağı yönlü hareketin sona erdiğini gösteren ikinci nokta, ters ilkeye dayalı olarak; hareketli ortalamanın pozitif bir hareketinin, yani değer artışının kaydedilmesiyle belirlendi (Şekil 18).


Şek. 18 Aşağı doğru aralığın ikinci noktası

Şek. 18 Aşağı doğru aralığın ikinci noktası


Bu nedenle, hedef aralığı 5 Eylül 2013 16:00 ile 6 Eylül 2013 17:00 arasındaydı.

Farklı aralıkların tanımlanması için sistem daha karmaşık veya daha basit olabilir. Konu bu değil. Önemli olan, grafik nesnelerle çalışmak ve eşzamanlı olarak istatistiksel veri toplamak için bu tekniğin, listenin en önemli avantajlarından birini; kompozisyon esnekliğini içermesidir.

Mevcut örneğe gelince, önce 2 grafik "Dikey çizgi" nesnesinden sorumlu CVertLineNode türünde bir düğüm oluşturdum.

Sınıf tanımı aşağıdaki gibidir:

//+------------------------------------------------------------------+
//|                      CVertLineNode class                         |
//+------------------------------------------------------------------+
class CVertLineNode : public CObject
  {
private:
   SVertLineProperties m_vert_lines[2];      // array of structures of vertical line properties
   uint              m_duration;             // frame duration
   bool              m_IsFrameFormed;        // flag of frame formation

public:
   void              CVertLineNode(void);
   void             ~CVertLineNode(void){};
   //--- set-methods   
   void              SetLine(const SVertLineProperties &_vert_line,bool IsFirst=true);
   void              SetDuration(const uint _duration){this.m_duration=_duration;};
   void              SetFrameFlag(const bool _frame_flag){this.m_IsFrameFormed=_frame_flag;};
   //--- get-methods   
   void              GetLine(SVertLineProperties &_vert_line_out,bool IsFirst=true) const;
   uint              GetDuration(void) const;
   bool              GetFrameFlag(void) const;
   //--- draw the line
   bool              DrawLine(bool IsFirst=true) const;
  };

Temel olarak, bu düğüm sınıfı bir çerçeveyi tanımlar (burada iki dikey çizgiyle sınırlandırılmış bir dizi mum grafik olarak yorumlanır). Çerçeve sınırları, dikey çizgi özellikleri, süre ve oluşum bayrağının birkaç yapısı ile temsil edilir.

Standart oluşturucu ve yıkıcı dışında, sınıf, grafikte çizgi çizme yönteminin yanı sıra birkaç set-ve get- yöntemine de sahiptir.

Hatırlatmama izin verin, örneğimdeki dikey çizgiler (çerçeve) düğümü, aşağı hareketin başlangıcını gösteren birinci dikey çizgi ve yukarı hareketin başlangıcını gösteren ikinci dikey çizgi olduğunda oluşmuş sayılabilir.

Stat_collector.mq5 script dosyasını kullanarak, grafikteki tüm çerçeveleri görüntüledim ve son 2 bin çubukta kaç düğümün (çerçeve) belirli bir süre sınırına karşılık geldiğini saydım.

Örnek olarak, herhangi bir çerçeveyi içerebilecek 4 liste oluşturdum. İlk liste, 5'e kadar mum grafik sayısı; ikincisi 10'a kadar; üçüncüsü 15'e kadar ve dördüncüsü sınırsız sayıda çerçeve içeriyordu. 

NS      0       15:27:32        Stat_collector (EURUSD,H1)      =======List #1=======
RF      0       15:27:32        Stat_collector (EURUSD,H1)      Duration limit: 5
ML      0       15:27:32        Stat_collector (EURUSD,H1)      Nodes number: 65
HK      0       15:27:32        Stat_collector (EURUSD,H1)      
OO      0       15:27:32        Stat_collector (EURUSD,H1)      =======List #2=======
RI      0       15:27:32        Stat_collector (EURUSD,H1)      Duration limit: 10
NP      0       15:27:32        Stat_collector (EURUSD,H1)      Nodes number: 15
RG      0       15:27:32        Stat_collector (EURUSD,H1)      
FH      0       15:27:32        Stat_collector (EURUSD,H1)      =======List #3=======
GN      0       15:27:32        Stat_collector (EURUSD,H1)      Duration limit: 15
FG      0       15:27:32        Stat_collector (EURUSD,H1)      Nodes number: 6
FR      0       15:27:32        Stat_collector (EURUSD,H1)      
CD      0       15:27:32        Stat_collector (EURUSD,H1)      =======List #4=======
PS      0       15:27:32        Stat_collector (EURUSD,H1)      Nodes number: 20

Sonuç olarak aşağıdaki grafiği elde ettim (Şekil 19). Kolaylık sağlamak için ikinci dikey çerçeve çizgisi mavi renkte görüntülenir.


Şek. 19 Çerçeveleri görüntüleme

İlginçtir ki, son çerçeve 13 Aralık 2013 Cuma gününün son saatinde oluşturuldu. Süresi 6 saat olduğu için ikinci listenin altına düştü.


4.2 Sanal Alım Satımla Başa Çıkma

Bir tik akışında tek bir enstrümana göre birkaç bağımsız strateji uygulayacak bir Expert Advisor yaratmanız gerektiğini hayal edin. Gerçekte, tek bir enstrümanla ilgili olarak aynı anda yalnızca bir stratejinin uygulanabileceği açıktır. Diğer tüm stratejiler sanal nitelikte olacaktır. Bu nedenle, yalnızca bir alım satım fikrini test etmek ve optimize etmek amacıyla uygulanabilir.

Burada, genel olarak alım satımla ve özellikle MetaTrader 5 terminaliyle ilgili temel kavramların ayrıntılı bir açıklamasını sağlayan temel bir makaleye atıfta bulunmam gerekiyor: "MetaTrader 5'te Talimatlar, Pozisyonlar ve Yatırımlar".

Dolayısıyla, bu sorunu çözerken, alım satım konseptini, alım satım nesnesi yönetim sistemini ve MetaTrader 5 ortamında alışılmış olan alım satım nesneleri hakkında bilgi depolama metodolojisini kullanırsak, muhtemelen sanal bir veritabanı oluşturmayı düşünmeliyiz.

Bir geliştiricinin tüm alım satım nesnelerini talimatlar, pozisyonlar, yatırımlar ve geçmiş talimatlar olarak sınıflandırdığını hatırlatmama izin verin. Eleştirel bir göz, "alım satım nesnesi" teriminin burada yazarın kendisi tarafından kullanıldığını fark edebilir. Bu doğru...

Sanal alım satım dabenzer bir yaklaşım kullanmayı ve şu sanal alım satım nesnelerini almayı öneriyorum: sanal talimatlar, sanal pozisyonlar, sanal yatırımlar ve sanal geçmiş talimatlar.

Bu konunun derinlemesine ve daha detaylı bir tartışmaya değer olduğuna inanıyorum. Bu arada makalenin konusuna dönersek, listeler de dahil olmak üzere kapsayıcı veri türlerinin sanal stratejileri uygularken programcının hayatını kolaylaştırabileceğini söylemek isterim.

Doğal olarak alım satım sunucusu tarafında olamayacak yeni bir sanal pozisyon düşünün. Bu, onunla ilgili bilgilerin terminal tarafında kaydedilmesi gerektiği anlamına gelir. Burada, bir veritabanı, bir tanesi sanal pozisyonun düğümlerini içerecek olan birkaç listeden oluşan bir liste ile temsil edilebilir.

Geliştiricinin yaklaşımını kullanarak, aşağıdaki sanal alım satım sınıfları olacaktır:

Sınıf/Grup

Açıklama

CSanalTalimat

sanal bekleyen talimatlarla çalışma sınıfı

CVirtualHistoryOrder

sanal "geçmiş" talimatlarla çalışma sınıfı

CSanalPozisyon

sanal açık pozisyonlarla çalışma sınıfı

CVirtualYatırım

sanal "geçmiş" yatırımlarla çalışma sınıfı

CSanallAlım Satım

sanal alım satım işlemlerini gerçekleştirme sınıfı

Tablo 1. Sanal alım satım sınıfları


Sanal alım satım sınıflarından herhangi birinin bileşimini tartışmayacağım. Ancak muhtemelen standart bir alım satım sınıfının tüm veya neredeyse tüm yöntemlerini içerecektir. Sadece, geliştiricinin kullandığı şeyin, belirli bir alım satım nesnesinin kendisinin bir sınıfı değil, özelliklerinin bir sınıfı olduğunu belirtmek isterim.

Algoritmalarınızda listeleri kullanmak için düğümlere de ihtiyacınız olacak. Bu nedenle, bir sanal alım satım nesnesinin sınıfını bir düğümde tamamlamamız gerekiyor.

Bir sanal açılış pozisyonu düğümünün CVirtualPositionNode türünde olduğunu varsayalım. Bu türün tanımı başlangıçta aşağıdaki gibi olabilir:

//+------------------------------------------------------------------+
//|                Class CVirtualPositionNode                        |
//+------------------------------------------------------------------+
class CVirtualPositionNode : public CObject
  {
protected:
   CVirtualPositionNode *m_virt_position;         // pointer to the virtual function

public:
   void              CVirtualPositionNode(void);  // default constructor
   void             ~CVirtualPositionNode(void);  // destructor
  };

Artık sanal pozisyon açıldığında, sanal pozisyonlar listesine eklenebilir.

Ayrıca, sanal alım satım nesneleri ile çalışmaya yönelik bu yaklaşımın, veritabanı rastgele erişimli bellekte depolandığından önbellek kullanımını gerektirmediğini de belirtmek isterim. Elbette, diğer depolama ortamlarında saklanmasını ayarlayabilirsiniz.


Sonuç

Bu makalede, liste gibi bir kapsayıcı veri türünün avantajlarını göstermeye çalıştım. Ama dezavantajlarından bahsetmeden geçemedim. Her neyse, bu bilgilerin genel olarak OOP ve özellikle de temel ilkelerinden biri olan polimorfizm üzerine çalışan kişiler için faydalı olacağını umuyorum.


Dosyaların konumu:

Benim görüşüme göre, proje klasöründe dosya oluşturmak ve depolamak en iyisi olacaktır. Örneğin, şunun gibi: %MQL5\Projects\UserLists. Burası tüm kaynak kod dosyalarını kaydettiğim yer. Varsayılan dizinleri kullanıyorsanız, bazı dosyaların kodundaki dosya atama yöntemi ekleme dosyasını (tırnak işaretlerini açılı ayraçlarla değiştirin) değiştirmeniz gerekecektir.

#DosyaKonumAçıklama
1 CiSingleNode.mqh  %MQL5\Projects\UserLists  Tek bağlantılı bir liste düğümünün sınıfı
2 CDoubleNode.mqh  %MQL5\Projects\UserLists  Çift bağlantılı bir liste düğümünün sınıfı
3 CiUnrollDoubleNode.mqh  %MQL5\Projects\UserLists  Teşhir edilmemiş çift bağlantılı liste düğümünün sınıfı
4 test_nodes.mq5  %MQL5\Projects\UserLists  Düğümlerle çalışma örnekleri içeren script dosyası
5 CiSingleList.mqh  %MQL5\Projects\UserLists  Tek bağlantılı bir listenin sınıfı
6 CDobleList.mqh  %MQL5\Projects\UserLists  Çift bağlantılı bir listenin sınıfı
7 CiUnrollDoubleList.mqh  %MQL5\Projects\UserLists  Teşhir edilmemiş çift bağlantılı listenin sınıfı
 8 CiCircleDoublList.mqh %MQL5\Projects\UserLists Dairesel çift bağlantılı bir listenin sınıfı
 9 test_sList.mq5 %MQL5\Projects\UserLists Tek bağlantılı bir listeyle çalışma örnekleri içeren script dosyası
 10 test_dList.mq5 %MQL5\Projects\UserLists Çift bağlantılı bir listeyle çalışma örnekleri içeren script dosyası
 11 test_UdList.mq5 %MQL5\Projects\UserLists Teşhir edilmemiş çift bağlantılı bir listeyle çalışma örnekleri içeren script dosyası
 12 test_CdList.mq5 %MQL5\Projects\UserLists Dairesel çift bağlantılı bir listeyle çalışma örnekleri içeren script dosyası
 13 test_MQL5_List.mq5 %MQL5\Projects\UserLists CList sınıfıyla çalışma örnekleri içeren script dosyası
 14 CNodeInt.mqh %MQL5\Projects\UserLists Tamsayı türündeki düğümün sınıfı
 15 CIntList.mqh %MQL5\Projects\UserLists CNodeInt düğümleri için liste sınıfı
 16 CRrandom.mqh %MQL5\Projects\UserLists Rastgele numara üretecinin sınıfı
 17 CVertLineNode.mqh %MQL5\Projects\UserLists Dikey çizgilerin çerçevesini işlemek için düğüm sınıfı
 18 Stat_collector.mq5 %MQL5\Projects\UserLists İstatistik koleksiyonu örneği içeren script dosyası


Referanslar:

  1. A. Friedman, L. Klander, M. Michaelis, H. Schildt. C/C++ Açıklamalı Arşivler. Mcgraw-Hill Osborne Media, 1999. 1008 sayfa.
  2. V.D. Daleka, A.S. Derevyanko, O.G. Kravets, L.E. Timanovskaya. Veri Modelleri ve Yapıları. Çalışma Rehberi. Kharkov, KhGPU, 2000. 241 sayfa (Rusça).


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

Ekli dosyalar |
files.zip (22.75 KB)
MQL5 Cookbook: Fiyat Farklılığını Analiz Etmek İçin Çoklu Sembollü Bir Göstergenin Geliştirilmesi MQL5 Cookbook: Fiyat Farklılığını Analiz Etmek İçin Çoklu Sembollü Bir Göstergenin Geliştirilmesi
Bu yazıda, belirli bir zaman diliminde fiyat farklılaşmasını analiz etmek için çoklu sembollü bir göstergenin geliştirilmesini ele alacağız. Temel konular, çoklu para birimi göstergelerinin programlanmasıyla ilgili bir önceki makalede tartışılmıştı "MQL5 Yemek Kitabı: MQL5'te Çok Sembollü Bir Volatilite Göstergesi Geliştirme". Bu sefer sadece çarpıcı biçimde değiştirilmiş olan yeni özellikler ve işlevler üzerinde duracağız. Çoklu para birimi göstergelerinin programlanmasında yeniyseniz, önce bir önceki makaleyi okumanızı tavsiye ederim.
Ekonometrik EURUSD Bir Adım İlerisi Tahmini Ekonometrik EURUSD Bir Adım İlerisi Tahmini
Makale, EViews yazılımının kullanılması ile, EURUSD için bir adım ilerisi tahminine ve EViews'teki programları kullanarak tahmin sonuçlarının daha fazla değerlendirilmesine odaklanır. Tahmin, regresyon modellerini içerir ve MetaTrader 4 için geliştirilmiş bir Uzman Danışman aracılığıyla değerlendirilir.
MQL5 Yemek Kitabı - Çok Para Birimli Expert Advisor ve MQL5'te Bekleyen Talimatlarla Çalışma MQL5 Yemek Kitabı - Çok Para Birimli Expert Advisor ve MQL5'te Bekleyen Talimatlarla Çalışma
Bu sefer, bekleyen Satın Al Durdur ve Sat Durdur talimatlarıyla çalışmayı temel alan bir alım satım algoritmasına sahip çok para birimli bir Expert Advisor oluşturacağız. Bu makale şu konuları ele almaktadır: belirli bir zaman aralığında alım satım yapma, bekleyen talimatları verme/değiştirme/silme, son pozisyonun Kar Al veya Zarar Durdur'da kapatılıp kapatılmadığını kontrol etme ve her bir sembol için yatırım geçmişinin kontrolü.
Kagi Grafik Göstergesi Kagi Grafik Göstergesi
Makale, çeşitli grafik seçenekleri ve ek fonksiyonlar içeren Kagi grafik göstergesini önermektedir. Ayrıca, gösterge grafik oluşturma ilkesi ve MQL5 uygulama özellikleri de göz önünde bulundurulmuştur. Alım satımda uygulanmasının en popüler örnekleri - Yin/Yang değişim stratejisi, trend çizgisinden uzaklaşan ve sürekli olarak artan "omuzlar"/azalan "beller" görüntülenir.