Download MetaTrader 5

Exercise of OOP. Constructive criticism welcome.

To add comments, please log in or register
All Code Base apps are available from MetaTrader 5. You can publish your own one!
Pierre Rougier
390
Pierre Rougier 2014.03.02 10:24 

Hello,

For my own needs, as an exercise, I tried to develop an indicator showing support and resistance determined by zones, where you can enter areas and values.

I publish my code hoping constructive criticism.

//+------------------------------------------------------------------+
//|                                                       idAreas.mq4|
//|                                        Copyright 2014, Pierrr8r. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, Pierrr8r."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 Pink
#property indicator_color2 SpringGreen


//---- input parameters
#include <../Areas/clArea.mqh>
#include <../Areas/clAreas.mqh>

//---- 
CAreas Areas;

//---- buffers
double Resistance_Buffer[];
double Support_Buffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   Print("init()");

   Areas.addArea(new CArea(D'1980.01.1 0:00', D'2008.10.19 0:00', 710, 700));
   Areas.addArea(new CArea(D'2008.10.19 1:00', D'2010.01.01 0:00', 1200, 1000));
   Areas.addArea(new CArea(D'2010.01.01 0:00', D'2200.01.1 0:00', 1800, 1500));

//---- indicators

   SetIndexStyle(0,DRAW_LINE);
   SetIndexBuffer(0,Resistance_Buffer);
   SetIndexLabel(0,"Resistance");

   SetIndexStyle(1,DRAW_LINE);
   SetIndexBuffer(1,Support_Buffer);
   SetIndexLabel(1,"Support");
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {
//---
   int limit=(Bars-IndicatorCounted())-1;
   for(int i=limit; i>=0; i--)
     {
      if(Areas.GetResistance(Time[i])>0)
        {
         Resistance_Buffer[i]=Areas.GetResistance(Time[i]);
        }
      else
        {
         Resistance_Buffer[i]=EMPTY_VALUE;
        }
      if(Areas.GetSupport(Time[i])>0)
        {
         Support_Buffer[i]=Areas.GetSupport(Time[i]);
        }
      else
        {
         Support_Buffer[i]=EMPTY_VALUE;
        }
     }

//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                       clArea.mqh |
//|                                         Copyright 2014, Pierre8r |
//|                                              https://www.mql4.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, Pierre8r"
#property link      "https://www.mql4.com"
#property version   "1.00"
#property strict

//---- input parameters
#include <../Areas/clArea.mqh>
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CAreas
  {
private:
   CArea            *Areas[];

public:
                     CAreas();
                    ~CAreas();

   void              addArea(CArea *area);
   double            GetResistance(datetime dtime);
   double            GetSupport(datetime dtime);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CAreas::CAreas()
  {
  }
//+------------------------------------------------------------------+
CAreas::~CAreas()
  {
   for(int i=ArraySize(Areas)-1; i>=0; i--)
     {
      if(CheckPointer(Areas[i])==POINTER_DYNAMIC)
        {
         delete Areas[i];
        }
     }
  }
//+------------------------------------------------------------------+
void CAreas::addArea(CArea *area)
  {
   ArrayResize(Areas,ArraySize(Areas)+1,10);
   Areas[ArraySize(Areas)-1]=area;
  }
//+------------------------------------------------------------------+
double CAreas::GetResistance(datetime dtime)
  {
   for(int i=ArraySize(Areas)-1; i>=0; i--)
     {
      if((Areas[i].GetStarTime()<dtime) && (Areas[i].GetEndTime()>dtime))
        {
         return(Areas[i].GetResistance());
        }
     }
   return(-1);
  }
//+------------------------------------------------------------------+
double CAreas::GetSupport(datetime dtime)
  {
   for(int i=ArraySize(Areas)-1; i>=0; i--)
     {
      if((Areas[i].GetStarTime()<dtime) && (Areas[i].GetEndTime()>dtime))
        {
         return(Areas[i].GetSupport());
        }
     }
   return(-1);
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                       clArea.mqh |
//|                                         Copyright 2014, Pierre8r |
//|                                              https://www.mql4.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, Pierre8r"
#property link      "https://www.mql4.com"
#property version   "1.00"
#property strict
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CArea
  {
private:
   datetime          m_startTime;
   datetime          m_endTime;
   double            m_resistance;
   double            m_support;

public:
                     CArea(datetime startTime,datetime endTime,double  resistance,double support);
                    ~CArea();
   //--- Getter methods
   datetime          GetStarTime(void);
   datetime          GetEndTime(void);
   double            GetResistance(void);
   double            GetSupport(void);

  };
//+------------------------------------------------------------------+
void CArea::CArea(datetime startTime,datetime endTime,double  resistance,double support)
  {
   m_startTime=startTime;
   m_endTime=endTime;
   m_resistance=resistance;
   m_support=support;
  }
//+------------------------------------------------------------------+
CArea::~CArea()
  {
  }
//+------------------------------------------------------------------+
datetime CArea::GetStarTime(void)
  {
   return m_startTime;
  }
//+------------------------------------------------------------------+
datetime CArea::GetEndTime(void)
  {
   return m_endTime;
  }
//+------------------------------------------------------------------+
double  CArea::GetResistance(void)
  {
   return m_resistance;
  }
//+------------------------------------------------------------------+
double  CArea::GetSupport(void)
  {
   return m_support;
  }
//+------------------------------------------------------------------+

Regards,

whroeder1
14545
whroeder1 2014.03.02 13:04  
tintin92: I publish my code hoping constructive criticism.
  1. In a constructor, first all members are constructed and then the code in the braces is executed. For basic data types it means little, but for member classes it can be a double hit (default construction and then parameter setting.
    void CArea::CArea(datetime startTime, datetime endTime,
                      double resistance, double support)
      {
       m_startTime=startTime;
       m_endTime=endTime;
       m_resistance=resistance;
       m_support=support;
      }
    Use Initialization lists.
    void CArea::CArea(datetime startTime, datetime endTime,
                      double resistance, double support)
      : m_startTime(startTime),
        m_endTime(endTime),
        m_resistance(resistance), // Same as assignment for basic members.
        m_support(support)      // Same as construction for class members.
      {}                 // {} all members initialized nothing else to do.

  2. #include <../Areas/clArea.mqh>
    #include <../Areas/clAreas.mqh>
    Do forward slashes actually compile? This looks like you created a non-standard folder in the data folder. Probably not a good idea.
    If you created a folder below the standard includes (in MQL4\Includes\Areas) you would use
    #include <Areas\\clArea.mqh>
    #include <Areas\\clAreas.mqh>
    Not recomended, I'd put non-application specific includes there, like WinUser32.mqh.
    If you created a folder below the experts folder (in \MQL4\Experts\Areas) you would use:
    #include "Areas\\clArea.mqh",
    #include "Areas\\clAreas.mqh"
    Application specific includes with or below the application.

Ex Ovo Omnia
3157
Ex Ovo Omnia 2014.03.02 13:57  

It depends on user preferences. From my point of view the MQL4/Includes folder is very appropriate for all includes. I use other root directories very rarely, since they are supposed to contain executable code rather than snippets.

For example if I use following combination:

#include "../TestInclude.mqh"
#include <Ovo/MT4OfflineChart.class.mqh>

it is just to ensure that the TestInclude.mqh is never processed by Doxygen, which otherwise traverses the Includes in my settings.

The forward slashes do work, I never noticed any problem.

Pierre Rougier
390
Pierre Rougier 2014.03.11 17:53  
Hello,

Thanks for the answers, now I have a new question.


No change in the code.
A simple add of a Print:

/ / + ----------------------------------------------- ------------------- + 
void Careas :: addArea (CAREA * area) 
   {
    Print ("ArraySize (Areas):" + ArraySize (Areas)); 

    ArrayResize (Areas, ArraySize (Areas) 1.10); 
    Areas [ArraySize (Areas) -1] = area; 
   } 
/ / + ----------------------------------------------- ------------------- + 

During a change of TimeFrame from W1 to D1 for example, I see that objects are added to the table not deleted.

CAREA * Areas [];

2014.03.11 17:56:03.588    idAreas GOLD,Weekly: initialized 
2014.03.11 17:56:03.588    idAreas GOLD,Weekly: ArraySize(Areas) :8 
2014.03.11 17:56:03.588    idAreas GOLD,Weekly: ArraySize(Areas) :7 
2014.03.11 17:56:03.588    idAreas GOLD,Weekly: ArraySize(Areas) :6 
2014.03.11 17:56:03.588    idAreas GOLD,Weekly: init() 
2014.03.11 17:56:03.588    idAreas GOLD,Daily: uninit reason 3 
2014.03.11 17:56:00.647    idAreas GOLD,Daily: initialized 
2014.03.11 17:56:00.647    idAreas GOLD,Daily: ArraySize(Areas) :5 
2014.03.11 17:56:00.647    idAreas GOLD,Daily: ArraySize(Areas) :4 
2014.03.11 17:56:00.647    idAreas GOLD,Daily: ArraySize(Areas) :3 
2014.03.11 17:56:00.647    idAreas GOLD,Daily: init() 
2014.03.11 17:56:00.647    idAreas GOLD,Weekly: uninit reason 3 
2014.03.11 17:55:49.849    idAreas GOLD,Weekly: initialized 
2014.03.11 17:55:49.849    idAreas GOLD,Weekly: ArraySize(Areas) :2 
2014.03.11 17:55:49.849    idAreas GOLD,Weekly: ArraySize(Areas) :1 
2014.03.11 17:55:49.849    idAreas GOLD,Weekly: ArraySize(Areas) :0 
2014.03.11 17:55:49.849    idAreas GOLD,Weekly: init() 
2014.03.11 17:55:49.843    Custom indicator Areas\idAreas GOLD,Weekly: loaded successfully 

It is not my wish, I want the objects to be deleted and then recreated.

To add comments, please log in or register