General Advice Sought For Creating An Indicator. Encapsulated By Classes or Not?

 

Hi there,

I'm new to MT4/MQ4 and have, with some help from this forum, just created a processing class that effectively produces a collection of values for plotting highs/lows on a chart subject to methodology rules. 

When I first started programming MT4, I was just using the Indicator/EA template and writing procedural type code and using function libraries. This seemed straightforward and fairly obvious. However, the requirements I had for establishing highs/lows quickly became too much for the Indicator/EA template approach and I started learning/working with MT4's CPP-like classes. This is great and provides more power and encapsulation. Objects of custom types can easily be instantiated in an EA and do much work with just a single call.

I now want to plot my High/Low trend lines and would like to know whether this kind of code is best handled in the EA/libraries or whether this is still something that should be done with classes?

I appreciate that there are probably many MT4 developers who create indicators and EAs without using an OOP based approach. Hence, I'd greatly appreciate any thoughts on best practices to approach this issue? 

Cheers,

--G

 
Geester:

Hi there,

I'm new to MT4/MQ4 and have, with some help from this forum, just created a processing class that effectively produces a collection of values for plotting highs/lows on a chart subject to methodology rules. 

When I first started programming MT4, I was just using the Indicator/EA template and writing procedural type code and using function libraries. This seemed straightforward and fairly obvious. However, the requirements I had for establishing highs/lows quickly became too much for the Indicator/EA template approach and I started learning/working with MT4's CPP-like classes. This is great and provides more power and encapsulation. Objects of custom types can easily be instantiated in an EA and do much work with just a single call.

I now want to plot my High/Low trend lines and would like to know whether this kind of code is best handled in the EA/libraries or whether this is still something that should be done with classes?

I appreciate that there are probably many MT4 developers who create indicators and EAs without using an OOP based approach. Hence, I'd greatly appreciate any thoughts on best practices to approach this issue? 

Cheers,

--G


It's way easier to use the standard (OOP) lib when plotting chart objects. 

 
nicholishen:

It's way easier to use the standard (OOP) lib when plotting chart objects. 


Hey @nicholishen, do you mean the standard ObjectCreate functions when you say "the standard (OOP) lib"?

I've used them to plot my lines but was trying to establish whether those commands are best kept outside of custom classes, in other words, inside the OnTick handler or functions called from OnTick etc.

Cheers!

 
Geester:

Hey @nicholishen, do you mean the standard ObjectCreate functions when you say "the standard (OOP) lib"?

I've used them to plot my lines but was trying to establish whether those commands are best kept outside of custom classes, in other words, inside the OnTick handler or functions called from OnTick etc.

Cheers!


Personally, I like to encapsulate the MQL drawing-object class inside of my custom class when possible. Here is a quick example

//+------------------------------------------------------------------+
//|                                                    PlotLines.mq4 |
//|                                      Copyright 2017, nicholishen |
//|                         https://www.forexfactory.com/nicholishen |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, nicholishen"
#property link      "https://www.forexfactory.com/nicholishen"
#property version   "1.00"
#property strict
#property indicator_chart_window

#include <ChartObjects\ChartObjectsLines.mqh>
#include <Arrays\List.mqh>
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+


class CHighs : public CObject
{
protected:
   double            m_price;
   datetime          m_time;
   CChartObjectTrend m_line;
public:
   CHighs(double price,datetime time):m_price(price),m_time(time)
   {
      string name = "__CHighs__"+string(time)+string(price);
      m_line.Create(0,name,0,time,price,TimeCurrent()+1000,price);
      m_line.Color(clrSalmon);
   }
   bool IsMatch(double price,datetime time)
   {
      return (price==m_price && time == m_time);
   }
};

class LineList : public CList
{
public:
   void  Add(double price,datetime time)
   {
      for(CHighs *high=GetFirstNode();high!=NULL;high=high.Next())
      {
         if(high.IsMatch(price,time))
            return;
      }
      CList::Add(new CHighs(price,time));
   }
};

LineList line_list;
int OnInit()
  {
//--- indicator buffers mapping
   
//---
   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[])
  {
//---
   double last_high = DBL_MIN;
   int count = 0;
   for(int i=0;i<rates_total && count<100;i++)
   {
      if(high[i] > last_high + 10 * _Point)
      {
         line_list.Add(high[i],time[i]);
         last_high = high[i];
         count++;
      }
   }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
 
nicholishen:

Personally, I like to encapsulate the MQL drawing-object class inside of my custom class when possible. Here is a quick example


@nicholishen - thanks again for showing me this. It's really helpful to see how you are going about this! :)

Also, I picked up on the way you bumped through the list object in your LineList add method. Not too far away from an iterable foreach in higher level languages. I'll definitely use that because I'm using the ObjVector<T> class for most things with collections of data. Really great insight and I appreciate your time in answering my questions!

Cheers,

--G