English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
Çok Zaman Dilimli ve Çok Para Birimli Paneller Oluşturmaya Yönelik Nesne Yönelimli Yaklaşım

Çok Zaman Dilimli ve Çok Para Birimli Paneller Oluşturmaya Yönelik Nesne Yönelimli Yaklaşım

MetaTrader 5Örnekler | 9 Aralık 2021, 12:46
44 0
Marcin Konieczny
Marcin Konieczny

Giriş

Bu makale, MetaTrader 5 için çok zaman dilimli ve çok para birimli paneller oluşturmak için nesne yönelimli programlamanın nasıl kullanılabileceğini açıklar. Ana amaç, panelin kodunu değiştirmeye gerek kalmadan fiyatlar, fiyat değişiklikleri, gösterge değerleri veya özel alım/satım koşulları gibi birçok farklı veri türünü görüntülemek için kullanılabilecek evrensel bir panel oluşturmaktır. Bu şekilde, paneli ihtiyacımız olan herhangi bir şekilde özelleştirmek için çok az kodlama gerekli olacaktır.

Anlatacağım çözüm iki modda çalışır:

  1. Çok zaman dilimli mod - mevcut sembolde hesaplanan tablo içeriklerini, ancak farklı zaman dilimlerinde görmenizi sağlar;
  2. Çok para birimli mod - mevcut zaman diliminde hesaplanan tablo içeriklerini, ancak farklı sembollerde görmenizi sağlar.

Aşağıdaki resimler paneli bu iki modda göstermektedir.

Birincisi çok zaman dilimli modda çalışır ve aşağıdaki verileri görüntüler:

  1. Mevcut fiyat;
  2. Mevcut çubuğun fiyat değişimi;
  3. Mevcut çubuğun yüzde olarak fiyat değişimi;
  4. Mevcut çubuğun bir ok olarak (yukarı/aşağı) fiyat değişimi;
  5. RSI(14) gösterge değeri;
  6. RSI(10) gösterge değeri;
  7. Özel durum: SMA(20) > mevcut fiyat.

Şekil 1. Çok zaman dilimli mod

Şekil 1. Çok zaman dilimli mod


İkincisi, çok para birimli modda çalışır ve şunu gösterir:

  1. Mevcut fiyat;
  2. Mevcut çubuğun fiyat değişimi;
  3. Mevcut çubuğun yüzde olarak fiyat değişimi;
  4. Mevcut çubuğun bir ok olarak fiyat değişimi;
  5. RSI(10) gösterge değeri;
  6. RSI(14) gösterge değeri;
  7. Özel durum: SMA(20) > mevcut fiyat.

Şekil 2. Çok para birimli mod

Şekil 2. Çok para birimli mod


1. Uygulama

Aşağıdaki sınıf diyagramı, panelin uygulama tasarımını açıklar.

Şekil 3. Panelin sınıf diyagramı

Şekil 3 Panelin sınıf diyagramı


Diyagramın öğelerini açıklayayım:

  1. CTable. Panelin çekirdek sınıfı. Panelin çiziminden ve bileşenlerinin yönetiminden sorumludur.
  2. SpyAgent. Diğer semboller (enstrümanlar) üzerinde 'casusluktan' sorumlu bir göstergedir. Her aracı oluşturulur ve farklı bir sembole gönderilir. Aracı, sembol grafiğine yeni bir tik geldiğinde OnCalculate etkinliğine tepki verir ve CTable nesnesini güncellemesi gerektiğini bildirmek için CHARTEVENT_CUSTOM etkinliğini gönderir. Bu yaklaşımın arkasındaki tüm fikir, "MetaTrader 5'te Çok Para Birimli Modun Uygulanması" makalesine dayanmaktadır. Tüm teknik detayları burada bulabilirsiniz.
  3. CRow. Paneli oluşturmak için kullanılan tüm göstergeler ve koşullar için temel sınıf. Bu sınıfı genişleterek, panelin gerekli tüm bileşenlerini oluşturmak mümkündür.
  4. CPriceRow. Mevcut teklif fiyatını görüntülemek için kullanılan basit CRow’u genişleten sınıf.
  5. CPriceChangeRow. Mevcut çubuğun fiyat değişimini görüntülemek için kullanılan CRow’u genişleten sınıf. Fiyat değişikliklerini, yüzde değişikliklerini veya okları gösterebilir.
  6. CRSIRow. Mevcut RSI gösterge değerini görüntülemek için kullanılan CRow’u genişleten sınıf.
  7. CPriceMARow. Özel bir koşul sergileyen CRow’u genişleten sınıf: SMA > mevcut fiyat.

CTable ve CRow sınıflarının yanı sıra SpyAgent göstergesi, panelin temel parçalarıdır. CPriceRow, CPriceChangeRow, CRSIRow ve CPriceMARow, panelin gerçek içerikleridir. CRow sınıfı, istenen sonucu elde etmek için birçok yeni sınıf tarafından genişletilecek şekilde tasarlanmıştır. Sunulan dört türetilmiş sınıf, ne yapılabileceğine ve nasıl yapılabileceğine dair basit örneklerdir.


2. SpyAgent

SpyAgent göstergesiyle başlayacağız. Bu, yalnızca çok para birimli modda kullanılır ve diğer grafiklerde yeni bir tik geldiğinde paneli düzgün bir şekilde güncellemek için gereklidir. Bu kavramın ayrıntılarına pek girmeyeceğim. Bunlar "MetaTrader 5’te Çok Para Birimli Modun Uygulanması" makalesinde açıklanmıştır.

SpyAgent göstergesi, belirtilen sembolün grafiği üzerinde çalışır ve iki etkinlik gönderir: başlatma etkinliği ve yeni tik etkinliği. Her iki etkinlik de CHARTEVENT_CUSTOM türündedir. Bu etkinlikleri işlemek için OnChartEvent(...) işleyicisini kullanmalıyız (makalenin ilerleyen bölümlerinde gösterilecektir).

SpyAgent'ın koduna bir göz atalım:

//+------------------------------------------------------------------+
//|                                                     SpyAgent.mq5 |
//|                                                 Marcin Konieczny |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Marcin Konieczny"
#property indicator_chart_window
#property indicator_plots 0

input long   chart_id=0;        // chart id
input ushort custom_event_id=0; // event id
//+------------------------------------------------------------------+
//| Indicator iteration function                                     |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
  {

   if(prev_calculated==0)
      EventChartCustom(chart_id,0,0,0.0,_Symbol); // sends initialization event
   else
      EventChartCustom(chart_id,(ushort)(custom_event_id+1),0,0.0,_Symbol); // sends new tick event

   return(rates_total);
  }
Bu oldukça basittir. Yaptığı tek şey yeni tikler almak ve CHARTEVENT_CUSTOM etkinlikleri göndermektir.


3. CTable

CTable, panelin çekirdek sınıfıdır. Panel ayarlarıyla ilgili bilgileri depolar ve bileşenlerini yönetir. Gerektiğinde paneli günceller (yeniden çizer).

CTable sınıfının bildirimine bakalım:

//+------------------------------------------------------------------+
//| CTable class                                                     |
//+------------------------------------------------------------------+
class CTable
  {
private:
   int               xDistance;    // distance from right border of the chart
   int               yDistance;    // distance from top of the chart
   int               cellHeight;   // table cell height
   int               cellWidth;    // table cell width
   string            font;         // font name
   int               fontSize;
   color             fontColor;

   CList            *rowList;      // list of row objects
   bool              tfMode;       // is in multi-timeframe mode?

   ENUM_TIMEFRAMES   timeframes[]; // array of timeframes for multi-timeframe mode
   string            symbols[];    // array of currency pairs for multi-currency mode

   //--- private methods
   //--- sets default parameters of the table
   void              Init();
   //--- draws text label in the specified table cell
   void              DrawLabel(int x,int y,string text,string font,color col);
   //--- returns textual representation of given timeframe
   string            PeriodToString(ENUM_TIMEFRAMES period);

public:
   //--- multi-timeframe mode constructor
                     CTable(ENUM_TIMEFRAMES &tfs[]);
   //--- multi-currency mode constructor
                     CTable(string &symb[]);
   //--- destructor
                    ~CTable();
   //--- redraws table
   void              Update();
   //--- methods for setting table parameters
   void              SetDistance(int xDist,int yDist);
   void              SetCellSize(int cellW,int cellH);
   void              SetFont(string fnt,int size,color clr);
   //--- appends CRow object to the of the table
   void              AddRow(CRow *row);
  };

Gördüğünüz gibi, tüm panel bileşenleri (satırlar) CRow işaretçilerinin bir listesi olarak depolanıyor, bu nedenle panele eklemek istediğimiz her bileşenin CRow sınıfını genişletmesi gerekiyor. CRow, panel ve bileşenleri arasında bir sözleşme olarak görülebilir. CTable, hücrelerinin hesaplanması için herhangi bir kod içermez. Bu, CRow'u genişleten sınıfların sorumluluğundadır. CTable sadece CRow bileşenlerini tutmak ve gerektiğinde yeniden çizmek için kullanılan bir yapıdır.

Şimdi CTable yöntemlerini inceleyelim. Sınıfın iki yapıcısı vardır. Birincisi çok zaman dilimli mod için kullanılır ve oldukça basittir. Yalnızca görüntülemek istediğimiz bir dizi zaman dilimi sağlamamız gerekir.

//+------------------------------------------------------------------+
//| Multi-timeframe mode constructor                                 |
//+------------------------------------------------------------------+
CTable::CTable(ENUM_TIMEFRAMES &tfs[])
  {
//--- copy all timeframes to own array
   ArrayResize(timeframes,ArraySize(tfs),0);
   ArrayCopy(timeframes,tfs);
   tfMode=true;
   
//--- fill symbols array with current chart symbol
   ArrayResize(symbols,ArraySize(tfs),0);
   for(int i=0; i<ArraySize(tfs); i++)
      symbols[i]=Symbol();

//--- set default parameters
   Init();
  }

İkinci yapıcı çok para birimli mod için kullanılır ve bir dizi sembol (enstrüman) alır. Bu da SpyAgent'ları gönderir. Bunları uygun grafiklere birer birer ekler.

//+------------------------------------------------------------------+
//| Multi-currency mode constructor                                  |
//+------------------------------------------------------------------+
CTable::CTable(string &symb[])
  {
//--- copy all symbols to own array
   ArrayResize(symbols,ArraySize(symb),0);
   ArrayCopy(symbols,symb);
   tfMode=false;
   
//--- fill timeframe array with current timeframe
   ArrayResize(timeframes,ArraySize(symb),0);
   ArrayInitialize(timeframes,Period());

//--- set default parameters
   Init();

//--- send SpyAgents to every requested symbol
   for(int x=0; x<ArraySize(symbols); x++)
      if(symbols[x]!=Symbol()) // don't send SpyAgent to own chart
         if(iCustom(symbols[x],0,"SpyAgent",ChartID(),0)==INVALID_HANDLE)
           {
            Print("Error in setting of SpyAgent on "+symbols[x]);
            return;
           }
  }

Init yöntemi, satırların listesini oluşturur (CList nesnesi olarak - CList, CObject türlerinin dinamik bir listesidir) ve CTable dahili değişkenleri (yazı tipi, yazı tipi boyutu, renk, hücre boyutu ve sağ üst grafik köşesinden uzaklık) için varsayılan değerleri ayarlar).

//+------------------------------------------------------------------+
//| Sets default parameters of the table                             |
//+------------------------------------------------------------------+
CTable::Init()
  {
//--- create list for storing row objects
   rowList=new CList;

//--- set defaults
   xDistance = 10;
   yDistance = 10;
   cellWidth = 60;
   cellHeight= 20;
   font="Arial";
   fontSize=10;
   fontColor=clrWhite;
  }

Yıkıcı oldukça basittir. Satır listesini siler ve panel tarafından oluşturulan tüm grafik nesnelerini (etiketleri) siler.

//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CTable::~CTable()
  {
   int total=ObjectsTotal(0);

//--- remove all text labels from the chart (all object names starting with nameBase prefix)
   for(int i=total-1; i>=0; i--)
      if(StringFind(ObjectName(0,i),nameBase)!=-1)
         ObjectDelete(0,ObjectName(0,i));

//--- delete list of rows and free memory
   delete(rowList);
  }

AddRow yöntemi, yeni satırı satır listesine ekler. rowList'in otomatik olarak yeniden boyutlandırılan bir CList nesnesi olduğunu unutmayın. Bu yöntem, eklenen her CRow nesnesi için Init yöntemini de çağırır. Nesnenin dahili değişkenlerini düzgün bir şekilde başlatmasına izin vermek gerekir. Örneğin, gösterge veya dosya tanıtıcıları oluşturmak için Inıt çağrısını kullanabilir.

//+------------------------------------------------------------------+
//| Appends new row to the end of the table                          |
//+------------------------------------------------------------------+
CTable::AddRow(CRow *row)
  {
   rowList.Add(row);
   row.Init(symbols,timeframes);
  }

Güncelleme yöntemi biraz daha karmaşıktır. Panelin yeniden çizilmesi için kullanılır.

Temel olarak, üç bölümden oluşur:

  • Birinci sütunu çizme (satırların adları)
  • Birinci satırın çizilmesi (seçilen moda bağlı olarak zaman dilimlerinin veya sembollerin adları)
  • Dahili hücrelerin çizimi (bileşenlerin değerleri)

Her bileşenin, sağlanan sembol ve zaman dilimine göre kendi değerini hesaplamasını istediğimizi belirtmekte fayda var. Ayrıca hangi yazı tipinin ve rengin kullanılması gerektiğine bileşenin karar vermesine izin veriyoruz.

//+------------------------------------------------------------------+
//| Redraws the table                                                |
//+------------------------------------------------------------------+
CTable::Update()
  {
   CRow *row;
   string symbol;
   ENUM_TIMEFRAMES tf;

   int rows=rowList.Total(); // number of rows
   int columns;              // number of columns

   if(tfMode)
      columns=ArraySize(timeframes);
   else
      columns=ArraySize(symbols);

//--- draw first column (names of rows)
   for(int y=0; y<rows; y++)
     {
      row=(CRow*)rowList.GetNodeAtIndex(y);
      //--- note: we ask row object to return its name
      DrawLabel(columns,y+1,row.GetName(),font,fontColor);
     }

//--- draws first row (names of timeframes or currency pairs)
   for(int x=0; x<columns; x++)
     {
      if(tfMode)
         DrawLabel(columns-x-1,0,PeriodToString(timeframes[x]),font,fontColor);
      else
         DrawLabel(columns-x-1,0,symbols[x],font,fontColor);
     }

//--- draws inside table cells
   for(int y=0; y<rows; y++)
      for(int x=0; x<columns; x++)
        {
         row=(CRow*)rowList.GetNodeAtIndex(y);

         if(tfMode)
           {
            //--- in multi-timeframe mode use current symbol and different timeframes
            tf=timeframes[x];
            symbol=_Symbol;
           }
         else
           {
            //--- in multi-currency mode use current timeframe and different symbols
            tf=Period();
            symbol=symbols[x];
           }

         //--- note: we ask row object to return its font, 
         //--- color and current calculated value for given timeframe and symbol
         DrawLabel(columns-x-1,y+1,row.GetValue(symbol,tf),row.GetFont(symbol,tf),row.GetColor(symbol,tf));
        }

//--- forces chart to redraw
   ChartRedraw();
  }

DrawLabel yöntemi, panelin belirtilen hücresinde metin etiketleri çizmek için kullanılır. İlk olarak, bu hücre için bir etiketin var olup olmadığını kontrol eder. Değilse, yeni bir tane oluşturur.

Ardından, gerekli tüm etiket özelliklerini ve metnini ayarlar.

//+------------------------------------------------------------------+
//| Draws text label in the specified cell of the table              |
//+------------------------------------------------------------------+  
CTable::DrawLabel(int x,int y,string text,string font,color col)
  {
//--- create unique name for this cell
   string name=nameBase+IntegerToString(x)+":"+IntegerToString(y);

//--- create label
   if(ObjectFind(0,name)<0)
      ObjectCreate(0,name,OBJ_LABEL,0,0,0);

//--- set label properties
   ObjectSetInteger(0,name,OBJPROP_CORNER,CORNER_RIGHT_UPPER);
   ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_RIGHT_UPPER);
   ObjectSetInteger(0,name,OBJPROP_XDISTANCE,xDistance+x*cellWidth);
   ObjectSetInteger(0,name,OBJPROP_YDISTANCE,yDistance+y*cellHeight);
   ObjectSetString(0,name,OBJPROP_FONT,font);
   ObjectSetInteger(0,name,OBJPROP_COLOR,col);
   ObjectSetInteger(0,name,OBJPROP_FONTSIZE,fontSize);

//--- set label text
   ObjectSetString(0,name,OBJPROP_TEXT,text);
  }

Diğer yöntemler çok basit ve daha az önemli oldukları için burada sunulmayacaktır. Kodun tamamı makalenin altında indirilebilir.


4. CRow'u Genişletme

CRow, panel tarafından kullanılabilen tüm bileşenler için bir temel sınıftır.

CRow sınıfının koduna bakalım:

//+------------------------------------------------------------------+
//| CRow class                                                       |
//+------------------------------------------------------------------+
//| Base class for creating custom table rows                        |
//| one or more methods of CRow should be overriden                  |
//| when creating own table rows                                     |
//+------------------------------------------------------------------+
class CRow : public CObject
  {
public:
   //--- default initialization method
   virtual void Init(string &symb[],ENUM_TIMEFRAMES &tfs[]) { }

   //--- default method for obtaining string value to display in the table cell
   virtual string GetValue(string symbol,ENUM_TIMEFRAMES tf) { return("-"); }

   //--- default method for obtaining color for table cell
   virtual color GetColor(string symbol,ENUM_TIMEFRAMES tf) { return(clrWhite); }
   
   //--- default method for obtaining row name
   virtual string GetName() { return("-"); }

   //--- default method for obtaining font for table cell
   virtual string GetFont(string symbol,ENUM_TIMEFRAMES tf) { return("Arial"); }
  };

CObject'i genişletir, çünkü bir CList yapısında yalnızca CObjects saklanabilir. Neredeyse boş olan beş yöntemi vardır. Daha kesin olmak gerekirse, çoğu yalnızca varsayılan değerleri vermektedir. Bu yöntemler, CRow genişletilirken geçersiz kılınacak şekilde tasarlanmıştır. Hepsini geçersiz kılmamıza gerek yok, sadece istediklerimizi geçersiz kılarız.

Örnek olarak, mümkün olan en basit panel bileşenini oluşturalım - mevcut teklif fiyatı bileşeni. Çeşitli enstrümanların mevcut fiyatlarını görüntülemek için çok para birimli modda kullanılabilir.

Bunu başarmak için şuna benzeyen bir CPriceRow sınıfı oluşturuyoruz:

//+------------------------------------------------------------------+
//| CPriceRow class                                                  |
//+------------------------------------------------------------------+
class CPriceRow : public CRow
  {
public:
   //--- overrides default GetValue(..) method from CRow
   virtual string    GetValue(string symbol,ENUM_TIMEFRAMES tf);

   //--- overrides default GetName() method from CRow
   virtual string    GetName();

  };
//+------------------------------------------------------------------+
//| Overrides default GetValue(..) method from CRow                  |
//+------------------------------------------------------------------+
string CPriceRow::GetValue(string symbol,ENUM_TIMEFRAMES tf)
  {
   MqlTick tick;

//--- gets current price
   if(!SymbolInfoTick(symbol,tick)) return("-");

   return(DoubleToString(tick.bid,(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS)));
  }
//+------------------------------------------------------------------+
//| Overrides default GetName() method from CRow                     |
//+------------------------------------------------------------------+
string CPriceRow::GetName()
  {
   return("Price");
  }

Burada geçersiz kılmayı seçtiğimiz yöntemler GetValue ve GetName yöntemleridir. GetName, panelin birinci sütununda görüntülenecek olan bu satırın adını verir. GetValue, belirtilen sembol üzerindeki en son işareti alır ve en son teklif fiyatını verir. İhtiyacımız olan tek şey budur.

Bu oldukça basitti. Farklı bir şey yapalım. Şimdi mevcut RSI değerini gösteren bir bileşen oluşturacağız.

Kod öncekine benzer:

//+------------------------------------------------------------------+
//| CRSIRow class                                                    |
//+------------------------------------------------------------------+
class CRSIRow : public CRow
  {
private:
   int               rsiPeriod;        // RSI period
   string            symbols[];        // symbols array
   ENUM_TIMEFRAMES   timeframes[];     // timeframes array
   int               handles[];        // array of RSI handles

   //--- finds the indicator handle for a given symbol and timeframe
   int               GetHandle(string symbol,ENUM_TIMEFRAMES tf);

public:
   //--- constructor
                     CRSIRow(int period);

   //--- overrides default GetValue(..) method from CRow
   virtual string    GetValue(string symbol,ENUM_TIMEFRAMES tf);

   //--- overrides default GetName() method from CRow
   virtual string    GetName();

   //--- overrides default Init(..) method from CRow
   virtual void      Init(string &symb[],ENUM_TIMEFRAMES &tfs[]);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CRSIRow::CRSIRow(int period)
  {
   rsiPeriod=period;
  }
//+------------------------------------------------------------------+
//| Overrides default Init(..) method from CRow                      |
//+------------------------------------------------------------------+
void CRSIRow::Init(string &symb[],ENUM_TIMEFRAMES &tfs[])
  {
   int size=ArraySize(symb);
   
   ArrayResize(symbols,size);
   ArrayResize(timeframes,size);
   ArrayResize(handles,size);
   
//--- copies arrays contents into own arrays
   ArrayCopy(symbols,symb);
   ArrayCopy(timeframes,tfs);
  
//--- gets RSI handles for all used symbols or timeframes
   for(int i=0; i<ArraySize(symbols); i++)
      handles[i]=iRSI(symbols[i],timeframes[i],rsiPeriod,PRICE_CLOSE);
  }
//+------------------------------------------------------------------+
//| Overrides default GetValue(..) method from CRow                  |
//+------------------------------------------------------------------+
string CRSIRow::GetValue(string symbol,ENUM_TIMEFRAMES tf)
  {
   double value[1];

//--- gets RSI indicator handle
   int handle=GetHandle(symbol,tf);

   if(handle==INVALID_HANDLE) return("err");

//--- gets current RSI value
   if(CopyBuffer(handle,0,0,1,value)<0) return("-");

   return(DoubleToString(value[0],2));
  }
//+------------------------------------------------------------------+
//| Overrides default GetName() method from CRow                     |
//+------------------------------------------------------------------+
string CRSIRow::GetName()
  {
   return("RSI("+IntegerToString(rsiPeriod)+")");
  }
//+------------------------------------------------------------------+
//| finds the indicator handle for a given symbol and timeframe      |
//+------------------------------------------------------------------+
int CRSIRow::GetHandle(string symbol,ENUM_TIMEFRAMES tf)
  {
   for(int i=0; i<ArraySize(timeframes); i++)
      if(symbols[i]==symbol && timeframes[i]==tf)
         return(handles[i]);

   return(INVALID_HANDLE);
  }

Burada birkaç yeni yöntemimiz var. Yapıcı, RSI periyodunun sağlanmasına izin verir ve bunu bir üye değişken olarak saklar. Init yöntemi, RSI gösterge tanıtıcılarını oluşturmak için kullanılır. Bu tanıtıcılar, handles[] dizisinde depolanır. GetValue yöntemi, RSI tamponundan son değeri kopyalar ve döndürür. Özel GetHandle yöntemi, handles[] dizisinde uygun gösterge tanıtıcısını bulmak için kullanılır. GetName kendi kendini açıklar.

Gördüğümüz gibi, panel bileşenleri oluşturmak oldukça kolaydır. Aynı şekilde, hemen hemen her özel koşul için bileşenler oluşturabiliriz. Bu, gösterge değeri olmak zorunda değildir. Aşağıda SMA'ya dayalı özel bir koşul sunuyorum. Bu, mevcut fiyatın hareketli ortalamanın üzerinde olup olmadığını kontrol eder ve 'Evet' veya 'Hayır' görüntüler.

//+------------------------------------------------------------------+
//| CPriceMARow class                                                |
//+------------------------------------------------------------------+
class CPriceMARow : public CRow
  {
private:
   int               maPeriod; // period of moving average
   int               maShift;  // shift of moving average
   ENUM_MA_METHOD    maType;   // SMA, EMA, SMMA or LWMA
   string            symbols[];        // symbols array
   ENUM_TIMEFRAMES   timeframes[];     // timeframes array
   int               handles[];        // array of MA handles

   //--- finds the indicator handle for a given symbol and timeframe
   int               GetHandle(string symbol,ENUM_TIMEFRAMES tf);

public:
   //--- constructor
                     CPriceMARow(ENUM_MA_METHOD type,int period,int shift);

   //--- overrides default GetValue(..) method of CRow
   virtual string    GetValue(string symbol,ENUM_TIMEFRAMES tf);

   // overrides default GetName() method CRow
   virtual string    GetName();

   //--- overrides default Init(..) method from CRow
   virtual void      Init(string &symb[],ENUM_TIMEFRAMES &tfs[]);
  };
//+------------------------------------------------------------------+
//| CPriceMARow class constructor                                    |
//+------------------------------------------------------------------+
CPriceMARow::CPriceMARow(ENUM_MA_METHOD type,int period,int shift)
  {
   maPeriod= period;
   maShift = shift;
   maType=type;
  }
//+------------------------------------------------------------------+
//| Overrides default Init(..) method from CRow                      |
//+------------------------------------------------------------------+
void CPriceMARow::Init(string &symb[],ENUM_TIMEFRAMES &tfs[])
  {
   int size=ArraySize(symb);
   
   ArrayResize(symbols,size);
   ArrayResize(timeframes,size);
   ArrayResize(handles,size);
   
//--- copies arrays contents into own arrays
   ArrayCopy(symbols,symb);
   ArrayCopy(timeframes,tfs);
  
//--- gets MA handles for all used symbols or timeframes
   for(int i=0; i<ArraySize(symbols); i++)
      handles[i]=iMA(symbols[i],timeframes[i],maPeriod,maShift,maType,PRICE_CLOSE);
  }
//+------------------------------------------------------------------+
//| Overrides default GetValue(..) method of CRow                    |
//+------------------------------------------------------------------+
string CPriceMARow::GetValue(string symbol,ENUM_TIMEFRAMES tf)
  {
   double value[1];
   MqlTick tick;

//--- obtains MA indicator handle
   int handle=GetHandle(symbol,tf);

   if(handle==INVALID_HANDLE) return("err");

//--- gets the last MA value
   if(CopyBuffer(handle,0,0,1,value)<0) return("-");
//--- gets the last price
   if(!SymbolInfoTick(symbol,tick)) return("-");

//--- checking the condition: price > MA
   if(tick.bid>value[0])
      return("Yes");
   else
      return("No");
  }
//+------------------------------------------------------------------+
//| Overrides default GetName() method of CRow                       |
//+------------------------------------------------------------------+
string CPriceMARow::GetName()
  {
   string name;

   switch(maType)
     {
      case MODE_SMA: name = "SMA"; break;
      case MODE_EMA: name = "EMA"; break;
      case MODE_SMMA: name = "SMMA"; break;
      case MODE_LWMA: name = "LWMA"; break;
     }

   return("Price>"+name+"("+IntegerToString(maPeriod)+")");
  }
//+------------------------------------------------------------------+
//| finds the indicator handle for a given symbol and timeframe      |
//+------------------------------------------------------------------+
int CPriceMARow::GetHandle(string symbol,ENUM_TIMEFRAMES tf)
  {
   for(int i=0; i<ArraySize(timeframes); i++)
      if(symbols[i]==symbol && timeframes[i]==tf)
         return(handles[i]);

   return(INVALID_HANDLE);
  }

Kod daha uzundur, çünkü Hareketli Ortalamanın üç parametresi vardır: periyot, kayma ve tür. GetName, adı MA türüne ve periyoda göre oluşturduğu için biraz daha karmaşıktır. GetValue, CRSIRow durumunda olduğu gibi hemen hemen aynı şekilde çalışır, ancak gösterge değerini döndürmek yerine, fiyat SMA'nın üzerindeyse 'Evet' veya altındaysa 'Hayır' vermektedir.

Son örnek biraz daha karmaşıktır. Mevcut çubuğun fiyat değişimini gösteren CPriceChangeRow sınıfıdır. Üç modda çalışır:

  • Okları görüntüleme (yeşil yukarı veya kırmızı aşağı);
  • Fiyat değişikliğini değer olarak görüntüleme (yeşil veya kırmızı);
  • Fiyat değişikliğini yüzde olarak görüntüleme (yeşil veya kırmızı).

Kod aşağıdaki gibi görünür:

//+------------------------------------------------------------------+
//| CPriceChangeRow class                                            |
//+------------------------------------------------------------------+
class CPriceChangeRow : public CRow
  {
private:
   bool              percentChange;
   bool              useArrows;

public:
   //--- constructor
                     CPriceChangeRow(bool arrows,bool percent=false);

   //--- overrides default GetName() method from CRow
   virtual string    GetName();

   //--- overrides default GetFont() method from CRow
   virtual string    GetFont(string symbol,ENUM_TIMEFRAMES tf);

   //--- overrides default GetValue(..) method from CRow
   virtual string    GetValue(string symbol,ENUM_TIMEFRAMES tf);

   //--- overrides default GetColor(..) method from CRow
   virtual color     GetColor(string symbol,ENUM_TIMEFRAMES tf);

  };
//+------------------------------------------------------------------+
//| CPriceChangeRow class constructor                                |
//+------------------------------------------------------------------+
CPriceChangeRow::CPriceChangeRow(bool arrows,bool percent=false)
  {
   percentChange=percent;
   useArrows=arrows;
  }
//+------------------------------------------------------------------+
//| Overrides default GetName() method from CRow                     |
//+------------------------------------------------------------------+
 string CPriceChangeRow::GetName()
  {
   return("PriceChg");
  }
//+------------------------------------------------------------------+
//| Overrides default GetFont() method from CRow                     |
//+------------------------------------------------------------------+
string CPriceChangeRow::GetFont(string symbol,ENUM_TIMEFRAMES tf)
  {
//--- we use Wingdings font to draw arrows (up/down)
   if(useArrows)
      return("Wingdings");
   else
      return("Arial");
  }
//+------------------------------------------------------------------+
//| Overrides default GetValue(..) method from CRow                  |
//+------------------------------------------------------------------+
string CPriceChangeRow::GetValue(string symbol,ENUM_TIMEFRAMES tf)
  {
   double close[1];
   double open[1];

//--- gets open and close of current bar
   if(CopyClose(symbol,tf,0, 1, close) < 0) return(" ");
   if(CopyOpen(symbol, tf, 0, 1, open) < 0) return(" ");

//--- current bar price change
   double change=close[0]-open[0];

   if(useArrows)
     {
      if(change > 0) return(CharToString(233)); // returns up arrow code
      if(change < 0) return(CharToString(234)); // returns down arrow code
      return(" ");
        }else{
      if(percentChange)
        {
         //--- calculates percent change
         return(DoubleToString(change/open[0]*100.0,3)+"%");
           }else{
         return(DoubleToString(change,(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS)));
        }
     }
  }
//+------------------------------------------------------------------+
//| Overrides default GetColor(..) method from CRow                  |
//+------------------------------------------------------------------+
color CPriceChangeRow::GetColor(string symbol,ENUM_TIMEFRAMES tf)
  {
   double close[1];
   double open[1];

//--- gets open and close of current bar
   if(CopyClose(symbol,tf,0, 1, close) < 0) return(clrWhite);
   if(CopyOpen(symbol, tf, 0, 1, open) < 0) return(clrWhite);

   if(close[0] > open[0]) return(clrLime);
   if(close[0] < open[0]) return(clrRed);
   return(clrWhite);
  }

Yapıcının iki parametresi vardır. Birincisi okların gösterilip gösterilmeyeceğine karar verir. Bu doğruysa, ikinci parametre atılır. Yanlışsa, ikinci parametre yüzde değişimlerinin mi yoksa sadece fiyat değişimlerinin mi gösterileceğine karar verir.

Bu sınıf için dört CRow yöntemini geçersiz kılmaya karar verdim: GetName, GetValue, GetColor ve GetFont. GetName en basitidir ve sadece adı verir. Wingdings yazı tipinden okları veya diğer karakterleri görüntüleme imkanı verdiği için GetFont kullanılır. GetColor, fiyat yükseldiğinde kireç rengine ve düştüğünde kırmızıya döner. Beyaz renk yerinde kaldığında veya hata olması durumunda döndürülür. GetValue, son çubuğun açılış ve kapanış fiyatlarını alır, farkı hesaplar ve döndürür. Ok modunda yukarı ve aşağı okların Wingdings karakter kodlarını döndürür.


5. Tamamı nasıl kullanılır

Paneli kullanabilmek için yeni bir gösterge oluşturmamız gerekiyor. Buna TableSample diyelim.

İşlememiz gereken etkinlikler şunlardır:

Ayrıca OnInit() içinde dinamik olarak oluşturulacak olan CTable nesnesine bir işaretçiye ihtiyacımız vardır. Her şeyden önce, hangi modu kullanacağımıza karar vermeliyiz (çok zaman dilimli veya çok para birimli). Aşağıdaki kod örneği, çok para birimli modu gösterir, ancak çok zaman dilimli mod için gereken her şey burada yorumlardadır. Çok para birimli mod için bir dizi sembol oluşturmamız ve bunu CTable yapıcısına iletmemiz gerekiyor. Çok zaman dilimli mod için bir dizi zaman dilimi oluşturacak ve bunu ikinci CTable yapıcısına ileteceğiz.

Bundan sonra gerekli tüm bileşenleri oluşturup AddRow yöntemini kullanarak panele eklemeliyiz. İsteğe bağlı olarak panel parametreleri ayarlanabilmektedir. Sonuçta ilk defa paneli çizmemiz gerekiyor, bu yüzden OnInit() fonksiyonunun sonunda Update çağırılır. OnDeinit basittir. Yaptığı tek şey, CTable yıkıcısının çağrılmasına neden olan CTable nesnesini silmektir.

OnCalculate(...) ve OnChartEvent(...) aynıdır. Yalnızca Update yöntemini çağırırlar. OnChartEvent(...) yalnızca panel çok para birimli modda çalışıyorsa gereklidir. Bu modda SpyAgent'lar tarafından oluşturulan etkinlikleri işler. Çok zaman dilimli modda yalnızca OnCalculate(...) gereklidir, çünkü yalnızca mevcut grafiğin sembolünü izlememiz gerekir.

//+------------------------------------------------------------------+
//|                                                  TableSample.mq5 |
//|                                                 Marcin Konieczny |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Marcin Konieczny"
#property version   "1.00"
#property indicator_chart_window
#property indicator_plots 0

#include <Table.mqh>
#include <PriceRow.mqh>
#include <PriceChangeRow.mqh>
#include <RSIRow.mqh>
#include <PriceMARow.mqh>

CTable *table; // pointer to CTable object
//+------------------------------------------------------------------+
//| Indicator initialization function                                |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- timeframes used in table (in multi-timeframe mode)
   ENUM_TIMEFRAMES timeframes[4]={PERIOD_M1,PERIOD_H1,PERIOD_D1,PERIOD_W1};

//--- symbols used in table (in multi-currency mode)
   string symbols[4]={"EURUSD","GBPUSD","USDJPY","AUDCHF" };
//-- CTable object creation 
//   table = new CTable(timeframes); // multi-timeframe mode
   table=new CTable(symbols); // multi-currency mode

//--- adding rows to the table
   table.AddRow(new CPriceRow());               // shows current price
   table.AddRow(new CPriceChangeRow(false));     // shows change of price in the last bar
   table.AddRow(new CPriceChangeRow(false,true)); // shows percent change of price in the last bar
   table.AddRow(new CPriceChangeRow(true));      // shows change of price as arrows
   table.AddRow(new CRSIRow(14));                // shows RSI(14)
   table.AddRow(new CRSIRow(10));                // shows RSI(10)
   table.AddRow(new CPriceMARow(MODE_SMA,20,0));  // shows if SMA(20) > current price

//--- setting table parameters
   table.SetFont("Arial",10,clrYellow);  // font, size, color
   table.SetCellSize(60, 20);           // width, height
   table.SetDistance(10, 10);           // distance from upper right chart corner

   table.Update(); // forces table to redraw

   return(0);
  }
//+------------------------------------------------------------------+
//| Indicator deinitialization function                              |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- calls table destructor and frees memory
   delete(table);
  }
//+------------------------------------------------------------------+
//| Indicator iteration function                                     |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
  {
//--- update table: recalculate/repaint
   table.Update();
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| OnChartEvent handler                                             |
//| Handles CHARTEVENT_CUSTOM events sent by SpyAgent indicators     |
//| nedeed only in multi-currency mode!                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
   table.Update(); // update table: recalculate/repaint
  }
//+------------------------------------------------------------------+

Bu göstergeyi grafiğe ekledikten sonra güncellenmeye başlar ve nihayet panelin çalıştığını görebiliriz.


6. Kurulum

Tüm dosyaların derlenmesi gerekir. SpyAgent ve TableSample göstergelerdir ve terminal_data_folder\MQL5\Indicators dizinine kopyalanmalıdır. Kalan dosyalar içerme dosyalarıdır ve terminal_data_folder\MQL5\Include içine yerleştirilmelidir. Paneli çalıştırmak için TableSample göstergesini herhangi bir grafiğe ekleyin. SpyAgent'ları eklemeye gerek yoktur. Bunlar otomatik olarak başlatılacaklar.


Sonuç

Makale, MetaTrader 5 için çok zaman dilimli ve çok para birimli panelin nesne yönelimli bir uygulamasını sağlar. Kolayca genişletilebilen ve çok az çabayla özelleştirilmiş paneller oluşturmaya izin veren bir tasarımın nasıl elde edileceğini gösterir.

Bu makalede sunulan tüm kodlar aşağıdan indirilebilir.


MetaQuotes Ltd tarafından İngilizceden çevrilmiştir.
Orijinal makale: https://www.mql5.com/en/articles/357

Semafor Göstergelerini Kullanan Basit Alım Satım Sistemleri Semafor Göstergelerini Kullanan Basit Alım Satım Sistemleri
Herhangi bir karmaşık alım satım sistemini dikkatlice incelersek, bunun bir dizi basit alım satım sinyaline dayandığını göreceğiz. Bu nedenle, acemi geliştiricilerin hemen karmaşık algoritmalar yazmaya başlamasına gerek yoktur. Bu makale, sözleşmeleri gerçekleştirmek için semafor göstergelerini kullanan bir alım satım sistemine bir örnek sunmaktadır.
Nesne Yönelimli Programlamanın Temelleri Nesne Yönelimli Programlamanın Temelleri
Nesne yönelimli programlamayı (OOP) kullanmak için polimorfizm, kapsülleme vb.'nin ne olduğunu bilmenize gerek yok... basit şekilde bu özellikleri kullanabilirsiniz. Bu makale, uygulamalı örneklerle OOP'nin temellerini kapsar.
6 Adımda Kendi Alım Satım Robotunuzu Oluşturun! 6 Adımda Kendi Alım Satım Robotunuzu Oluşturun!
Alım satım sınıflarının nasıl oluşturulduğunu bilmiyorsanız ve "Nesne Yönelimli Programlama" kelimelerinden korkuyorsanız, bu makale tam size göredir. Aslında, kendi alım satım sinyalleri modülünüzü yazmak için ayrıntıları bilmenize gerek yoktur. Sadece bazı basit kurallara uyun. Geri kalan her şey MQL5 Sihirbazı tarafından yapılacak ve kullanıma hazır bir alım satım robotu elde edeceksiniz!
MQL5'te Kendi Grafik Panellerinizi Oluşturun MQL5'te Kendi Grafik Panellerinizi Oluşturun
MQL5 programının kullanılabilirliği hem zengin fonksiyonu hem de ayrıntılı bir grafik kullanıcı arayüzü ile belirlenir. Görsel algı bazen hızlı ve istikrarlı çalışmadan daha önemlidir. Standart Kitaplık sınıfları temelinde kendi başınıza ekran panelleri oluşturmanız için adım adım bir kılavuzu aşağıda bulabilirsiniz.