English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
Örnek olarak MQL5'te OOP: Uyarı ve Hata Kodlarını İşleme

Örnek olarak MQL5'te OOP: Uyarı ve Hata Kodlarını İşleme

MetaTrader 5Örnekler | 15 Aralık 2021, 09:50
54 0
KlimMalgin
KlimMalgin

OOP'ye Kısa Giriş

Geliştirmeye başlamadan önce, bu makalede kullanılacak olan OOP'nin bazı özelliklerini tanıyalım. 

Elbette, yapıları ve sınıfları kullanacağız. Bunlar nesne yönelimli dillerin temelleridir. Yapı nedir, sınıf nedir ve aralarındaki farklar nelerdir?

Yapı, bir dizi değişken ve farklı türde işlevler (void hariç) içermesine izin veren bir yapıdır.

Sınıf ve yapı bir dizi veri alanıdır. Ancak sınıf daha karmaşık ve "Esnek" bir yapıdır. Sınıflar, OOP'nin temel kavramıdır. Sınıfların ve yapıların farklılıkları belgelerde açıklanmıştır. Bu farklıkları burada tekrarlayacağım:

  • Sınıf anahtar sözcüğü, bildirimde kullanılır.
  • Tüm sınıf üyelerinin erişim belirticisi, aksi belirtilmedikçe, varsayılan olarak özeldir. Yapıların veri üyeleri, aksi belirtilmedikçe, varsayılan olarak genel erişim türleridir.
  • Sınıf nesneleri, sınıfta sanal işlevler bildirilmemiş olsa dahi, her zaman bir sanal işlevler tablosu içerir. Yapılar sanal işlevler içermez.
  • new işleci sınıf nesnelerine uygulanabilir; bu işleç yapılara uygulanamaz.
  • Sınıflar yalnızca sınıflardan devralınabilir; yapılar yalnızca yapılardan devralınabilir.

 

Şimdi sınıfları ele alalım. Tüm sınıf alanları iki türe ayrılır. Bunlar, bir sınıf içinde tanımlanan veri üyeleri (değişkenler, diziler vb.) ve işlevlerdir.

Veri üyeleri genellikle sınıf özellikleri olarak adlandırılır; zira bir sınıftan bir nesne oluşturulduğunda, veri üyeleri tam olarak bu nesnenin özelliklerini yansıtır. Örneğin, bu bir geometrik şekil (ör. daire) ise, özellikler yarıçapını, çizgi genişliğini, şekil rengini yani nesne özelliklerini içerecektir.

Bir sınıf içinde tanımlanan işlevler, yöntemler olarak adlandırılır. Hem sınıf özellikleriyle çalışmak hem de bunlarda programlanmış diğer algoritmaları uygulamak için kullanılırlar.

Nesne yönelimli programlama kapsülleme kavramına sahiptir. Bu, bir nesnenin verilerini ve uygulamasını bir kullanıcının (uygulama programcısı) doğrudan etkisinden gizleme olasılığıdır. Bir programcı, yalnızca nesne özelliklerini hangi yöntemleri kullanarak değiştirebileceğini açıklayan belgeler alır, ancak nesne özelliklerini doğrudan değiştirmek imkansızdır.

Bu tür koruma önlemleri, bir özellik değerini değiştirmeden önce bir dizi kontrolün gerekli olduğu durumlarda gereklidir. Yöntemlerde gerekli tüm kontroller yapılır ve başarılı bir şekilde gerçekleştirilmesi durumunda bunlar, özellik değerinin değiştirilmesine izin verir. Ve bir kullanıcının özelliklere doğrudan erişimi olması durumunda, bu kontroller gerçekleştirilmez ve sonuç olarak özellik değeri yanlış ayarlanabilir; bu durumda, MQL programı gerektiği gibi çalışmayacaktır.

Herhangi bir sınıf özelliği ve yöntemi için, üç değiştirici kullanarak bir erişim düzeyi ayarlayabiliriz: özel, korumalı ve genel.

Bir sınıf alanı için özel değiştiricisi kullanılıyorsa bu alana erişim yalnızca aynı sınıfa ait yöntemler kullanılarak mümkündür; dolayısıyla bu, dışarıdan değiştirilemez. Korumalı değiştiricisi ayrıca alana dışarıdan erişime bazı kısıtlamalar getirir, ancak aynı sınıfın yöntemleri ve alt sınıfların yöntemleri için sınıf alanlarına erişmeyi mümkün kılar. Aksine, genel, tüm erişim kısıtlamalarını kaldırır ve sınıf alanlarına ücretsiz erişim açar.

Bir Include mqh-dosyası oluşturma

Yazacağımız sınıf ayrı bir mqh dosyasında yer almalıdır, böylece programlarımıza dahil edilebilir (Expert Advisor'lar, script dosyaları, göstergeler)

Bu dosyayı oluşturmak için MQL5 Sihirbazını kullanalım. Dosya -> Oluştur menüsünde İçerme dosyasını (*.mqh) seçin ve Sonraki seçeneğine gidin. Açılan pencerede dosya adını girin (buna ControlErrors adını verdim) ve Bitti düğmesine basın. Bir mqh dosyasının şablonu açılacaktır. Bu dosyada çalışmaya devam edeceğiz.

Başlarken

Artık bu makaleyi inceleme sürecinde faydalı olabilecek OOP'nin tüm teorik temellerini biliyorsunuz. O halde, devam edelim.

Tüm özelliklerinin ve yöntemlerinin bildirildiği sınıf kodunu ele alalım:

class ControlErrors
{
private:

   // Flags determining what types of statements should be introduced
   bool _PlaySound;    // Play or don't play a sound when an error occurs
   bool _PrintInfo;    // Enter error data the the journal of Expert Advisors
   bool _AlertInfo;    // Generate Alert alert with error data
   bool _WriteFile;    // Write reports on errors onto a file or not
   
   // A structure for storing error data and elements that use this structure
   struct Code
   {
      int code;      // Error code
      string desc;   // Description of an error code
   };
   Code Errors[];    // Array that contains error codes and their descriptions
   Code _UserError;  // Stores information about a custom error
   Code _Error;      // Stores information about the last error of any type   
   
   // Different service properties
   short  _CountErrors;     // Number of errors stored in array Errors[]
   string _PlaySoundFile;   // File that will be played for an alert sound
   string _DataPath;        // Path to the log storing directory

   
public:
   // Constructor
   ControlErrors(void);
   
   // Methods for setting flags
   void SetSound(bool value);          // Play or don't play a sound when an error occurs
   void SetPrint(bool value);          // Enter error data the the journal of Expert Advisors or not
   void SetAlert(bool value);          // Generate an Alert message or not
   void SetWriteFlag(bool flag);       // Set the writing flag. true - keep logs, false - do not keep
   
   // Methods for working with errors
   int  mGetLastError();            // Returns contents of the system variable _LastError
   int  mGetError();                // Returns code of the last obtained error
   int  mGetTypeError();            // Returns error type (Custom = 1 ore predefined = 0)
   void mResetLastError();          // Resets the contents of the system variable _LastError
   void mSetUserError(ushort value, string desc = "");   // Sets the custom error
   void mResetUserError();          // Resets class fields that contain information about the custom error
   void mResetError();              // Resets the structure that contains information about the last error
   string mGetDesc(int nErr = 0);   // Returns error description by the number, or that of the current error of no number
   int Check(string st = "");       // Method to check the current system state for errors
   
   // Alert methods(Alert, Print, Sound)
   void mAlert(string message = "");
   void mPrint(string message = "");
   void mSound();
      
   // Various service methods
   void SetPlaySoundFile(string file); // Method sets the file name to play an sound
   void SetWritePath(string path);     // Set the path to store logs  
   int mFileWrite();                   // Record into a file the available information about the last error
};

Sınıf Özellikleri

İlk önce sınıf özelliklerinin bildirimi gelir, özel değiştiricisi tüm özelliklere uygulanır; bu nedenle doğrudan sınıfın dışındaki özelliklerle çalışmak imkansızdır. Özellikler kolaylık sağlamak için üç sınıfa ayrılır:

  1. Ne tür raporların tutulması gerektiğini belirleyen bayraklar. Bu bayrakların tamamı yalnızca iki değeri kabul edebilir: True, bu tür raporların (bildirimlerin) etkinleştirildiği anlamına gelir ve false, bu tür raporların devre dışı bırakıldığı anlamına gelir.
    • _PlaySound - Bir hata oluştuğunda seçilen bir melodinin veya sesin çalınmasını devre dışı bırakan/etkinleştiren değişkendir.
    • _PrintInfo - Expert Advisor günlüğüne hata ayrıntılarını eklemekten sorumludur.
    • _AlertInfo - Hata bilgisi içeren Uyarı çıktısını etkinleştirir veya devre dışı bırakır.
    • _WriteFile - Hata bilgilerinin bir dosyaya kaydedilmesini etkinleştirir veya devre dışı bırakır.
  2. Hata verilerini ve bu yapıyı kullanan öğeleri depolamak için yapı.
    • Kod - Başlı başına yapıdır. Bir dizide saklanan hata verilerinin elverişliliği için oluşturulmuştur.
    • Hatalar - Kod türünde bir dizidir, yani her dizi öğesi bir Kod yapısıdır.
    • _UserError - Kod türünde bir değişkendir. Özel hatalarla çalıştığı için talep edilir.
    • _Error - Kod türünde bir değişkendir. En son meydana gelen hata bu değişkene yerleştirilir ve hata ile daha fazla çalışma bu değişken aracılığıyla gerçekleştirilir.
  3. Diğer hizmet özellikleri.
    • _CountErrors - Değişken, verileri Errors dizisinde saklanması gereken hataların sayısını içerir. Dizi boyutunu belirtmek için kullanılır.
    • _PlaySoundFile - Bir uyarı sesi için çalınacak dosya adını içerir.
    • _DataPath - Hata verilerinin yazıldığı günlük dosyasının yolunu ve adını içerir.

Bence, ilk özellikler grubuyla ilgili her şey nettir: Belirli raporların tutulmasını etkinleştirir veya devre dışı bırakırlar. İkinci grupta, Kod yapısı ilgi çekicidir. Bu nedir ve neden tam olarak bu yapı dizi öğeleri olarak kullanılır? Çok basit! Bir hata kodu ve açıklaması için ayrı diziler ayarlamaktansa, gerekli tüm verileri tek bir dizi öğesinde depolamak çok daha uygundur. Böyle bir olasılığı uygulamak için bir yapı kullanılır. Gerekli tüm alanlar bir yapı içinde bildirilir. Bizim durumumuzda bunlar şu şekildedir:

  • kod - hata kodunu içeren int türü alanı,
  • desc - dize türü alanı. Hata açıklamasını içerir.

Aslında yapı bir bileşik veri türü'dür; yani yapılan değişken ve dizileri bildirmek için kullanılabilir. Sonuç olarak, Kod türünün her değişkeni bu yapının alanlarını içerecektir. Ayrıca, Kod türünün her dizi öğesi kodu ve açıklamasını depolamak için iki alan içerir. Böylece, farklı türlerdeki nesne verilerini tek bir konumda depolamak için oldukça uygun bir yol MQL5'te uygulanmaktadır.

Ardından _UserError ve _Error değişkenleri gelir. Her ikisi de en son meydana gelen hata hakkında bilgi içerir, ancak _UserError özel hatalar hakkında bilgi depolarken, _Error tüm hatalar hakkında bilgi depolar.

Ve üçüncü özellikler grubu. Birinci veya ikinci gruba dahil edilemeyen kalan tüm özellikleri buraya dahil ettim. Bunlar üç tanedir. İlki - _CountErrors, bilgileri _Errors dizisinde depolanan hataların sayısını içerir. Bu özellik, oluşturucuda ve dizi öğelerini çağırmak için bazı yöntemlerde _Errors dizisinin boyutunu ayarlamak için kullanılır. İkinci özellik _PlaySoundFile'dır. Bir hata oluştuğunda çalınan ses dosyasının adını depolar. Üçüncü özellik _DataPath'dir. Günlükleri tutmak için dosyanın yolunu ve adını depolar.

Sınıf Yöntemleri. Oluşturucu

Sonraki, oluşturucu ve sınıf yöntemlerinin açıklamasıdır. Oluşturucuyu göz önünde bulundurmaya başlayalım ve ne olduğunu anlamaya çalışalım. Yöntemler gibi, bu da bir sınıf içinde tanımlanan ortak bir işlevdir, ancak bazı belirli özelliklere sahiptir:

  • Oluşturucu adı, sınıf adını değiştirir.
  • Oluşturucunun bir dönüş değeri yoktur (void türü belirtilir).
  • Oluşturucunun giriş parametreleri yoktur.

Genellikle sınıf üyeleri oluşturucularda başlatılır. Örneğin sınıf oluşturucumuzda, rapor tutmayı devre dışı bırakacak tüm bayraklar ayarlanır, ses dosyasının ve günlük dosyasının adları belirtilir, _Errors dizisinin boyutu ayarlanır ve bu diziler verilerle doldurulur. Aşağıda, oluşturucu kodunun yalnızca bir bölümünü yayınlayacağım; zira çok büyük ve aynı türden - Ana bölüm _Errors dizisinin kodlar ve açıklamalarıyla doldurulur. Kodun tamamı makaleye eklenmiştir.

void ControlErrors::ControlErrors(void)
{
   SetAlert(false);
   SetPrint(false);
   SetSound(false);
   SetWriteFlag(false);
   SetPlaySoundFile("alert.wav");
   SetWritePath("LogErrors.txt");
   
   _CountErrors = 150;
   ArrayResize(Errors, _CountErrors);

   // Return codes of a trade server
   Errors[0].code = 10004;Errors[0].desc = "Requote";
   Errors[1].code = 10006;Errors[1].desc = "Request rejected";
   Errors[2].code = 10007;Errors[2].desc = "Request canceled by trader";
   Errors[3].code = 10008;Errors[3].desc = "Order placed";
   Errors[4].code = 10009;Errors[4].desc = "Request is completed";
   Errors[5].code = 10010;Errors[5].desc = "Request is partially completed";
   Errors[6].code = 10011;Errors[6].desc = "Request processing error";
   Errors[7].code = 10012;Errors[7].desc = "Request canceled by timeout";
   Errors[8].code = 10013;Errors[8].desc = "Invalid request";
   Errors[9].code = 10014;Errors[9].desc = "Invalid volume in the request";
   Errors[10].code = 10015;Errors[10].desc = "Invalid price in the request";
   Errors[11].code = 10016;Errors[11].desc = "Invalid stops in the request";
   Errors[12].code = 10017;Errors[12].desc = "Trade is disabled";
   Errors[13].code = 10018;Errors[13].desc = "Market is closed";
   Errors[14].code = 10019;Errors[14].desc = "There is not enough money to fulfill the request";
   Errors[15].code = 10020;Errors[15].desc = "Prices changed";
   Errors[16].code = 10021;Errors[16].desc = "There are no quotes to process the request";
   Errors[17].code = 10022;Errors[17].desc = "Invalid order expiration date in the request";
   Errors[18].code = 10023;Errors[18].desc = "Order state changed";
   Errors[19].code = 10024;Errors[19].desc = "Too frequent requests";
   Errors[20].code = 10025;Errors[20].desc = "No changes in request";
   Errors[21].code = 10026;Errors[21].desc = "Autotrading disabled by server";
   Errors[22].code = 10027;Errors[22].desc = "Autotrading disabled by client terminal";
   Errors[23].code = 10028;Errors[23].desc = "Request locked for processing";
   Errors[24].code = 10029;Errors[24].desc = "Order or position frozen";
   Errors[25].code = 10030;Errors[25].desc = "Invalid order filling type";

   // Common Errors
   Errors[26].code = 4001;Errors[26].desc = "Unexpected internal error";
   Errors[27].code = 4002;Errors[27].desc = "Wrong parameter in the inner call of the client terminal function";
   Errors[28].code = 4003;Errors[28].desc = "Wrong parameter when calling the system function";
   Errors[29].code = 4004;Errors[29].desc = "Not enough memory to perform the system function";
   Errors[30].code = 4005;Errors[30].desc = "The structure contains objects of strings and/or dynamic arrays and/or structure of such objects and/or classes";
   Errors[31].code = 4006;Errors[31].desc = "Array of a wrong type, wrong size, or a damaged object of a dynamic array";
   Errors[32].code = 4007;Errors[32].desc = "Not enough memory for the relocation of an array, or an attempt to change the size of a static array";
   Errors[33].code = 4008;Errors[33].desc = "Not enough memory for the relocation of string";
   Errors[34].code = 4009;Errors[34].desc = "Not initialized string";
   Errors[35].code = 4010;Errors[35].desc = "Invalid date and/or time";
   Errors[36].code = 4011;Errors[36].desc = "Requested array size exceeds 2 GB";
   Errors[37].code = 4012;Errors[37].desc = "Wrong pointer";
   Errors[38].code = 4013;Errors[38].desc = "Wrong type of pointer";
   Errors[39].code = 4014;Errors[39].desc = "System function is not allowed to call";

}

Lütfen uygulama açıklamasının sınıfın dışında yapıldığını unutmayın! Sınıf içinde yalnızca yöntemler bildirilir! Bu gerekli olmasa da. İsterseniz, sınıftaki her yöntemin gövdesini tanımlayabilirsiniz, ancak bence bu, elverişsiz ve anlaşılması zordur.

Dediğim gibi, sınıf gövdesinde yalnızca yöntem işlevlerinin üstbilgileri bildirilirken, açıklama sınıfın dışında yapılır. Bir yöntemi tanımlarken hangi sınıfa ait olduğunu belirtmelisiniz. şu işleme izin veren bağlam :: bunun için kullanılır. Yukarıdaki koddan görüldüğü gibi, önce bir yöntemin dönüş türü belirtilir (bir oluşturucu için bu void'dir), ardından sınıf adı (yöntemin ait olduğu bağlamın adı) gelir ve sınıf adından sonra işleme izin veren bağlam gelir ve daha sonra giriş parametreleriyle birlikte yöntem adı gelir. Tüm bunlardan sonra, yöntemin algoritma açıklaması başlar.

İlk olarak, oluşturucuda tüm bayraklar ayarlanır ve ses ve günlük dosyaları belirtilir: 

SetAlert(false);
SetPrint(false);
SetSound(false);
SetWriteFlag(false);
SetPlaySoundFile("alert.wav");
SetWritePath("LogErrors.txt"); 

Bu yöntemlerin her biri belirli bir sınıf özelliğiyle çalışır. Bu, kullanıcı tarafından özellikler için ayarlanan değerlerin filtrelenmesi gerekliliği durumunda özellikle yapılır. Örneğin, özel bir küme dosyası adı ve yolunun karşılık gelmesi gereken belirli bir maske ayarlayabilirsiniz. Artık maskeye yazışma varsa kullanıcı bu konuda bilgilendirilecektir. 

Bahsetmiş olabileceğiniz gibi, tüm bayraklar false değerini alır. Yani, bir sınıf örneği oluşturulduğunda varsayılan olarak hiçbir rapor tutulmayacaktır. Kullanıcı hangi raporların tutulacağını seçmeli ve OnInit() işlevinde aynı "Ayarla" yöntemlerini kullanarak bunları etkinleştirmelidir. Aynı şekilde, günlük dosyasının (yol, 'MetaTrader 5\MQL5\Files\' dizinine göre ayarlanır) ve ses dosyasının (yol, 'MetaTrader 5\Sounds\' dizinine göre ayarlanır) adını ve yolunu değiştirebilirsiniz.

Bayraklar ayarlandıktan sonra, _CountErrors değişkenini başlatıyor, ona 150 değerini atıyoruz (149 dizi ile ilgili bilgi dizide depolanır) ve ardından ArrayResize() işlevini kullanarak gerekli dizi boyutunu ayarlıyoruz. Bundan sonra diziyi doldurmaya başlıyoruz.

Bayrak Ayarlama Yöntemleri

Oluşturucu açıklamasını, bayrak ayarlama yöntemlerine ve ses ve günlük dosyası adlarının ayarlanmasına ilişkin açıklama izler:

void ControlErrors::SetAlert(bool value)
{
   _AlertInfo = value;
}

void ControlErrors::SetPrint(bool value)
{
   _PrintInfo = value;
}

void ControlErrors::SetSound(bool value)
{
   _PlaySound = value;
}

void ControlErrors::SetWriteFlag(bool flag)
{
   _WriteFile = flag;
}

void ControlErrors::SetWritePath(string path)
{
   _DataPath = path;
}

void ControlErrors::SetPlaySoundFile(string file)
{
   _PlaySoundFile = file;
}

Koddan görüldüğü gibi, bu, parametre yöntemine, sınıf özelliğine iletilen basit bir atamadır. Bayraklar herhangi bir kontrol gerektirmez; zira yalnızca iki değer alabilir. Ancak, atamadan önce dosya adlarının ve yollarının kontrol edilmesi gerekir.

Bu yöntemlerin yanı sıra diğerlerinin çağrıları aşağıdaki gibi görünür: 

type Class_name::Function_Name(parameters_description)
{
   // function body
}

Bir sonraki, hatalarla çalışma yöntemlerinin açıklamasıdır ve bunlardan ilki mGetLastError() ve mResetLastError()'dur.

mGetLastError() ve mResetLastError() yöntemleri 

mGetLastError() yöntem adı kendisi için konuşur. GetLastError() işlevini yineler. Ancak GetLastError() çağrısının yanı sıra, _Errors dizisinde elde edilen hata kodu için bir açıklama aranır ve hata ayrıntıları (kod ve açıklaması) _Error değişkenine kaydedilir; böylece her seferinde GetLastError() çağırmak yerine kaydedilen değer daha fazla kullanılır.

Yöntem kodu:

int ControlErrors::mGetLastError(void)
{
   _Error.code = GetLastError();
   _Error.desc = mGetDesc(_Error.code);
   return _Error.code;
}

mResetLastError() yöntemi ResetLastError() işlevini yineler:

void ControlErrors::mResetLastError(void)
{
   ResetLastError();
}

Son Hata Mesajıyla Çalışma Yöntemleri

Bunlar iki yöntemdir: mGetError() ve mResetError().

mGetError() yöntemi, _Error.code içinde bulunan kodu döndürür:

int ControlErrors::mGetError(void)
{
   return _Error.code;
}

mResetError() yöntemi, _Error değişkeninin içeriğini sıfırlar:

void ControlErrors::mResetError(void)
{
   _Error.code = 0;
   _Error.desc = "";
}

Hata Türü Belirleme Yöntemi mGetTypeError()

Sonraki yöntem mGetTypeError()'dur. Son oluşan hatanın özel bir hata mı yoksa önceden tanımlanmış bir hata mı (_Errors dizisinde bulunur) olup olmadığını kontrol eder.

Yöntem kodu:

int ControlErrors::mGetTypeError(void)
{
   if (mGetError() < ERR_USER_ERROR_FIRST)
   {
      return 0;
   }
   else if (mGetError() >= ERR_USER_ERROR_FIRST)
   {
      return 1;
   }
   return -1;
}

ERR_USER_ERROR_FIRST sabiti, 65536 değerine sahiptir. Bu kodlardan özel tanımlı hatalar başlar. Böylece yöntem gövdesinde en son alınan hata kodu kontrol edilir. Yöntem sıfır değerini döndürürse, bu, önceden tanımlanmış bir hatadır. Bir değeri döndürülürse, bu özel bir hatadır.

Özel Hatalarla Çalışma Yöntemleri

MQL5'te, kullanıcılar programın çalışması sırasında kendi hatalarını belirleyebilir. Özel kodların uygun açıklamalar atanabilmesi için, sınıfta _UserError özelliği mevcuttur. Bu özellik ile çalışmak için iki yöntem kullanılır.

mSetUserError() yöntemi, bir kod ayarlamak ve özel hatayı açıklamak için kullanılır:

void ControlErrors::mSetUserError(ushort value, string desc = "")
{
   SetUserError(value);
   _UserError.code = value;
   _UserError.desc = desc;
}

İlk olarak, SetUserError() işlevi, önceden tanımlanmış _LastError değişkenini ERR_USER_ERROR_FIRST + değerine eşit bir değere ayarlar. Ardından değer ve atanan uygun açıklaması _UserError değişkenine kaydedilir.

İkinci yöntem mResetUserError(), _UserError değişkeninin alanlarını sıfırlar:

void ControlErrors::mResetUserError(void)
{
   _UserError.code = 0;
   _UserError.desc = "";
}

Bu yöntem yalnızca _UserError değişkeniyle çalışabilir. _LastError sistem değişkeninin değerini sıfırlamak için başka bir yöntem kullanılır: mResetLastError(); bu, yukarıda açıklanmıştır.

Hata Kodu Açıklamasını Elde Etme Yöntemi

Ayrıca sınıfta özel bir mGetDesc() yöntemi vardır; bu yöntem, çağrıldığında Errors dizisinden veya hata bir kullanıcı tarafından ayarlanmışsa _UserError değişkeninin alan açıklamasından hata kodu açıklamasını döndürecektir:

string ControlErrors::mGetDesc(int nErr=0)
{
   int ErrorNumber = 0;
   string ReturnDesc = "";
   
   ErrorNumber = (mGetError()>0)?mGetError():ErrorNumber;
   ErrorNumber = (nErr>0)?nErr:ErrorNumber;
   
   if ((ErrorNumber > 0) && (ErrorNumber < ERR_USER_ERROR_FIRST))
   {
      for (int i = 0;i<_CountErrors;i++)
      {
         if (Errors[i].code == ErrorNumber)
         {
            ReturnDesc = Errors[i].desc;
            break;
         }
      }
   }
   else if (ErrorNumber > ERR_USER_ERROR_FIRST)
   {
      ReturnDesc = (_UserError.desc=="")?"Cusrom error":_UserError.desc;
   }
      
   if (ReturnDesc == ""){return "Unknown error code: "+(string)ErrorNumber;}
   return ReturnDesc;
}

Bu yöntem, bir nErr parametresine sahiptir . Varsayılan olarak sıfıra eşittir. Yöntem çağrısı sırasında parametreye bir değer ayarlanırsa ayar değeri için açıklama aranacaktır. Parametre ayarlanmazsa son alınan hata kodu için açıklama aranacaktır.

Başlangıçta, yöntemde iki değişken bildirilir: ErrorNumber - Bu değişken kullanılarak hata kodu işlenecektir ve ReturnDesc - ErrorNumber için elde edilen açıklama bunun içinde saklanacaktır. Sonraki iki satırda ErrorNumber'a bir değer atanırken ?: koşullu işleci kullanılır. Bu, if-else yapısının basitleştirilmiş bir analogudur.

ErrorNumber = (mGetError()>0)?mGetError():ErrorNumber;
ErrorNumber = (nErr>0)?nErr:ErrorNumber;

İlk satırda şunları tanımlarız: Bir hata düzeltildiyse, yani mGetError() sıfırdan farklı bir sonuç döndürdüyse, elde edilen hata kodu (mGetError() yöntemi tarafından döndürülen değer) ErrorNumber değişkenine atanacaktır; aksi takdirde ErrorNumber değişkeninin değeri atanacaktır. İkinci satırda aynı kontrol gerçekleştirilir ama bu, mGetError() yönteminin parametresi için yapılır. nErr değeri sıfır değilse, bu, ErrorNumber değişkenine atanır.

Hata kodunu aldığımızda, bu kod için açıklamaları aramaya başlayın. Elde edilen kod sıfırdan büyük ve ERR_USER_ERROR_FIRST'ten küçükse, yani özel bir hata değilse, açıklamasını bir döngü içinde ararız. Ve elde edilen kod ERR_USER_ERROR_FIRST'den büyükse, _UserError değişkeninin alan açıklamasından bir açıklama alırız.

Sonunda, açıklamanın bulunup bulunmadığını kontrol ederiz. Yoksa, bilinmeyen hata kodu mesajı döndürür.

Sinyal Yöntemleri

Sinyal yöntemleri mAlert(), mPrint() ve mSound() yöntemlerini içerir. Düzenlemelerinde, bu yöntemler çok benzerdir:

void ControlErrors::mAlert(string message="")
{
   if (_AlertInfo == true)
   {
      if (message == "")
      {
         if (mGetError() > 0)
         {
            Alert("Error №",mGetError()," - ",mGetDesc());
         }
      }
      else
      {
         Alert(message);
      }   
   }
}

void ControlErrors::mPrint(string message="")
{
   if (_PrintInfo == true)
   {
      if (message == "")
      {
         if (mGetError() > 0)
         {
            Print("Error №",mGetError()," - ",mGetDesc());
         }
      }
      else
      {
         Print(message);
      }
   }
}

void ControlErrors::mSound(void)
{
   if (_PlaySound == true)
   {
      PlaySound(_PlaySoundFile);
   }
}

Üç yöntemin tamamında, başlangıçta raporlara ve sinyallere izin veren bayrak kontrol edilir. Daha sonra, yöntemlerde (mAlert() and mPrint()), giriş parametresi mesajı Uyarı iletişim kutusunda görüntülenmesi veya günlüğe eklenmesi gereken mesaj kontrol edilir. Bu, mesaj'da bir mesaj ayarlanmışsa ve son hata kodu sıfırdan büyükse görüntülenir. Değilse, standart bir mesaj görüntülenir. mSound() yöntemi herhangi bir parametreye sahip değildir; bu nedenle bayrak kontrol edildikten sonra, bir ses üretmek için hemen PlaySound() işlevi çağrılır.

Check() Yöntemi

Bu yöntem, yalnızca bu sınıfın tüm işlevlerini doğru dizide çağırır; böylece yeni bir hatanın oluşup oluşmadığı kontrol edilir, izin verilen tüm raporlar düzenlenir ve bunun hemen ardından hata kodu ve açıklaması silinir. Böylece, Check() yöntemi kapsamlı bir kontrol gerçekleştirir:

int ControlErrors::Check(string st="")
{
   int errNum = 0;
   errNum = mGetLastError();
   mFileWrite();
   mAlert(st);
   mPrint(st);
   mSound();
   mResetError();
   mResetLastError();
   mResetUserError();
   return errNum;
}

Check(), dize türünde bir parametre içerir. Bu, raporlara yazılmak üzere mAlert() ve mPrint() yöntemlerine iletilen özel bir mesajdır.

Günlük Dosyasına Mesaj Yazma Yöntemleri

Bu yöntem, mFileWrite() olarak adlandırılır. Bir günlük dosyası tutulmasına izin veriliyorsa ve dosyanın yolu doğru bir şekilde belirtilirse - bu yöntem kaydı belirtilen dosyaya yapar.

int ControlErrors::mFileWrite(string message = "")
{
   int      handle  = 0,
            _return = 0;
   datetime time    = TimeCurrent();
   string   text    = (message != "")?message:time+" - Error №"+mGetError()+" "+mGetDesc();
   
   if (_WriteFile == true)
   {
      handle = FileOpen(_DataPath,FILE_READ|FILE_WRITE|FILE_TXT|FILE_ANSI);
      if (handle != INVALID_HANDLE)
      {
         ulong size = FileSize(handle);
         FileSeek(handle,size,SEEK_SET);
         _return = FileWrite(handle,text);
         FileClose(handle);
      }
   }
   return _return;
}

Başlangıçta  dört değişken bildirilir: işle - açık bir dosyanın tanıtıcısını depolamak için, _return - dönüş değerini depolamak için, zaman, mevcut zamanı depolamak için (dosyaya kaydetme zamanı) ve metin - dosyaya yazılacak metin mesajı. mFileWrite() yöntemi bir giriş parametresine sahiptir - Kullanıcının dosyaya yazılması gereken dizeyi ilettiği mesaj.

Bu özellik, belirli anlarda gösterge değerleri, fiyatlar ve diğer gerekli verileri kaydetmek için kullanılabilir.

Değişkenler bildirildikten sonra, _WriteFile bayrağı kontrol edilir. Ve bir günlük dosyasının tutulmasına izin veriliyorsa dosya FileOpen() işlevi kullanılarak yeniden yazılmak üzere açılır. FileOpen() öğesinin ilk parametresi, dosya adını ve buna giden yolu içeren DataPath özelliğidir. İkinci parametre, bayraklarla çalışma modunu belirleyen bir bayraklar kümesi'dir. Bizim durumumuzda, dört bayrak kullanılır:

  • FILE_READ ve FILE_WRITE birlikte, veri ekleme olanağı olan boş olmayan bir dosyayı açmaya yönlendirir.
  • FILE_TXT, çalışmanın basit bir metin dosyası ile gerçekleştirileceğini gösterir.
  • FILE_ANSI, verilerin dosyaya ANSI türünde (tek baytlı semboller) dizeler olarak yazılacağını belirtir.

Bir sonraki adımda dosyanın başarıyla açılıp açılmadığını kontrol ederiz. Başarıyla açılmadıysa, tanıtıcı INVALID_HANDLE değerine sahip olacak ve yöntem işlemi burada sona erecektir. Ancak başarıyla açıldıysa, FileSize() kullanarak dosya boyutunu elde ederiz, ardından FileSeek() öğesini kullanarak dosya işaretçisinin pozisyonunu dosya sonuna taşırız ve FileWrite() işlevini kullanarak dosyanın sonuna bir mesaj ekleriz. Bunun ardından, FileClose() işlevini kullanarak bu dosyayı kapatın.

FileSize() işlevi için bir giriş parametresi olarak, boyutunu döndürmemiz gereken dosyanın tanıtıcısını iletin. Bu, bu işlevin tek parametresidir.

FileSeek()'in çalışması için üç parametrenin belirtilmesi gerekir:

  • Çalıştığımız dosyanın tanıtıcısı.
  • Dosya işaretçisinin üst karakteri.
  • Üst karakter için referans noktası. Bu, ENUM_FILE_POSITION değerlerinden birini alır.

FileWrite() işlevinin çalışması için en az iki parametre gereklidir. Bu, metin verilerini yazmamız gereken bir dosyanın tanıtıcısıdır. İkincisi, yazılması gereken bir metin satırı ve dosyaya yazılacak sonraki tüm metin satırlarıdır. Parametre sayısı 63'ü geçmemelidir.

FileClose() işlevi, onu kapatmak için aynı zamanda dosya tanıtıcısına da ihtiyaç duyar.

Örnekler

Şimdi yazdığımız sınıfı kullanmanın birkaç yaygın örneğini eklemek istiyorum. Nesne oluşturma ile başlayalım ve gerekli raporların tutulmasına olanak tanıyalım.

Şimdi bir sınıf nesnesi oluşturalım:

#include <ControlErrors.mqh>

ControlErrors mControl;

Bir nesne oluşturmadan önce, sınıf açıklamasını içeren dosyayı Expert Advisor'a eklememiz gerekir. Bu, programın en başında #include yönergesiyle yapılır. Ve ancak bundan sonra nesne oluşturulur; bu, yeni bir değişken oluşturmakla aynı şekilde görünür. Ancak, veri türü yerine sınıf adı eklenir. 

Şimdi almak istediğimiz hata raporlarını oluşturalım. Bu, OnInit() işlevinde yapılır: 

int OnInit()
{
//---
mControl.SetAlert(true);
mControl.SetPrint(true);
mControl.SetSound(false);
mControl.SetWriteFlag(true);
mControl.SetPlaySoundFile("news.wav");
//---
return(0);
}

Varsayılan olarak, bir nesne oluşturulduğunda, izin verilen tüm bayraklar false olarak ayarlanır; yani tüm raporlar devre dışı bırakılır. Bu nedenle, OnInit()'te, yukarıdaki örnekte (SetSound() yöntemi) yapıldığı için, false değerine sahip yöntemleri çağırmak gerekli değildir. Bu yöntemler, diğer program bölümlerinde de çağrılabilir. Örneğin, belirli koşullar altında rapor tutmayı devre dışı bırakmanız gerekiyorsa bu koşulları programlayabilir ve koşullar yerine getirildiğinde bayrakları gerekli değerlere ayarlayabilirsiniz.

Ve burada belirtilmesi gereken bir nokta da, program çalışırken yöntemlerin çağrılması ve hataların "yakalanması"dır. Bu kısım zor değil; zira burada ondan önce tüm bayrakları ayarlayarak tek bir Check() yöntemini kullanabilirsiniz:

mControl.Check();

Bu yöntem, yukarıda belirtildiği gibi, oluşan hatanın kodunu belirleyecek, raporları tutan tüm yöntemleri çağıracak ve ardından son hata hakkında bilgi içeren tüm değişkenlerin değerlerini sıfırlayacaktır. Check() tarafından sunulan hata işleme şekli bazı nedenlerden dolayı uygun değilse, mevcut sınıf yöntemlerini kullanarak kendi raporlarınızı oluşturabilirsiniz.

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

Ekli dosyalar |
controlerrors.mqh (19.82 KB)
MetaTrader 5: Bloglarda, sosyal ağlarda ve özel web sitelerinde e-posta yoluyla alım satım tahminleri ve canlı alım satım beyanları yayınlamak MetaTrader 5: Bloglarda, sosyal ağlarda ve özel web sitelerinde e-posta yoluyla alım satım tahminleri ve canlı alım satım beyanları yayınlamak
Bu makale, MetaTrader 5 kullanarak tahmin yayınlamak için hazır çözümler sunulmasına yöneliktir. Bu, MetaTrader beyanlarını yayınlamak için özel web siteleri kullanmaktan, kişinin neredeyse hiç web programlama deneyimi gerektirmeden kendi web sitesini kurmasına ve son olarak birçok okuyucunun katılmasına ve tahminleri takip etmesine izin veren bir sosyal ağ mikroblog hizmeti ile entegrasyona kadar bir dizi fikri içerir. Burada sunulan tüm çözümler %100 ücretsizdir ve temel e-posta ve ftp hizmetleri bilgisi olan herkes tarafından kurulabilir. Profesyonel barındırma ve ticari alım satım tahmini hizmetleri için aynı tekniklerin kullanılması konusunda hiçbir engel yoktur.
Piyasa Analizi için Veritabanlarının Pratik Uygulaması Piyasa Analizi için Veritabanlarının Pratik Uygulaması
Verilerle çalışmak, hem bağımsız hem de ağ uygulamaları için modern yazılımların ana görevi haline geldi. Bu sorunu çözmek için özel bir yazılım oluşturuldu. Bunlar, bilgisayar depolama ve işlemeleri için verileri yapılandırabilen, sistematikleştirebilen ve düzenleyebilen Veritabanı Yönetim Sistemleridir (DBMS). Alım satım işlemine gelince, analistlerin çoğu çalışmalarında veritabanlarını kullanmaz. Ancak böyle bir çözümün işe yaraması gereken görevler vardır. Bu makale, hem istemci-sunucu hem de dosya-sunucu mimarileriyle veritabanlarından veri kaydedebilen ve yükleyebilen göstergelere ilişkin bir örnek sağlar.
MQL4'ten MQL5'e geçiş MQL4'ten MQL5'e geçiş
Bu makale MQL4 dil işlevleri için hızlı bir rehber olup programlarınızı MQL4'ten MQL5'e geçirmeniz konusunda size yardımcı olacaktır. Her MQL4 işlevi için (alım satım işlevleri hariç) açıklama ve MQL5 uygulaması sunulur, dönüştürme süresini önemli ölçüde azaltmanıza olanak tanır. Kolaylık sağlamak için MQL4 işlevleri, MQL4 Referansı'na benzer şekilde gruplara ayrılmıştır.
Göstergeleri MQL4'ten MQL5'e Aktarma Göstergeleri MQL4'ten MQL5'e Aktarma
Bu makale, MQL4'te yazılan fiyat yapılarının MQL5'e aktarılmasına ilişkin özelliklere ayrılmıştır. Gösterge hesaplamalarını MQL4'ten MQL5'e aktarma işlemini kolaylaştırmak için mql4_2_mql5.mqh işlevler kitaplığı önerilir. Kullanımı MACD, Stokastik ve RSI göstergelerinin aktarımı temelinde açıklanmıştır.