Exercise of OOP. Constructive criticism welcome.

 

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,

 
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.

 

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.

 
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.

Reason: