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

MQL5 Programlama Temelleri: Diziler

MetaTrader 5Örnekler | 13 Ocak 2022, 09:04
380 23
Dmitry Fedoseev
Dmitry Fedoseev

Giriş

Diziler, değişkenler ve fonksiyonlar ile birlikte, hemen hemen tüm programlama dillerinin entegre bir parçasıdır. Genellikle, birçok acemi programcı dizilerden korkar. Kulağa garip geliyor ama doğru! Sizi temin edebilirim, hiç de korkutucu değiller. Aslında diziler normal değişkenlere benzer. Notasyon özelliklerine dair ayrıntılara dalmadan, basit değişkenler kullanarak:

Variable0=1;
Variable1=2;

Variable2=Variable0+Variable1;

veya dizileri kullanarak bir ifade yazmak arasında büyük bir fark yok:

double Variable[3];

Variable[0]=1;
Variable[1]=2;

Variable[2]=Variable[0]+Variable[1];

Gördüğünüz gibi, değişken adlarının dizileri kullandığımızda parantezler içermesi haricinde fark o kadar büyük değil. Daha önemli bir nokta daha var: Değişken bildirirken her değişkenin adını belirtmeniz gerekir, ancak bir dizi bildirirken adını yalnızca bir kez yazmanız ve değişkenlerin sayısını parantezler içinde (dizi öğelerinin sayısı) belirtmeniz gerekir. Dizileri kullanmanın değişkenlere kıyasla avantajları, birçok gerçek hayattaki programlama görevinin zorluklarıyla uğraşırken daha belirgin hale gelir.

Dizilerin karmaşık bir şey olarak görülmesinin nedeni bir şekilde "[" ve "]" kullanımıyla ilgili olabilir mi? Bu semboller, programlama dışında diziler ile çalışırken nadiren kullanılır, bu nedenle klavyedeki konumları kişinin hafızasından silinebilir ve rahatsızlığa neden olabilir. Aslında bunların nerede olduğunu kolayca hatırlayabilirsiniz: bu iki tuş "Enter" tuşunun yanında mantıksal bir sırayla yer alır: açma parantezinden sonra kapatma parantezi gelir.


Dizilerin Tanımı ve Genel Özellikleri

Bir dizi, aynı ada sahip numaralandırılmış bir değişkenler kümesidir. Dizilerin genel özellikleri arasında dizinin adını, değişken türünü (int, double, vb.) ve dizi boyutu yer alır. Dizi öğeleri sıfırdan itibaren indislenir. Dizi öğelerine dair konuşurken, dizi öğelerini sıfırdan itibaren saymaya başlamamızı önermek için "sayı" yerine "indis" kelimesinin kullanılması her zaman daha iyidir (numaralandırma genellikle birden başlar). Bu şekilde indislenen öğelerde, son öğenin indisi dizi öğelerinin sayısından bir eksiktir.

Dizi aşağıdaki gibi bildirilmişse:

double Variable[3];

aşağıdaki öğelere sahiptir: Değişken[0], Değişken[1] ve Değişken[2].

Öğe sayısı ile son öğenin indisi arasında böyle bir uyumsuzluk ilk bakışta uygunsuz görünebilir. Aslında bu, dizi öğelerinin 1'den indislendiği veya dizi boyutunun dizideki gerçek öğe sayısı yerine son öğesinin indisi ile tanımlandığı programlama dillerine göre önemli avantajlar sunar.

MQL5'te dizi boyutunu belirlemek için ArraySize() fonksiyonunu kullanırız:

double Variable[3];

int Size=ArraySize(Variable);

Kodu çalıştırdıktan sonra Size değişkeninin değeri 3'e eşit olacaktır.


Statik ve Dinamik Diziler

Diziler statik ve dinamik olabilir. Dizi boyutu bildiriminde belirtilmişse, dizi statiktir:

double Variable[3];

Statik bir dizi boyutu programda değiştirilemez. Bir diziyi bildirirken, boyutu doğrudan bir sayı olarak (yukarıdaki örnekte olduğu gibi) veya önceden tanımlanmış bir sabiti kullanılarak belirtilebilir:

#define SIZE 3

double Variable[SIZE];

Bildiriminde boyutu belirtilmeyen bir dizi dinamiktir:

double Variable[];

Kullanmadan önce böyle bir dizinin boyutunu ayarlamanız gerekir. Boyut, ArrayResize() fonksiyonu ile ayarlanır:

ArrayResize(Variable,3);

Dinamik bir dizinin boyutu, program yürütme sırasında gerektiği kadar değiştirilebilir, bu da dinamik ve statik diziler arasındaki temel farktır.

Diziyi tamamen boşaltmanız gerekiyorsa, ArrayFree() fonksiyonunu kullanın:

ArrayFree(Variable);

Dizi boyutu bu fonksiyonu yürütürken 0 olarak ayarlanır. Bu fonksiyonun ortaya çıkardığı etki aşağıdaki eyleme benzerdir:

ArrayResize(Variable,0);

Dizinin boşaltılması, daha fazla program işlemi için diziye artık ihtiyaç duyulmadığında (program tarafından kullanılan bellek miktarını azaltır) veya bir fonksiyon yürütme başlangıcında (dizi veri toplama için kullanılıyorsa) faydalı olabilir.

ArrayIsDynamic() fonksiyonu, sağlanan herhangi bir dizinin statik mi yoksa dinamik mi olduğunun belirlenmesine olanak sağlar:

bool dynamicArray=ArrayIsDynamic(Variable);

dynamicArray değişkeni, dizi dinamikse bir true değerini, dizi statikse bir false değerini içerecektir.


Dizi Başlatma

Bazen bir diziyi, bildirdikten hemen sonradeğerlerle doldurmak gerekir. Aynı türde birkaç düğme oluşturarak her düğmeyi kendi metnine sahip olacak şekilde bir satırda düzenlemek istediğinizi varsayalım. Dizilerin devasa avantajları burada devreye girer. Her düğme için kodu kopyalamanız gerekmez (düzinelerce olabilir) veya aynı fonksiyonu tekrar tekrar çağırmanız gerekmez. Fonksiyon çağrı kodunu yalnızca bir kez yazdıktan sonra bir döngüde dizi üzerinde yineleme yaparak gerekli sayıda düğme oluşturabilirsiniz.

Basitçe bir dizi bildiririz ve hemen öğelerine değerler atarız:

string Variable[] = {"Button 1", "Button 2", "Button 3"};

Bu şekilde bildirildiğinde dizi, boyutu belirtilmemiş olmasına rağmen hala statik olacaktır. Bunun nedeni, öğelerinin sayısının değerler listesiyle (süslü parantez içinde) tanımlanmasıdır.

Dizi öğelerinin sayısını belirtirseniz hata meydana gelmeyecektir:

string Variable[3] = {"Button 1", "Button 2", "Button 3"};

Ancak bunu yapmamanız daha iyi olacaktır; programda yapılacak iyileştirmeler sırasında dizi değerleri listesini değiştirmeniz ve daha fazla veya daha az sayıda öğe kullanmanız gerekebilir. Kullanıldığı kod kısımlarında dizi boyutunu belirlemek için, belirli bir sayısal değer yerine ArraySize() fonksiyonunun kullanılması önerilir. Bu yaklaşım, ana koda müdahale etmeksizin, yalnızca değerler listesini değiştirmenize olanak sağlar. Programı başlattığınızda dizi boyutu değişkenini bildirmek ve buna ArraySize() fonksiyonu ile elde edilen değeri atamak daha uygun olacaktır.

Değerler listesi ile statik bir dizi başlatılamıyorsa, dizi boyutunu belirtmek için bir sabit kullanmak daha iyi olacaktır. Genel olarak, programda daha fazla iyileştirme yapılması gerektiğinde değiştirilmesi gereken kod miktarını azaltma ilkesini izleriz. Tüm dizi öğelerini aynı değerlerle doldurmanız gerekiyorsa, ArrayInitialize() fonksiyonunu kullanın:

ArrayInitialize(Variable,1);

Yukarıdaki kodu çalıştırdıktan sonra, tüm Var dizi öğeleri 1 değerinde olacaktır. Aynı değerlerin yalnızca bazı dizi öğelerine atanması gerekiyorsa, ArrayFill() fonksiyonunu kullanırız:

double Variable[4];

ArrayFill(Variable,0,2,1);
ArrayFill(Variable,2,2,2);

Bu kodu çalıştırdıktan sonra, 0 ve 1 öğeleri 1 değerini alırken, 2 ve 3 öğeleri 2 değerini alacaktır.


Dizi Yineleme Döngüsü

Diziler genellikle bir for döngüsü kullanılarak işlenir. Boyutu önceden bilinen statik bir dizi kullanırken elimizdeki işe göre diziyi ileri veya geri yineleriz:

//--- forwards
for(int i=0; i<SIZE; i++){ 
  // some manipulations on the Variable[i] element
}

//--- backwards
for(int i=SIZE-1; i>=0; i--){
  // some manipulations on the Variable[i] element
}

Dizi dinamikse, döngüden hemen önce dizi boyutu için bir değişken bildirmeli, dizi boyutunu elde etmeli ve bir döngü oluşturmalısınız:

int Size=ArraySize(Var);

for(int i=0; i<Size; i++){
  // some manipulations on the Variable[i] element
}

Bir for döngüsünde koşulu kontrol ederken dizi boyutu için bir değişken kullanmak yerine ArraySize() fonksiyonunu çağırırsanız, ArraySize() fonksiyonu her döngü yinelemesinde çağrılacağı için döngü süresi önemli ölçüde uzayabilir. Yani fonksiyon çağrısı bir değişkeni çağırmaktan daha fazla zaman alır:

for(int i=0; i<ArraySize(Variable); i++){
   // some manipulations on the Variable[i] element
}
Yukarıdaki kodun kullanımı önerilmez.

Program algoritması geriye doğru döngü yinelemesine olanak sağlıyorsa, şunu dizi boyutu için bir değişken olmaksızın yapabilirsiniz:

for(int i=ArraySize(Variable)-1; i>=0; i--){
  // some manipulations on the Variable[i] element
}

Bu durumda, döngünün başında ArraySize() fonksiyonu yalnızca bir kez çağrılacak ve döngü hızlı bir şekilde çalışacaktır.


Çok Boyutlu Diziler

Şimdiye kadar yalnızca tek boyutlu dizileri ele aldık. Bunlar aşağıdaki gibi temsil edilebilir:

Tek boyutlu dizi

Diziler çok boyutlu da olabilir. Tek boyutlu bir dizide indis başına yalnızca bir değer varken çok boyutlu bir dizide indis başına birden fazla sayıda değer vardır. Çok boyutlu diziler aşağıdaki şekilde bildirilir:

double Variable[10][3];

Bu, dizinin ilk boyutunun on öğeye sahip olması ve ikinci boyutun üç öğeye sahip olması anlamına gelir. Aşağıdaki şekilde gösterilebilir:

Çok boyutlu dizi

İki boyutlu bir dizi, kolay anlaşılması için bir düzlem olarak gösterilebilir. Birinci boyutun boyutu uzunluğu belirler, ikinci boyutun boyutu genişliği belirler ve öğenin değeri örneğin deniz seviyesinden yükseklik olmak üzere düzlemde belirli bir noktanın parametrelerini tanımlar.

Bir dizi üç boyutlu da olabilir:

double Variable[10][10][10];

Bu dizi bir küp veya paralelkenar olarak gösterilebilir: birinci boyut uzunluğu belirler, ikinci boyut genişliği belirler, üçüncü boyut yüksekliği belirler ve öğenin değeri uzayda belirli bir noktanın parametrelerini tanımlar.

MQL5'te izin verilen maksimum dizi boyutu sayısı 4'tür.

Çok boyutlu bir dizi yalnızca birinci boyutta statik veya dinamik olabilir, diğer tüm boyutlarda statiktir. Dolayısıyla, ArrayResize() fonksiyonuyla yalnızca birinci boyutun boyutunu değiştirmeniz sağlanır. Bir dizi bildirilirken diğer boyutların da boyutları belirtilmelidir:

double Variable[][3][3];

Çok boyutlu bir dizinin boyutunu ArraySize() fonksiyonunu kullanarak belirlerken bir şeyi aklımızda tutmalıyız: Dizi boyutunu ArrayResize() fonksiyonunu kullanarak değiştirirken, fonksiyonun ikinci parametresi dizinin birinci boyutunun boyutudur. Buna rağmen, ArraySize() fonksiyonu, birinci boyutun boyutunu değil, toplam öğe sayısını döndürür.

double Variable[][3][3]; 

ArrayResize(Variable,3); 
int Size = ArraySize(Variable);

Yukarıdaki kodu çalıştırdıktan sonra, Size (Boyut) değişkeninin değeri 27'ye eşit olacaktır. Birinci boyutun boyutunu elde etmeniz gerekiyorsa, bir döngüde çok boyutlu diziler üzerinde yineleme yaparken bu özelliği hatırlayın:

double Variable[][3][3];
 
ArrayResize(Variable,3); 

int Size=ArraySize(Variable)/9; // Determine the size of the first dimension

for(int i=0; i<Size; i++) {
   for(int j=0; j<3; j++) {
      for(int k=0; k<3; k++) {
            //  some manipulations on the Var[i][j][k] element;
      }   
   }   
}

Daha önce bahsedildiği gibi programda daha fazla iyileştirme yapılması gerektiğinde, değiştirilmesi gereken kod miktarını azaltma ilkesine uyulması tavsiye edilir. Yukarıdaki kod örneğinde, hesaplanabilen 9 sayısını kullandık. Bunun için, dizinin belirtilen boyutunda bulunan öğelerin sayısını döndüren ArrayRange() fonksiyonunu kullanabiliriz. Dizi boyutlarının sayısı biliniyorsa basit bir hesaplama yapabiliriz:

int Elements=ArrayRange(Variable,1)*ArrayRange(Variable,2);
int Size=ArraySize(Variable)/Elements;

Bunu daha evrensel hale getirebiliriz:

int Elements=1; // One element for a one-dimensional array
int n=1; // Start with the second dimension (dimensions are numbered from zero)

while(ArrayRange(Variable,n) > 0){ // Until there are elements in the dimension
   Elements*=ArrayRange(Variable,n); // Multiplication of the number of elements
   n++; // Increase in the dimension's number
}

Bu noktada, böyle bir hesaplama için bir fonksiyon oluşturmanın iyi olacağını düşünebilirsiniz. Ne yazık ki bu mümkün değil, çünkü bir fonksiyona rastgele bir dizi aktarılamaz. Bir fonksiyon argümanı bildirirken, birincisi hariç tüm dizi boyutlarındaki öğelerin sayısını açıkça belirtmeniz gerekir, bu da böyle bir fonksiyonu anlamsız hale getirir. Bu hesaplamalar program başlatılırken daha kolay ve daha iyi şekilde yapılır. Bir diziyi bildirirken, boyutların boyutlarını belirleyen sabitlerin kullanılması tavsiye edilir:

#define SIZE1 3
#define SIZE2 3
#define TOTAL SIZE1*SIZE2 

Çok boyutlu dizilerin değer listesi kullanılarak başlatılması tek boyutlu dizilerin başlatılmasına benzerdir. Ancak, çok boyutlu bir dizi birkaç başka diziden oluştuğundan, bu dizilerin her biri süslü parantezler ile ayrılmalıdır.

Diyelim ki aşağıdaki gibi bir dizimiz var:

double Variable[3][3];

Bu dizi, her biri üç öğeden oluşan üç diziden oluşuyor:

double Variable[][3]={{1, 2, 3},{ 4, 5, 6},{7, 8, 9}};

Üç boyutlu bir dizi de aynı şekilde ele alınır. Dizi yapısının daha kolay anlaşılması için kod birkaç satıra bölünebilir:

double Variable[][3][3]={
   {
      {1, 2, 3},
      {4, 5, 6},
      {7, 8, 9}
   },
   {
      {10, 20, 30},
      {40, 50, 60},
      {70, 80, 90}
   },
   {
      {100, 200, 300},
      {400, 500, 600},
      {700, 800, 900}
   }
};

ArrayInitialize() fonksiyonu kullanılarak çok boyutlu bir dizinin başlatılması, tek boyutlu bir dizinin başlatılması ile aynı şekilde yapılır:

ArrayInitialize(Variable,1);

Yukarıdaki kodu çalıştırdıktan sonra, tüm dizi öğeleri 1 değerinde olacaktır. Bu ArrayFill() fonksiyonu için de geçerlidir:

double var[3][3][3];

ArrayFill(Variable,0,9,1);
ArrayFill(Variable,9,9,10);
ArrayFill(Variable,18,9,100);

Bu kodu çalıştırdıktan sonra, birinci boyutun ilk öğesiyle ilişkili tüm öğeler 1, ikinci öğeyle ilişkili olanlar 10 ve üçüncü öğeyle ilişkili olanlar - 100 değerini alacaktır.


Bir Diziyi Bir Fonksiyona Aktarma

Diziler, değişkenlerden farklı olarak, bir fonksiyona yalnızca referans yoluyla aktarılabilir. Bunun anlamı, fonksiyonun dizinin kendi örneğini oluşturmaması ve bunun yerine doğrudan kendisine aktarılan diziyle çalışmasıdır. Yani, fonksiyonun dizide yaptığı tüm değişiklikler orijinal diziyi etkiler.

Bir değişken, bir fonksiyona olağan bir şekilde (değere göre) aktarılırsa, aktarılan değişkenin değeri fonksiyon tarafından değiştirilemez:

int x=1;
Func(x);

void  Func(int arg){
   arg=2;
}

x değeri, Func() fonksiyonunu çalıştırdıktan sonra 1'e eşit kalır.

Eğer bir değişken referans yoluyla aktarılırsa (& ile gösterilir), fonksiyon kendisine aktarılan bu değişkenin değerini değiştirebilir:

int x=1;
Func(x);

void  Func(int &arg){
   arg=2;
}

x değeri, Func() fonksiyonunu çalıştırdıktan sonra 2'ye eşit olur.

Bir fonksiyona bir dizi aktarırken, argümanın referans olarak aktarıldığını ve bir diziyi temsil ettiğini (parantez içinde) belirtmeniz gerekir:

void Func(double &arg[]){
   // ...
}

Çok boyutlu dizileri bir fonksiyona aktarırken, boyut boyutları (birincisi hariç) belirtilmelidir:

double var[][3][3];

void Func(double &arg[][3][3]){
   // ...
}

Bu durumda, sabitlerin kullanılması daha da çok tavsiye edilir:

#define SIZE1 3
#define SIZE2 3

double Var[][SIZE1][SIZE2];

void Func(double &arg[][SIZE1][SIZE2]){
   // ...
}


Dizileri Kaydetme ve bir Dosyadan Yükleme

Bir diziyi kaydederken ve bir dosyadan yüklerken, dizinin birinci boyutunun boyutundaki değerler ile dizi öğelerinin toplam sayısı arasındaki farkı her daim göz önünde bulundurmalısınız. Bir diziyi kaydetmek için dosyaya ilk olarak dizi boyutunu (ArraySize() fonksiyonu ile belirlenen toplam öğe sayısı) ve ardından dizinin tamamını yazarız:

bool SaveArrayToFile(string FileName,string &Array[])
  {
//--- Open the file
   int h=FileOpen(FileName,FILE_TXT|FILE_WRITE);
   if(h==-1) return(false); // Error opening the file
//--- Write to the file
   FileWriteInteger(h,ArraySize(Array),INT_VALUE); // Write the array size
   FileWriteArray(h,Array); // Write the array
//--- Close the file
   FileClose(h);
   return(true); // Saving complete
  }

Bunun sonucunda, tek boyutlu dizileri kaydetmek için oldukça evrensel bir fonksiyon elde ederiz.

Bir dosyadan dizi yüklemek için ilk olarak dizi boyutunu okumamız, bunu yeniden boyutlandırmamız ve son olarak diziyi okumamız gerekir:

bool LoadArrayFromFile(string FileName,double &Array[])
  {
//--- Open the file
   int h=FileOpen(FileName,FILE_BIN|FILE_READ);
   if(h==-1) return(false); // Error opening the file
//--- Read the file
   int Size=FileReadInteger(h,INT_VALUE); // Read the number of array elements
   ArrayResize(Array,Size); // Resize the array. 
                            // In one-dimensional arrays the size of the first dimension is equal to the number of array elements.
   FileReadArray(h,Array); // Read the array from the file
//--- Close the file
   FileClose(h);
   return(true); // Reading complete
  }

Bir dosyadan çok boyutlu bir dizi yüklerken, birinci boyutun boyutunu hesaplamanız gerekecektir. Örneğin üç boyutlu bir dizi okuduğumuzu varsayalım:

bool LoadArrayFromFile3(string FileName,double &Array[][SIZE1][SIZE2])
  {
//--- Open the file
   int h=FileOpen(FileName,FILE_BIN|FILE_READ);
   if(h==-1)return(false); // Error opening the file
//--- Read the file   
   int SizeTotal=FileReadInteger(h,INT_VALUE); // Read the number of array elements
   int Elements=SIZE1*SIZE2; // Calculate the number of elements 
   int Size=SizeTotal/Elements; // Calculate the size of the first dimension
   ArrayResize(Array,Size); // Resize the array
   FileReadArray(h,Array); // Read the array
//--- Close the file
   FileClose(h);
   return(true); // Reading complete
  }

Dosya 2-3'lük bir dizi içeriyor ve biz bunu 3-3'lük bir dizi olarak okumaya çalışıyor olabiliriz. Boyutlar arasındaki uyumu, birinci boyutun hesaplanan boyutunu öğe sayısı ile çarparak kontrol edebilirsiniz. Ortaya çıkan değer dizi öğelerinin toplam sayısına eşitse uyum vardır diyebiliriz.

Ancak Var[2][3] dizisi Var[3][2] dizisine karşılık gelecektir. Bu durumu da ele almanız gerekiyorsa, çok boyutlu bir diziye dair daha fazla bilgi kaydetmelisiniz. Örneğin, ilk olarak dizi öğelerinin sayısını, ardından dizi boyutlarının sayısını ve ardından boyutların her birinin ve dizinin kendisinin boyutlarını kaydedebilirsiniz.

Yukarıda sağlanan son fonksiyon evrensel değildir ve yalnızca ikinci boyutun boyutunun SIZE1'e ve üçüncü boyutun boyutunun SIZE2'ye eşit olduğu üç boyutlu dizileri okumak için tasarlanmıştır. İlki hariç tüm dizi boyutlarının boyutlarını dinamik olarak değiştirmenin bir yolu olmadığından bu sorun değil - programda kullanılması gereken diziler için fonksiyonlar oluşturacağız.

Bu durumda evrensellik gerekli değildir: Dizi boyutlarının boyutları (birincisi hariç) programın harici parametreleri ile kontrol edilmeyecektir. Bununla birlikte, diğer boyutların boyutlarını kontrol etme olanağını uygulamanız gerekiyorsa, bilerek daha büyük boyuttan ve ek değişkenlerden oluşan çok boyutlu bir dizi kullanarak veya nesne yönelimli programlama (OOP) tekniklerini uygulayarak bu işi halledebilirsiniz. Bu makalenin ilerleyen kısımlarında daha çok ikinci yaklaşıma dair konuşacağız.


Dinamik Dizileri Kullanma

Dinamik diziler, dizi boyutunu önceden bilinmediğinde kullanılır. Dizi boyutu program özellikleri penceresinde ayarlanan parametrelere bağlıysa, dinamik dizilerin kullanılması sorun olmayacaktır: Dizi boyutu program başlatma sırasında yalnızca bir kez değiştirilecektir.

Örneğin bekleyen siparişlerle ilgili bilgiler olmak üzere belirli bilgileri dinamik olarak toplamak için bir dizi kullanılabilir. Bunların sayıları değişebilir, yani gerekli boyut önceden bilinmez. Bu durumda, emirleri aktarmadan önce dizi boyutunu 0 olarak değiştirmek ve her emri aktarırken dizi boyutunu bir öğe artırmak en kolay yol olacaktır. Bu yol işe yarayacaktır, ama çok yavaş bir şekilde.

Dizi boyutu, emirleri aktarmadan önce, emir sayısına göre yalnızca bir kez değiştirilebilir. Bu, dizinin son aktif öğesinin indisi için başka bir değişken (veya indis yerine bir dizi fiili olarak aktif dizi öğesi) gerektirecektir. Bu yöntem, maksimum dizi boyutunu zaten biliyorsanız uygundur. Maksimum dizi boyutunu bilmiyorsanız, aşağıdaki sınıfta gösterildiği gibi, parçaları kullanarak diziyi yeniden boyutlandırarak bununla çalışmayı hızlandırabiliriz:

class CDynamicArray
  {
private:
   int               m_ChunkSize;    // Chunk size
   int               m_ReservedSize; // Actual size of the array
   int               m_Size;         // Number of active elements in the array
public:
   double            Element[];      // The array proper. It is located in the public section, 
                                     // so that we can use it directly, if necessary
   //+------------------------------------------------------------------+
   //|   Constructor                                                    |
   //+------------------------------------------------------------------+
   void CDynamicArray(int ChunkSize=1024)
     {
      m_Size=0;                            // Number of active elements
      m_ChunkSize=ChunkSize;               // Chunk size
      m_ReservedSize=ChunkSize;            // Actual size of the array
      ArrayResize(Element,m_ReservedSize); // Prepare the array
     }
   //+------------------------------------------------------------------+
   //|   Function for adding an element at the end of array             |
   //+------------------------------------------------------------------+
   void AddValue(double Value)
     {
      m_Size++; // Increase the number of active elements
      if(m_Size>m_ReservedSize)
        { // The required number is bigger than the actual array size
         m_ReservedSize+=m_ChunkSize; // Calculate the new array size
         ArrayResize(Element,m_ReservedSize); // Increase the actual array size
        }
      Element[m_Size-1]=Value; // Add the value
     }
   //+------------------------------------------------------------------+
   //|   Function for getting the number of active elements in the array|
   //+------------------------------------------------------------------+
   int Size()
     {
      return(m_Size);
     }
  };

Bu sınıfı ekteki CDynamicArray.mqh dosyasında bulabilirsiniz. Dosya, terminal veri dizininin MQL5\Include klasörüne yerleştirilmelidir.

Şimdi kodun performansını her iki durumda da değerlendirip karşılaştıralım: dizi boyutunun sırayla 1 artırıldığı durum ve parçalar kullanılarak artırıldığı durum:

int n=50000;
   double ar[];
   CDynamicArray da;

//--- Option 1 (increasing the size by the 1st element)
   long st=GetTickCount(); // Store the start time 
   ArrayResize(ar,0); // Set the array size to zero 
   for(int i=0;i<n;i++)
     {
      ArrayResize(ar,i+1); // Resize the array sequentially
      ar[i]=i;
     }
   Alert("Option 1: "+IntegerToString(GetTickCount()-st)+" ms"); // Message regarding the amount of time required to perform the first option

//--- Option 2 (increasing the size using chunks)
   st=GetTickCount(); // Store the start time 
   for(int i=0;i<n;i++)
     {
      da.AddValue(i); // Add an element
     }
   Alert("Option 2: "+IntegerToString(GetTickCount()-st)+" ms"); // Message regarding the amount of time required to perform the second option

  }

Bir betik biçimindeki bu test, ekteki sTest_Speed.mq5 dosyasında bulunabilir. Dosya, terminal veri dizininin MQL5\Scripts klasörüne yerleştirilmelidir.

İlk seçeneğin performansı birkaç saniye alırken, ikinci seçenek neredeyse anında gerçekleşmiştir.


Dizi İndisleme Sırası

Genellikle, bir dizi yeniden boyutlandırılırken yeni öğeler dizinin sonuna eklenir:

double ar[]; // Array
ArrayResize(ar,2); // Prepare the array
ar[0]=1; // Set the values
ar[1]=2; 
ArrayResize(ar,3); // Increase the array size
ar[2]=3; // Set the value for the new array element
Alert(ar[0]," ",ar[1]," ",ar[2]); // Print array values

Bu kodu çalıştırdıktan sonra, dizide yer alan değerler 1, 2 ve 3 olmalıdır.

Dizilerdeki öğeler ters sırada da indislenebilir. İndisleme sırası, ArraySetAsSeries() fonksiyonu ile belirlenir:

ArraySetAsSeries(ar,true); // set indexing in reverse order
ArraySetAsSeries(ar,false); // set normal indexing

İndislenen dizinin boyutu ters sırada değiştirildiğinde, yeni öğe dizinin başına öğe eklenir:

double ar[]; // Array
ArrayResize(ar,2); // Prepare the array
ar[0]=1; // Set the values
ar[1]=2; 
ArraySetAsSeries(ar,true); // Change the indexing order
ArrayResize(ar,3); // Increase the array size
ar[0]=3; // Set the value for the new array element
Alert(ar[0]," ",ar[1]," ",ar[2]); // Print array values

Bu kodu çalıştırdıktan sonra, dizide yer alan değerler 3, 2 ve 1 olmalıdır.

İki durumda da, yeni öğe dizinin aynı tarafına eklenir, tek fark indisleme sırasıdır. Öğeleri normal sırada indislenen dizinin başına öğe eklemek için bu fonksiyon kullanılamaz. Normal şekilde indislenen dizinin sonuna bir öğe eklemek için, sadece dizi boyutunu artırmanız ve son öğeye bir değer atamanız gerekir.

Dizinin başına öğe eklemek için dizi boyutunu artırmalı, tüm değerleri taşımalı ve sıfır öğesine yeni bir değer atamanız gerekir. Ters sırada indislenen dizilerde ise, dizinin başına kolayca yeni bir öğe eklenebilir. Ancak, yeni öğeyi dizinin sonuna eklemeniz gerekiyorsa, ilk olarak dizi boyutunu artırmalı ve tüm değerleri başa taşıdıktan sonra son öğeye yeni bir değer atamalısınız. İndisleme sırası manipülasyonları bu sorunu çözmeyecektir.

Dizi indisleme sırası, ArrayIsSeries() fonksiyonu kullanılarak belirlenebilir:

bool series=ArrayIsSeries(ar);

Dizi ters sırada indislenirse, fonksiyon true değerini döndürür.

Ters sırada indislenen diziler esas olarak Uzman Danışmanlarda kullanılır. EA'ları geliştirirken, çubukların sağdan sola sayılması ve dolayısıyla fiyat verilerinin ve gösterge tamponlarının ters indisleme ile dizilere kopyalanması genelde daha uygun bir yoldur.


Dizileri Kopyalama

Kopyalamanın en kolay yolu, bir döngüdeki bir dizi üzerinde yineleme yapmak ve öğeleri bir diziden diğerine sırayla kopyalamaktır. Bununla birlikte, MQL5'te dizileri kopyalamamıza olanak sağlayan özel bir fonksiyon vardır: ArrayCopy():

double ar1[]={1,2,3};
double ar2[];

ArrayCopy(ar2,ar1);

Yukarıdaki kodu çalıştırdıktan sonra ar2 dizisi, ar1 dizisindeki ile aynı değerlere sahip üç öğeden oluşacaktır: 1, 2, 3.

Kopyalanacak öğe sayısı, kopyaladığınız diziye uymuyorsa, dizi boyutu otomatik olarak artırılacaktır (dizi dinamik olmalıdır). Dizi kopyalanacak öğe sayısından büyükse, boyutu aynı kalacaktır.

ArrayCopy() fonksiyonu bir dizinin yalnızca bir kısmının kopyalanmasına da olanak sağlar. Fonksiyonun isteğe bağlı parametrelerini kullanarak, kopyalanacak ilk öğeyi, ilk kopyalanan öğenin yeni dizideki indisini ve kopyalayacağınız öğe sayısını belirleyebilirsiniz.

Bir dizinin öğelerini diğer diziye kopyalamaya ek olarak, ArrayCopy() fonksiyonu aynı dizi içindeki öğeleri kopyalamak için de kullanılabilir:

double ar1[]={1,2,3,4,5};
ArrayCopy(ar1,ar1,1,2);

İndis 2'ye sahip öğe ile başlayan verileri kopyalarız ve bunları indis 1'den başlayarak yapıştırırız. Bu kodu çalıştırdıktan sonra dizi aşağıdaki değerleri içerecektir: 1, 3, 4, 5, 5.

ArrayCopy() fonksiyonu ayrıca verileri sağa kaydırmanıza olanak sağlar:

double ar1[]={1,2,3,4,5};
ArrayCopy(ar1,ar1,2,1);

İndis 1'e sahip öğe ile başlayan verileri alırız ve bunları indis 2'den başlayarak düzenleriz. Bu kodu çalıştırdıktan sonra dizi aşağıdaki değerleri içerecektir: 1, 2, 2, 3, 4.

ArrayCopy() fonksiyonu, çok boyutlu dizilere de uygulanabilir; bu sayede, dizi tek boyutluymuş ve tüm öğeleri seri halinde düzenlenmiş gibi davranır:

double ar[3][2]={{1, 2},{3, 4},{5, 6}};
ArrayCopy(ar,ar,2,4);

Bu kodu çalıştırdıktan sonra dizi şu şekilde görünecektir: {1, 2}, {5, 6}, {5, 6}.


Bir Diziyi Sıralama

Bir dizi, ArraySort() fonksiyonu kullanılarak sıralanabilir:

double ar[]={1,3,2,5,4};
ArraySort(ar);

Yukarıdaki kodu çalıştırdıktan sonra, dizi değerleri aşağıdaki sırayla düzenlenecektir: 1, 2, 3, 4, 5.

ArraySort() fonksiyonu çok boyutlu dizilere uygulanamaz. Çok boyutlu dizileri ve veri yapılarını sıralamaya dair bilgiyi "MQL5'te Elektronik Tablolar" başlıklı makalede bulabilirsiniz.


İkili arama yapmak için ArrayBsearch() fonksiyonunu kullanırız. Bu fonksiyon yalnızca sıralanmış dizilerde düzgün çalışabilir. İkili arama, adını algoritmanın bir diziyi sürekli olarak iki parçaya ayırmasından alır. Algoritma ilk olarak hedef değeri dizinin orta öğesinin değeri ile karşılaştırır, böylece hedef öğeyi içeren yarıyı belirler: soldaki alt dizi veya sağdaki alt dizi. Ardından, hedef değeri alt dizilerin orta öğesinin değeri ile karşılaştırır ve bu böyle devam eder.

ArrayBsearch() fonksiyonu, hedef değere sahip öğenin indisini döndürür:

double ar[]={1,2,3,4,5};

int index=ArrayBsearch(ar,3);

Bu kodu çalıştırdıktan sonra indis değişkeni 2 değerinde olacaktır.

Hedef değer dizide bulunamazsa, fonksiyon en yakın daha küçük değere sahip öğenin indisini döndürecektir. Bu özellik sayesinde fonksiyon, çubukları zamana göre aramak için kullanılabilir. Belirtilen süreye sahip çubuk yoksa, hesaplamalarda daha az süreli bir çubuk kullanılmalıdır.

Hedef değer dizide yer almıyorsa ve dizi değerleri aralığının dışındaysa, fonksiyon 0'ı (hedef değer minimum değerden küçükse) veya son indisi (hedef değer maksimum değerden büyükse) döndürür.

Sıralanmamış bir dizide arama yapmanıza olanak sağlayan tek bir yöntem vardır: bir dizi üzerinde yineleme:

int FindInArray(int &Array[],int Value){
   int size=ArraySize(Array);
      for(int i=0; i<size; i++){
         if(Array[i]==Value){
            return(i);
         }
      }
   return(-1);
}

Yukarıdaki örnekte fonksiyon, hedef değere sahip öğenin indisini döndürür. Hedef değer dizide yer almıyorsa, fonksiyon -1 değerini döndürür.


Maksimum ve Minimum Değeri Bulma

Dizideki maksimum ve minimum değerler, sırasıyla maksimum veya minimum değere sahip öğenin indisini döndüren ArrayMaximum() ve ArrayMinimum() fonksiyonları kullanılarak bulunabilir:

double ar[]={3,2,1,2,3,4,5,4,3};

int MaxIndex=ArrayMaximum(ar);
int MinIndex=ArrayMinimum(ar);
double MaxValue=ar[MaxIndex];
double MinValue=ar[MinIndex];

Bu kodu çalıştırdıktan sonra, MaxIndex değişkeni 6'ya eşit olacaktır, MinIndex değişkeni 2'ye eşit olacaktır, MaxValue 5 değerine eşit olacaktır ve MinValue 1 olacaktır.

ArrayMaximum() ve ArrayMinimum() fonksiyonları, arama aralığındaki ilk öğenin indisini ve arama aralığındaki öğelerin sayısını belirterek arama aralığını sınırlamanıza olanak sağlar:

int MaxIndex=ArrayMaximum(ar,5,3);
int MinIndex=ArrayMinimum(ar,5,3);

Bu durumda MaxIndex 6 değerini alacaktır ve MinIndex - 5 olacaktır. Lütfen belirtilen aralığın minimum 4 değerine sahip iki pozisyon - pozisyon 5 ve pozisyon 7 - içerdiğini unutmayın. Böyle bir durumda fonksiyon, dizinin başlangıcına daha yakın olan öğenin indisini döndürür. Bu fonksiyonlar, ters sırada indislenen dizilerle aynı şekilde çalışır - en küçük indisi döndürür.

Böylece, dizilerle çalışmak için MQL5'te bulunan tüm standart fonksiyonları gözden geçirmiş olduk.


OOP Kullanarak Çok Boyutlu Diziler Oluşturma

Çok boyutlu diziler oluşturmak için sınıfların bir kümesi üç sınıf içerir: bir temel sınıf ve iki alt sınıf. Bir nesne oluşturma aşamasında seçilen alt sınıfa göre nesne, double değişkenlerinin bir dizisini veya nesnelerin bir dizisini temsil edebilir. Nesnelerin dizisinin her öğesi, nesnelerin veya değişkenlerin bir başka dizisini temsil edebilir.

Temel sınıf ve alt sınıflar, temel sınıftaki yıkıcılar ve alt sınıflardaki yapıcılar dışında hemen hemen hiçbir fonksiyon içermez. Temel sınıftaki yıkıcı, programın veya fonksiyonun tamamlanmasından sonra tüm nesnelerin silinmesi içindir. Alt sınıflardaki yapıcılar yalnızca, dizileri yapıcının parametrelerinde belirtilen boyuta göre ölçeklendirmek için kullanılır: bir sınıftaki nesnelerin bir dizisini ve diğer sınıftaki değişkenlerin bir dizisini ölçeklendirmek için. Aşağıda, bu sınıfların uygulanmasına yönelik kod verilmiştir:

//+------------------------------------------------------------------+
//|   Base class                                                     |
//+------------------------------------------------------------------+
class CArrayBase
  {
public:
   CArrayBase       *D[];
   double            V[];

   void ~CArrayBase()
     {
      for(int i=ArraySize(D)-1; i>=0; i--)
        {
         if(CheckPointer(D[i])==POINTER_DYNAMIC)
           {
            delete D[i];
           }
        }
     }
  };
//+------------------------------------------------------------------+
//|   Child class 1                                                  |
//+------------------------------------------------------------------+
class CDim : public CArrayBase
  {
public:
   void CDim(int Size)
     {
      ArrayResize(D,Size);
     }
  };
//+------------------------------------------------------------------+
//|   Child class 1                                                  |
//+------------------------------------------------------------------+
class CArr : public CArrayBase
  {
public:
   void CArr(int Size)
     {
      ArrayResize(V,Size);
     }
  };

Bu sınıfları ekteki CMultiDimArray.mqh dosyasında bulabilirsiniz. Dosya, terminal veri dizininin MQL5\Include klasörüne yerleştirilmelidir.

Şimdi bu sınıfı, tek boyutlu benzerlik dizisi oluşturmak için kullanalım:

CArrayBase * A; // Declare a pointer
   A=new CArr(10); // Load a child class instance that scales the array of variables. 
                   // The array will consist of 10 elements.

//--- Now the array can be used:
   for(int i=0; i<10; i++)
     {
      //--- Assign to each element of the array successive values from 1 to 10
      A.V[i]=i+1;
     }
   for(int i=0;i<10;i++)
     {
      //--- Check the values
      Alert(A.V[i]);
     }
   delete A; // Delete the object
  }

Bir betik biçimindeki bu örnek, ekteki sTest_1_Arr.mq5 dosyasında bulunabilir. Dosya, terminal veri dizininin MQL5\Scripts klasörüne yerleştirilmelidir.

Şimdi iki boyutlu bir dizi oluşturmaya çalışalım. Birinci boyutun her bir öğesi, ikinci boyutun farklı sayıda öğesini içerecektir - birincide bir, ikincide iki vb.:

CArrayBase*A;  // Declare a pointer
   A=new CDim(3); // The first dimension represents an array of objects

//--- Each object of the first dimension represents an array of variables of different sizes 
   A.D[0]=new CArr(1);
   A.D[1]=new CArr(2);
   A.D[2]=new CArr(3);
//--- Assign values
   A.D[0].V[0]=1;

   A.D[1].V[0]=10;
   A.D[1].V[1]=20;

   A.D[2].V[0]=100;
   A.D[2].V[1]=200;
   A.D[2].V[2]=300;
//--- Check the values
   Alert(A.D[0].V[0]);

   Alert(A.D[1].V[0]);
   Alert(A.D[1].V[1]);

   Alert(A.D[2].V[0]);
   Alert(A.D[2].V[1]);
   Alert(A.D[2].V[2]);
//---
   delete A; // Delete the object

Bir betik biçimindeki bu örnek, ekteki sTest_2_Dim.mq5 dosyasında bulunabilir. Dosya, terminal veri dizininin MQL5\Scripts klasörüne yerleştirilmelidir.

Sınıfların dizi boyutlarını değiştirmek için yöntemleri olmadığından, ortaya çıkan diziler bir nevi statiktir. Ancak bunlar, D[] ve V[] dizileri sınıfın genel bölümünde yer aldığından herhangi bir manipülasyon için kullanılabilir. Ve V[] dizisini herhangi bir zorluk çekmeden ölçeklendirebilirsiniz. D[] dizilerini ölçeklendirirken ve boyutlarını küçültürken, ilk olarak silinecek nesnelerle işaret edilen nesneleri silmelisiniz; veya dizi boyutlarını artırırken nesneleri bunlara yüklemelisiniz.

İstenirse, OOP veya veri yapıları kullanılarak çok boyutlu dizileri uygulamanın başka yolları da düşünülebilir.


Sonuç

Makale, dizilerle çalışmak için MQL5'te bulunan tüm standart fonksiyonları kapsar. Dizileri ele almak için özellikleri ve en önemli tekniklerden bazılarını gözden geçirdik. MQL5 dili, bazıları çok önemli olmakla birlikte bazıları alışılmadık bir sorunu çözmeniz gereken durumlar dışında tamamen kullanım dışı olabilen toplam 15 fonksiyon sunar. Fonksiyonlar, önem ve kullanım sıklığına göre aşağıdaki şekilde sıralanabilir:

  1. ArraySize() ve ArrayResize() temel fonksiyonlardır.

  2. ArrayMaximum(), ArrayMinimum(), ArrayCopy(), ArrayInitialize(), ArrayFill() ve ArrayFree() dizilerle çalışmayı önemli ölçüde daha kolay hale getiren fonksiyonlardır.

  3. ArraySort(), önemli ve kullanışlı bir fonksiyondur, ancak düşük fonksiyonelliği nedeniyle nadiren kullanılır.

  4. ArrayBsearch() nadiren kullanılan bir fonksiyondur, ancak nadir istisnai durumlarda çok önemli hale gelebilir.

  5. ArraySetAsSeries(), ArrayRange(), ArrayGetAsSeries(), ArrayIsDynamic() ve ArrayIsSeries() çok nadir kullanılan veya neredeyse hiç kullanılmayan fonksiyonlardır.

Bu makalede açıklanan programlama tekniklerinden biri olan dinamik dizilerin kullanımına özellikle dikkat edilmelidir, çünkü bunun program performansı üzerinde büyük etkisi vardır ve aslında bunu belirlediği söylenebilir.

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

Ekli dosyalar |
cdynamicarray.mqh (2.59 KB)
stest_speed.mq5 (1.6 KB)
cmultidimarray.mqh (1.67 KB)
stest_1_arr.mq5 (1.29 KB)
stest_2_dim.mq5 (1.43 KB)
Son yorumlar | Tartışmaya git (23)
Ernie Gunning
Ernie Gunning | 11 Ara 2020 saat 14:52

Kodunuz için teşekkürler, yazmak için bana biraz zaman kazandırdı. MQL5 Array nesnesini (double, int vb.) kullanmaya çalıştım ve sadece hayal kırıklığına uğradım. Gönderinize geldim ve dizileri yeniden boyutlandırmak için kodunuzu buldum, bu harikaydı teşekkürler. Kodunuzu herhangi bir veri türüne hitap edecek şekilde değiştirdim. Sadece Contains (Arama yöntemi) yöntemini nesneler için kullanmaya çalışmayın çünkü nesneler referans olabileceğinden çalışmayabilir, bunu test etmediğimden emin değilim. C#'ı MQL5 içinde yeniden oluşturmaya çalışıyorum, bu nedenle kısaltmalar benzer :)


Tanrı korusun !!!



// + ----------------------------------------------- ------------------- + 


// | 
CDynamicArray.mqh | 


// | 
Tamsayı | 


// | 
https://login.mql5.com/ru/users/Integer | 


// + ----------------------------------------------- ------------------- + 


#property 

copyright  

"Integer" 


#property 

link  

"https://login.mql5.com/en/users/Integer" 


// + - -------------------------------------------------- --------------- + 


// | 
| 


// + ----------------------------------------------- ------------------- + 


template 

< 

typename 

 T> 


class 

 CDynamicArray 


  { 


private 

 : 
   

int 

                m_ChunkSize;     

// Yığın boyutu 
   

int 

                m_ReservedSize; 

// Dizinin gerçek boyutu 
   

int 

                m_Size;         

// Dizideki aktif eleman sayısı 


public 

 : 


   T Element [];       

// Uygun dizi. 
Public bölümünde yer alır, 
                                     

// böylece gerekirse doğrudan kullanabiliriz 
   

// + --------------------------- --------------------------------------- + 
   

| 
Kurucu | 
   

// + ----------------------------------------------- ------------------- + 
   

void 

 CDynamicArray ( 

int 

 ChunkSize = 

1024 

 ) 


     { 


      m_Size = 

0 

 ;                             

// Aktif eleman sayısı 


       m_ChunkSize = ChunkSize;               

// Yığın boyutu 


       m_ReservedSize = ChunkSize;             

// Dizinin gerçek boyutu 
      

ArrayResize 

 (Element, m_ReservedSize); 

// Diziyi hazırlayın 


      } 
   

// + ----------------------------------------- ------------------------- + 
   

// | 
Dizinin sonuna bir eleman ekleme işlevi | 
   

// + ----------------------------------------------- ------------------- + 
   

void 

 Add (T Value) 


     { 


      m_Size ++; 

// Etkin öğe sayısını artırın 
      

if 

 (m_Size> m_ReservedSize) 


        { 

// İstenen sayı gerçek dizi boyutundan daha büyüktür 


          m_ReservedSize + = m_ChunkSize; 

// Yeni dizi boyutunu hesapla 
         

ArrayResize 

 (Element, m_ReservedSize); 

// Gerçek dizi boyutunu artırın 


         } 


      Element [m_Size- 

1 

 ] = Value; 

// Değeri ekleyin 


      } 
     
     

void 

 Set ( 

int 

 index, T Value) 


     { 


      m_Size ++; 

// Etkin öğe sayısını artırın 
      

if 

 (m_Size <index) 


        { 
         

return 

 ; 


        } 


      Element [index] = Value; 

// Değeri ekleyin 


      } 
   

// + ----------------------------------------- ------------------------- + 
   

// | 
Dizideki aktif eleman sayısını elde eden fonksiyon | 
   

// + ----------------------------------------------- ------------------- + 
   

int 

 Count () 


     { 
      

return 

 (m_Size); 


     } 
   


   T 

operator 

 [] ( 

const  

int 

 index) 

const 

 { 

return 

 Element [index]; 
} 
   
   

bool 

Contains (T itemToFind) 


   { 
      

for 

 ( 

int 

 i = 

0 

 ; i <Count (); i ++) 


        { 
            

if 

 (Element [i] == itemToFind) 


            { 
               

return  

true 

 ; 


            } 


        } 
        
      

return  

false 

 ; 


   } 
   
   

int 

 IndexOf (T itemToFind) 


   { 
      

for 

 ( 

int 

 i = 

0 

 ; i <Count (); i ++) 


        { 
            

if 

 (Element [i] == itemToFind) 


            { 
               

return 

 i; 


            } 


        } 
        
      

return 

 - 

1 

 ; 


   } 


  }; 


// + ----------------------------------------------- ------------------- + 

O zaman onları şu şekilde bildirebilirsiniz:

CDynamicArray 

< 

int 

> 

  *Tickets; 


CDynamicArray 

< 

bool 

> 

 *FixedSLUsed; 


CDynamicArray 

< 

bool 

> 

 *PrevBarSLUsed; 

ve şöyle oluşturabilirsiniz:

                        Tickets = 

new 

 CDynamicArray< 

int 

>(); 


                        FixedSLUsed = 

new 

 CDynamicArray< 

bool 

>(); 


                        PrevBarSLUsed = 

new 

 CDynamicArray< 

bool 

>(); 

ve kodda onları normal bir sınıf gibi kullanırsınız:



int 

 ticket = 

PositionGetInteger 

 ( 

POSITION_TICKET 

 ); 


int 

 index; 


if 

 (!Tickets.Contains(ticket)) // If Ticket Object does NOT contains ticket then we go into the if 


{ 


        Tickets.Add(ticket); 


        FixedSLUsed.Add( 

false 

); 


        PrevBarSLUsed.Add( 

false 

); 


} 
      


index = Tickets.IndexOf(ticket);   
Ernie Gunning
Ernie Gunning | 11 Ara 2020 saat 15:03

Tamam, MQL'in İngilizce sürümünü deneyelim.


Kod gönderiniz için teşekkürler. Bana zaman kazandırdı. MQL dizilerini kullanmayı denedim ve kafa karıştırıcıydılar. Daha sonra orada olması gereken temel yapıları bir kez daha yazmam gerektiği için çok üzüldüm AMA sonra diziler ve bunların dinamik olarak nasıl büyütüleceği / artırılacağı konusunda bana biraz araştırma süresi kazandıran kodunuzu buldum. HARİKA teşekkürler.

Umarım size geri verebilirim! Aşağıdaki kod tüm veri türleri için çalışır. Nesneler üzerinde de çalışacaktır ancak Contains (arama) yöntemi çalışmayabilir. Ben sadece (double, int, bool) tipleri üzerinde test ettim. String de size sorun çıkarabilir ve kodun genişletilmesi gerekebilir.


//+------------------------------------------------------------------+
//|CDynamicArray.mqh |
//|Tamsayı |
//| https://login.mql5.com/ru/users/Integer |
//+------------------------------------------------------------------+
#property copyright "Integer"
#property link "https://login.mql5.com/ru/users/Integer"
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
template <typename T>
class CDynamicArray
  {
private:
   int               m_ChunkSize;    // Yığın boyutu
   int               m_ReservedSize; // Dizinin gerçek boyutu
   int               m_Size;         // Dizideki aktif eleman sayısı
public:
   T                 Element[];      // Uygun dizi. Public bölümünde yer alır, 
                                     // böylece gerekirse doğrudan kullanabiliriz
   //+------------------------------------------------------------------+
   //| Kurucu|
   //+------------------------------------------------------------------+
   void CDynamicArray(int ChunkSize=1024)
     {
      m_Size=0;                            // Aktif eleman sayısı
      m_ChunkSize=ChunkSize;               // Yığın boyutu
      m_ReservedSize=ChunkSize;            // Dizinin gerçek boyutu
      ArrayResize(Element,m_ReservedSize); // Diziyi hazırlayın
     }
   //+------------------------------------------------------------------+
   //| Dizinin sonuna bir eleman ekleme fonksiyonu |
   //+------------------------------------------------------------------+
   void Add(T Value)
     {
      m_Size++; // Etkin öğe sayısını artırın
      if(m_Size>m_ReservedSize)
        { // İstenen sayı gerçek dizi boyutundan daha büyüktür
         m_ReservedSize+=m_ChunkSize; // Yeni dizi boyutunu hesapla
         ArrayResize(Element,m_ReservedSize); // Gerçek dizi boyutunu artırın
        }
      Element[m_Size-1]=Value; // Değeri ekleyin
     }
     
     void Set(int index, T Value)
     {
      m_Size++; // Etkin öğe sayısını artırın
      if(m_Size<index)
        { 
         return;
        }
      Element[index]=Value; // Değeri ekleyin
     }
   //+------------------------------------------------------------------+
   //| Dizideki aktif eleman sayısını elde eden fonksiyon|
   //+------------------------------------------------------------------+
   int Count()
     {
      return(m_Size);
     }
   
   T operator[](const int index) const { return Element[index]; }
   
   bool Contains(T itemToFind)
   {
      for(int i=0;i<Count();i++)
        {
            if(Element[i] == itemToFind)
            {
               return true;
            }
        }
        
      return false;
   }
   
   int IndexOf(T itemToFind)
   {
      for(int i=0;i<Count();i++)
        {
            if(Element[i] == itemToFind)
            {
               return i;
            }
        }
        
      return -1;
   }
  };
//+------------------------------------------------------------------+


Daha sonra ihtiyacınız olan tüm tipler için bu şekilde bildirimde bulunabilirsiniz:


//bunları sınıfımda şu şekilde bildirdim
   CDynamicArray<int> *Tickets;
   CDynamicArray<bool> *FixedSLUsed;
   CDynamicArray<bool> *PrevBarSLUsed;


// Sonra bunları sınıf metotlarımda şu şekilde bildirdim

   Tickets = new CDynamicArray<int>();
   FixedSLUsed = new CDynamicArray<bool>();
   PrevBarSLUsed = new CDynamicArray<bool>();

// ve bunları sınıf metotlarımda şu şekilde kullandım:
      int ticket = PositionGetInteger(POSITION_TICKET);
      int index;
      if(!Tickets.Contains(ticket))
      {
         Tickets.Add(ticket);
         FixedSLUsed.Add(false);
         PrevBarSLUsed.Add(false);
      }
      
      index = Tickets.IndexOf(ticket);  
//daha fazla kod kaldırıldı



umarım bu herkese yardımcı olur

Ernie Gunning
Ernie Gunning | 20 Ara 2020 saat 15:28
Ernie Gunning:

Tamam, MQL'in İngilizce versiyonunu deneyelim.


Kod gönderiniz için teşekkürler. Bana zaman kazandırdı. MQL dizilerini kullanmayı denedim ve kafa karıştırıcıydılar. Daha sonra orada olması gereken temel yapıları bir kez daha yazmam gerektiği için çok üzüldüm AMA sonra diziler ve bunların dinamik olarak nasıl büyütüleceği / artırılacağı konusunda bana biraz araştırma süresi kazandıran kodunuzu buldum. Harika, teşekkürler.

Umarım size geri dönebilirim! Aşağıdaki kod tüm veri türleri için çalışır. Nesneler üzerinde de çalışacaktır ancak Contains (arama) yöntemi çalışmayabilir. Ben sadece tipler üzerinde test ettim (double, int, bool). String de size sorun çıkarabilir ve kodun genişletilmesi gerekebilir.



Daha sonra ihtiyacınız olan tüm tipler için bu şekilde bildirimde bulunabilirsiniz:




umarım bu herkese yardımcı olur


Lütfen herhangi bir veri türü için Dinamik dizi kullanmak için yukarıdaki önerimi dikkate almayın. Zaten bildirilmiş genel bir CArrayList var. lütfen bunu kullanın. Nesneleri kullanırken bu başlıkta çözülen bir sorunla karşılaştım: https: //www.mql5.com/en/forum/358432

Tobias Johannes Zimmer
Tobias Johannes Zimmer | 16 Nis 2021 saat 16:51
Sizden zaten bazı iyi makaleler okudum. Bu da bir istisna değildi.
zumaya01
zumaya01 | 21 Nis 2024 saat 00:39

arrayResize() fonksiyonunda bir hata görünüyor, örnekte dizinin içeriği 1, 2, 3 değil normal indekslemede 1, 1, 3'tür. Bu örneğe bakın:

//+------------------------------------------------------------------+
//|Yanlış.mq5 |
//|Telif Hakkı 2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
//+------------------------------------------------------------------+
//| Özel gösterge başlatma işlevi |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- gösterge tamponları eşleme
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Özel gösterge yineleme işlevi|
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   double ar[]; // Dizi
ArrayResize(ar,2); // Diziyi hazırlayın
ar[0]=1; // Değerleri ayarlayın
ar[1]=2; 
ArraySetAsSeries(ar,true); // İndeksleme sırasını değiştirin
ArrayResize(ar,3); // Dizi boyutunu artırın
ar[0]=3; // Yeni dizi elemanı için değer ayarlayın
Alert(ar[0]," ",ar[1]," ",ar[2]); // Dizi değerlerini yazdır
ArraySetAsSeries(ar,false);
Alert("Normal indexing: ", ar[0]," ",ar[1]," ",ar[2]); // Dizi değerlerini yazdır
//--- sonraki çağrı için prev_calculated değerini döndürür
   return(rates_total);
  }
//+------------------------------------------------------------------+
arraySetAsSeries() işlevi eklendiğinde, arrayresieze işlevinden etkileniyor gibi görünüyor, bu örneğe bakın:
//+------------------------------------------------------------------+
//|errorindex.mq5 |
//|Telif Hakkı 2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
//+------------------------------------------------------------------+
//| Özel gösterge başlatma işlevi |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- gösterge tamponları eşleme
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Özel gösterge yineleme işlevi|
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   double ar[]; // Dizi
ArrayResize(ar,2); // Diziyi hazırlayın
ar[0]=9; // Değerleri ayarlayın
ar[1]=8; 
ArrayResize(ar,6); // Dizi boyutunu artırın
Alert("Normal resize: ", ar[0]," ",ar[1]," ",ar[2]," ", ar[3], " ", ar[4], " ", ar[5]);
ArraySetAsSeries(ar,true); // İndeksleme sırasını değiştirin
ArrayResize(ar,4); // Dizi boyutunu artırın
ArraySetAsSeries(ar, false);
Alert("See the random element added: ", ar[0]," ",ar[1]," ",ar[2]," ", ar[3]);
ArraySetAsSeries(ar,true); // Dizinleme sırasını değiştir 0
ar[0]=8; // Yeni dizi elemanı için değer ayarlayın
Alert("Modify the first as serlies: ", ar[0]," ",ar[1]," ",ar[2]," ", ar[3]); // Dizi değerlerini yazdır
//--- sonraki çağrı için prev_calculated değerini döndürür
   return(rates_total);
  }
//+------------------------------------------------------------------+

Adımlar:

1. ar = {}
2. ar = {9, 8}

3. ar = {9, 8, 0, 8, 0, 0}

4. Seri doğru olarak ayarlanır:

ar = {0, 0, 8, 0, 8, 9}

5. 4'e yeniden boyutlandır

ar = {0, 0, 8, 0}

6. Seri yanlış olarak ayarlayın:

ar = {0, 8, 0, 0}

7. Seri doğru olarak ayarlanır:

ar = {0, 0, 8, 0}

8. İlk öğeyi değiştir a[0]

ar = {8, 0, 8, 0}


Hangi diziyi yeniden boyutlandırdığını bilmiyorum (3 -5) değerleri alır ve yeni konumlara kopyalar, 6 ileri rastgele değerler alır, sanırım. Önce resize() ve ardından setasseries() işlevini tercih ederim:

//+------------------------------------------------------------------+
//|indexingarraytest.mq5 |
//|Telif Hakkı 2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
//+------------------------------------------------------------------+
//| Özel gösterge başlatma işlevi |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- gösterge tamponları eşleme
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Özel gösterge yineleme işlevi|
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   double ar[]; // Dizi
ArrayResize(ar,2); // Diziyi hazırlayın
ar[0]=1; // Değerleri ayarlayın
ar[1]=2;
ArrayResize(ar,3); // Dizi boyutunu artırın
Alert("Redimension to 3 normal: ", ar[0], " ", ar[1], " ", ar[2]); 
ArraySetAsSeries(ar,true); // İndeksleme sırasını değiştirin
Alert("Redimension to 3 series: ", ar[0], " ", ar[1], " ", ar[2]); 
ar[0]=8; // Yeni dizi elemanı için değer ayarlayın
Alert("Change the first element: ", ar[0]," ",ar[1]," ",ar[2]); // Dizi değerlerini yazdır
ArraySetAsSeries(ar, false);
Alert("Normal renew: ", ar[0]," ",ar[1]," ",ar[2]); // Dizi değerlerini yazdır
//--- sonraki çağrı için prev_calculated değerini döndürür
   return(rates_total);
  }
//+------------------------------------------------------------------+
"Çalışma Sırasında" Kullanıcı Panelinden Uzman Danışman Parametrelerini Değiştirme "Çalışma Sırasında" Kullanıcı Panelinden Uzman Danışman Parametrelerini Değiştirme
Bu makale, bir Uzman Danışman uygulamasını gösteren küçük bir örnek sunar, bunun parametreleri kullanıcı panelinden kontrol edilebilir. Uzman Danışman, parametreleri "çalışma sırasında" değiştirirken, dosyadan daha fazla okumak ve bunları panelde uygun şekilde görüntülemek için bilgi panelinden alınan değerleri bir dosyaya yazar. Bu makale, manuel veya yarı otomatik modda alım satım yapanların dikkatini çekebilir.
MetaTrader 5 için Alım Satım Sinyalleri: PAMM Hesaplarına Daha İyi Bir Alternatif! MetaTrader 5 için Alım Satım Sinyalleri: PAMM Hesaplarına Daha İyi Bir Alternatif!
MetaTrader 5'in artık Alım Satım Sinyalleri içerdiğini ve böylece yatırımcılara ve yöneticilere güçlü bir araç sağladığını duyurmaktan mutluluk duyuyoruz. Siz başarılı bir yatırımcının alım satımlarını takip ederken, terminal otomatik olarak bunları hesabınıza kopyalayacaktır!
Makine Öğrenmesi: Destek Vektör Makineleri Ticarette Nasıl Kullanılabilir? Makine Öğrenmesi: Destek Vektör Makineleri Ticarette Nasıl Kullanılabilir?
Destek Vektör Makineleri, biyoinformatik ve uygulamalı matematik gibi alanlarda, karmaşık veri kümelerini değerlendirmek ve verileri sınıflandırmak için kullanılabilecek faydalı modellerini çıkarmak için uzun süredir kullanılmaktadır. Bu makale, destek vektör makinelerinin ne olduğunu, bunların nasıl çalıştığını ve karmaşık modelleri çıkarmada neden bu kadar faydalı olabileceklerini inceler. Daha sonra, bunların piyasaya nasıl uygulanabileceğini ve potansiyel olarak alım satım tavsiyelerinde bulunmak için nasıl kullanılabileceğini araştırıyoruz. Makale, okuyucuların Destek Vektörü Makine Öğrenme Aracını kullanarak kendi alım satımlarını denemelerine olanak sağlayan çalışılmış örnekler sunar.
Alım Satım Fikirlerinin Grafik Üzerinde Hızlı Testi Alım Satım Fikirlerinin Grafik Üzerinde Hızlı Testi
Makale, alım satım fikirlerinin hızlı görsel test yöntemini açıklar. Yöntem bir fiyat grafiği, bir sinyal göstergesi ve bir bakiye hesaplama göstergesinin kombinasyonuna dayanır. Alım satım fikirleri için arama yöntemimi ve bu fikirleri hızlı bir şekilde test etmek için kullandığım yöntemi paylaşmak istiyorum.