Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano Türkçe
Using the Object Pointers in MQL5

Using the Object Pointers in MQL5

MetaTrader 5Examples | 16 April 2010, 09:51
17 890 2
MetaQuotes
MetaQuotes

Introduction

In MQL5, you may create your own class for the further use of class type variables in your code. As we already know from the article The Order of Object Creation and Destruction in MQL5, the structures and classes can be created in two ways - automatically and dynamically.

To create an object automatically simply declare a class type variable - the system will create and initialize it automatically. To create an object dynamically it's necessary to apply the operator new  to the object pointer explicitly.

However, what is the difference between the objects created automatically and dynamically, and when we need the necessarily use of the object pointer, and when it's sufficient to create the objects automatically? This topic is the subject of this article. The first, let's discuss some possible pitfalls when working with objects and consider the ways to fix them.

A Critical Error in Access to Invalid Pointer

The first, that you should remember when using the object pointers - it's mandatory initialization of the object before its use. When you access to invalid pointer, the work of MQL program terminates with a critical error, so the program is removed. As an example, let's consider a simple Expert Advisor, with class CHello, declared there. The pointer to the class instance is declared at global level.

//+------------------------------------------------------------------+
//|                                             GetCriticalError.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2009, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| A simple class                                                   |
//+------------------------------------------------------------------+
class CHello
  {
private:
   string            m_message;
public:
                     CHello(){m_message="Starting...";}
   string            GetMessage(){return(m_message);}
  };
//---
CHello *pstatus;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- calling a method to show status
   Print(pstatus.GetMessage());
//--- printing a message if Expert Advisor has been initialized successfully
   Print(__FUNCTION__," The OnInit() function is completed");
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

  }
//+------------------------------------------------------------------+

The pstatus variable is the object pointer, but we intentionally "forgot" to create the object itself using the new operator. If you will try to launch this Expert Advisor on the EURUSD chart, you will see the natural result - the Expert Advisor has been immediately unloaded at the stage of execution of the OnInit() function. The messages that appears in the Experts Journal are the following:

14:46:17 Expert GetCriticalError (EURUSD, H1) loaded successfully
14:46:18 Initializing of GetCriticalError (EURUSD, H1) failed
14:46:18 Expert GetCriticalError (EURUSD, H1) removed

This example is a very simple, the error catching is easy. However, if your MQL5-program contains hundreds or even thousands of lines of code, catching of these errors may be greatly complicated. It's important, especially for the cases of emergency situation conditions in the program behavior depends on the unpredictable factors - for example, on the particular market structure.

Checking of the Pointer Before its Use

Was it possible to avoid the critical program termination? Yes, of course! It's sufficient to insert the check of the object pointer before its use. Let's modify this example by adding the PrintStatus function:

//+------------------------------------------------------------------+
//| Prints a message using a method of CHello type object            |
//+------------------------------------------------------------------+
void PrintStatus(CHello *pobject)
  {
   if(CheckPointer(pobject)==POINTER_INVALID)
      Print(__FUNCTION__," the variable 'object' isn't initialized!");
   else Print(pobject.GetMessage());
  }

Now this function calls the GetMessage() method, the pointer of the object of CHello type is passed to the function. The first, it checks the pointer using the function CheckPointer(). Let's add an external parameter and save the code of an Expert Advisor to the file GetCriticalError_OnDemand.mq5.

//+------------------------------------------------------------------+
//|                                    GetCriticalError_OnDemand.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2009, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"

input bool GetStop=false;// To get a critical error
//+------------------------------------------------------------------+
//| A simple class                                                   |
//+------------------------------------------------------------------+
class CHello
  {
private:
   string            m_message;
public:
                     CHello(){m_message="Starting...";}
   string            GetMessage(){return(m_message);}
  };
//---
CHello *pstatus;
//+------------------------------------------------------------------+
//| Prints a message using a method of CHello type object            |
//+------------------------------------------------------------------+
void PrintStatus(CHello *pobject)
  {
   if(CheckPointer(pobject)==POINTER_INVALID)
      Print(__FUNCTION__," the variable 'object' isn't initialized!");
   else Print(pobject.GetMessage());
  }
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- calling a method to show status
   if(GetStop)
      pstatus.GetMessage();
   else
      PrintStatus(pstatus);
//--- printing a message if Expert Advisor has been initialized successfully
   Print(__FUNCTION__," The OnInit() function is completed");
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

  }
//+------------------------------------------------------------------+

Now we can launch the Expert Advisor in two ways:

  1. With a critical error (GetStop = true)
  2. Without an error, but with the message about invalid pointer (GetStop = false)

By default, the execution of Expert Advisor is successful and the following message appears in the "Experts" Journal:

GetCriticalError_OnDemand (EURUSD, H1) 15:01:57 PrintStatus the variable 'object' isn't initialized!
GetCriticalError_OnDemand (EURUSD, H1) 15:01:57 OnInit function OnInit () is completed

Thus, the checking of the pointer before its use allows to avoid the critical errors.

Always check for the pointer correctness before its use in the function

Passing the Uninitialized Object by Reference

What happens if you will pass the uninitialized object as an input parameter of the function? (the object itself by reference, not the object pointer). The complex objects, such as classes and structures are passed by reference with an ampersand. Let's rewrite some code of the GetCriticalError_OnDemand.mq5. Let's rename the PrintStatus() function and rewrite its code in a different way.

//+------------------------------------------------------------------+
//| Prints a message using a method of CHello type object            |
//+------------------------------------------------------------------+
void UnsafePrintStatus(CHello &object)
  {
   DebugBreak();
   if(CheckPointer(GetPointer(object))==POINTER_INVALID)
      Print(__FUNCTION__," the variable 'object' isn't initialized!");
   else Print(object.GetMessage());
  }

Now the difference is that the variable itself of this type is passed by reference as an input parameter instead of the object pointer of CClassHello type. Let's save the new version of an Expert Advisor as GetCriticalError_Unsafe.mq5.

//+------------------------------------------------------------------+
//|                                      GetCriticalError_Unsafe.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2009, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"

input bool GetStop=false;// To get a critical error
//+------------------------------------------------------------------+
//| A simple class                                                   |
//+------------------------------------------------------------------+
class CHello
  {
private:
   string            m_message;
public:
                     CHello(){m_message="Starting...";}
   string            GetMessage(){return(m_message);}
  };
//---
CHello *pstatus;
//+------------------------------------------------------------------+
//| Prints a message using a method of CHello type object            |
//+------------------------------------------------------------------+
void UnsafePrintStatus(CHello &object)
  {
   DebugBreak();
   if(CheckPointer(GetPointer(object))==POINTER_INVALID)
      Print(__FUNCTION__," the variable 'object' isn't initialized!");
   else Print(object.GetMessage());
  }
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- calling a method to show status
   if(GetStop)
      pstatus.GetMessage();
   else
      UnsafePrintStatus(pstatus);
//--- printing a message if Expert Advisor has been initialized successfully
   Print(__FUNCTION__," The OnInit() function is completed");
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

  }
//+------------------------------------------------------------------+

One can see the difference between the GetCriticalError_OnDemand.mq5 and GetCriticalError_Unsafe.mq5 Expert Advisors in the way of parameter passing to the function. For the first case, the object pointer is passed to the function, and for the second case the object itself is passed by reference. In both cases, before the use of the object and its pointer, the function checks it for the pointer correctness.

Does it means that Expert Advisors will work the same way? No, it doesn't! Let's launch the Expert Advisor with parameter GetStop=false, and again we will get a critical error. The fact is that if an object is passed by reference, the critical error occurs at the stage of a function call, because the uninitialized object is passed as a parameter. You can verify it, if you launch the script in debug mode directly from MetaEditor5, using the  F5 button.

To avoid the use of the manual breakpoints, let's modify the function by adding the DebugBreak () breakpoint inside of the function.

//+------------------------------------------------------------------+
//| Prints a message using a method of CHello type object            |
//+------------------------------------------------------------------+
void UnsafePrintStatus(CHello &object)
  {
   DebugBreak();
   if(CheckPointer(GetPointer(object))==POINTER_INVALID)
      Print(__FUNCTION__," the variable 'object' isn't initialized!");
   else Print(object.GetMessage());
  }

In debug mode, the Expert Advisor will unloaded before a call of the DebugBreak() function. How to write the secure code for the case if an uninitialized object is passed by the reference? The answer is simple - to use the function overloading.

If a pointer of an uninitialized object is passed by reference as a parameter of the function, it will lead to a critical error and stop the mql5-program.

Using the Overloaded Functions for Safe Code

It would be very inconvenient, if the developer, that uses the external library, had forced to carry out checking of the input objects for the correctness. It's much better to perform all the necessary checks inside the library, it can be implemented using the function overloading.

Let's implement the method UnsafePrintStatus() with the function overloading and write two versions of this function - the first that uses the passed object pointer instead of the object itself, the second that uses the passing of object by reference. Both functions will have the same name "PrintStatus", but this implementation will be no longer potentially dangerous.

//+------------------------------------------------------------------+
//| The safe printing of a message using the CHello object pointer     |
//+------------------------------------------------------------------+
void SafePrintStatus(CHello *pobject)
  {
   if(CheckPointer(pobject)==POINTER_INVALID)
      Print(__FUNCTION__," the variable 'object' isn't initialized!");
   else Print(pobject.GetMessage());
  }
//+------------------------------------------------------------------+
//| Printing a message using the CHello object, passed by reference  |
//+------------------------------------------------------------------+
void SafePrintStatus(CHello &pobject)
  {
   DebugBreak();
   SafePrintStatus(GetPointer(pobject));
  }

Now for the case if the function is called by passing of the object pointer, the checking for a correctness is performed and the critical error doesn't occur. If you call the overloaded function with passing of an object by reference, the first we get the object pointer using the GetPointer function and then we call the safe code, that uses the passing of an object by the pointer.

We can rewrite a secure version of the function is even shorter, instead of

void SafePrintStatus (CHello & pobject)
  (
   DebugBreak ();
   CHello * p = GetPointer (pobject);
   SafePrintStatus (p);
  )

let's write the compact version:

void SafePrintStatus (CHello & object)
  (
   DebugBreak ();
   SafePrintStatus (GetPointer (object));
  )

The both versions are equal. Let's save the second version with the name GetCriticalError_Safe.mq5.

//+------------------------------------------------------------------+
//|                                        GetCriticalError_Safe.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2009, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"

input bool GetStop=false;// To get a critical error
//+------------------------------------------------------------------+
//| A simple class                                                   |
//+------------------------------------------------------------------+
class CHello
  {
private:
   string            m_message;
public:
                     CHello(){m_message="Starting...";}
   string            GetMessage(){return(m_message);}
  };
//---
CHello *pstatus;
//+------------------------------------------------------------------+
//| The safe printing of a message using the CHello object pointer     |
//+------------------------------------------------------------------+
void SafePrintStatus(CHello *pobject)
  {
   if(CheckPointer(pobject)==POINTER_INVALID)
      Print(__FUNCTION__," the variable 'object' isn't initialized!");
   else Print(pobject.GetMessage());
  }
//+------------------------------------------------------------------+
//| Printing a message using the CHello object, passed by reference  |
//+------------------------------------------------------------------+
void SafePrintStatus(CHello &pobject)
  {
   DebugBreak();
   SafePrintStatus(GetPointer(pobject));
  }
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- calling a method to show status
   if(GetStop)
      pstatus.GetMessage();
   else
      SafePrintStatus(pstatus);
//--- printing a message if Expert Advisor has been initialized successfully
   Print(__FUNCTION__," The OnInit() function is completed");
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

  }
//+------------------------------------------------------------------+

If you use two functions with the different implementations (by passing the reference and by passing the object pointer), it allows to ensure the safe work of the overloaded function.

Finally, we have learned how to use the objects, passed to the function as parameters, now it's time to learn:

When do You Need Pointers?

The object pointers allow to perform a flexible management of the process of objects creation and destroying, and allow you to create more complex abstract objects. It makes the program more flexible.

Linked List

But in some cases a different way of data organization is required, the linked list is the one of them. The class of a linked list CList is available in the Standard Library, here we will present our own examples. A linked list means, that each list item is connected with the next and previous items, if they exist. To organize such links, it's convenient to use the object pointers of list items (ListItem).

Let's create a class, that will represent an item of a list, like this one:

class CListItem
  {
private:
   int               m_ID;
   CListItem        *m_next;
   CListItem        *m_prev;
public:
                    ~CListItem();
   void              setID(int id){m_ID=id;}
   int               getID(){return(m_ID);}
   void              next(CListItem *item){m_next=item;}
   void              prev(CListItem *item){m_prev=item;}
   CListItem*        next(){return(m_next);}
   CListItem*        prev(){return(m_prev);}
  };

The list itself will be organized in a separate class:

//+------------------------------------------------------------------+
//| Linked list                                                      |
//+------------------------------------------------------------------+
class CList
  {
private:
   int               m_counter;
   CListItem        *m_first;
public:
                     CList(){m_counter=0;}
                    ~CList();
   void              addItem(CListItem *item);
   int               size(){return(m_counter);}
  };

The CList class contains a pointer m_first  of the first list item, an access to the other list items is always available via the next () and prev() functions of the CListItem() class. The CList class has two interesting functions. The first is the function for adding of a new item to the list.

//+------------------------------------------------------------------+
//| Adding of an item to the list                                    |
//+------------------------------------------------------------------+
CList::addItem(CListItem *item)
  {
//--- checking of a pointer, it should be correct
   if(CheckPointer(item)==POINTER_INVALID) return;
//--- increasing the number of list items
   m_counter++;
//--- if there isn't any items in the list
   if(CheckPointer(m_first)!=POINTER_DYNAMIC)
     {
      m_first=item;
     }
   else
     {
      //--- setting for first a pointer to the previous item
      m_first.prev(item);
      //--- saving a pointer of the current first item
      CListItem *p=m_first;
      //--- placing the input item on the place of the first element
      m_first=item;
      //--- for the first item in the list, setting a pointer to the next item 
      m_first.next(p);
     }
  }

An each item, added to the list, becomes the first item, the pointer of the previous first item is stored in the m_next  field. Thus, an item, added to the list first, will be at the end of the list. The last added item, will be the first, and its pointer is stored in a m_first  variable. The second interesting function is the ~CList() destructor. It calls when the object is destroyed, it should ensure the correct destruction of the list objects. It can be done very simple:

//+------------------------------------------------------------------+
//| List destructor                                                  |
//+------------------------------------------------------------------+
CList::~CList(void)
  {
   int ID=m_first.getID();
   if(CheckPointer(m_first)==POINTER_DYNAMIC) delete(m_first);
   Print(__FUNCTION__," The first item with ID =",ID," is destroyed");
  }

One can see, if the m_first  contain the correct pointer of the list item, only first list item is removed. All other list items are removed avalanche, because the CListItem()  class destructor in turn, produces the correct object deinitialization.

//+------------------------------------------------------------------+
//| Item destructor                                                  |
//+------------------------------------------------------------------+
CListItem::~CListItem(void)
  {
   if(CheckPointer(m_next)==POINTER_DYNAMIC)
     {
      delete(m_next);
      Print(__FUNCTION__," Removing an item with ID =",m_ID);
     }
   else
      Print(__FUNCTION__," The next item isn't defined for the item with ID=",m_ID);

  }

The correctness of a pointer is verified inside the destructor, if it specified, the object with pointer m_next  is destroyed using the delete() operator. Before the destruction, the first list item calls the destructor, it will delete the second item, then it will cause the deletion of the third item and so on until the end of the chain.

The work of the list is shown in the script SampleList.mq5. The declaration of a list (a variable of CListType) is in the OnStart () function. This list will be created and initialized automatically. The filling of the list is performed inside of a list, and the first, each list item is created dynamically using the new operator and then it added to the list. 

void OnStart()
  {
//---
   CList list;
   for(int i=0;i<7;i++)
     {
      CListItem *item=new CListItem;
      item.setID(i);
      list.addItem(item);
     }
     Print("There are ",list.size()," items in the list");
  }

Launch the script and you will see the following messages in the "Experts" journal.

2010.03.18 11:22:05 SampleList (EURUSD, H1) CList:: ~ CList The first item with ID=6 is destroyed
2010.03.18 11:22:05 SampleList (EURUSD, H1) CListItem:: ~ CListItem Removing an item with ID = 6
2010.03.18 11:22:05 SampleList (EURUSD, H1) CListItem:: ~ CListItem Removing an item with ID = 5
2010.03.18 11:22:05 SampleList (EURUSD, H1) CListItem:: ~ CListItem Removing an item with ID = 4
2010.03.18 11:22:05 SampleList (EURUSD, H1) CListItem:: ~ CListItem Removing an item with ID = 3
2010.03.18 11:22:05 SampleList (EURUSD, H1) CListItem:: ~ CListItem Removing an item with ID = 2
2010.03.18 11:22:05 SampleList (EURUSD, H1) CListItem:: ~ CListItem Removing an item with ID = 1
2010.03.18 11:22:05 SampleList (EURUSD, H1) CListItem:: ~ CListItem The next item isn't defined for the item with ID=0
2010.03.18 11:22:05 SampleList (EURUSD, H1) There are 7 items in the list

If you have studied the code carefully, it isn't a surprise that item with ID=0 doesn't has the next following item. However, we have considered only one reason, when use of the pointers makes writing of programs convenient and readable. There is a second reason, and it's called as

Polymorphism

It's often necessary to implement the same functionality for different objects, belonging to the same type. For example, there are simple objects like Line, Triangle, Rectangle and Circle. Despite the fact that they look differently, they have a common feature - they can be drawn. Let's create a base class CShape, and use it for creation of its descendants for each type of geometric shapes.


For the educational purposes, the base class and its descendants have a minimal functionality.

//+------------------------------------------------------------------+
//| The base class for a Shape object                                |
//+------------------------------------------------------------------+
class CShape
  {
private:
   int               m_type;
public:
                     CShape(){m_type=0;}
   void              Draw();
   string            getTypeName(){return("Shape");}
  };
//+------------------------------------------------------------------+
//| The class for a Line object                                      |
//+------------------------------------------------------------------+
class CLine:public CShape
  {
private:
   int               m_type;
public:
                     CLine(){m_type=1;}
   void              Draw();
   string            getTypeName(){return("Line");}
  };
//+------------------------------------------------------------------+
//| The class for a Triangle object                                  |
//+------------------------------------------------------------------+
class CTriangle:public CShape
  {
private:
   int               m_type;
public:
                     CTriangle(){m_type=2;}
   void              Draw();
   string            getTypeName(){return("Triangle");}
  };
//+------------------------------------------------------------------+
//| The class for a Rectangle object                                 |
//+------------------------------------------------------------------+
class CRectangle:public CShape
  {
private:
   int               m_type;
public:
                     CRectangle(){m_type=3;}
   void              Draw();
   string            getTypeName(){return("Rectangle");}
  };
//+------------------------------------------------------------------+
//| The class for a Cirlce object                                    |
//+------------------------------------------------------------------+
class CCircle:public CShape
  {
private:
   int               m_type;
public:
                     CCircle(){m_type=4;}
   void              Draw();
   string            getTypeName(){return("Circle");}
  };

The parent CShape class contains two functions, which are overridden in his descendants - a Draw() and getTypeName(). The Draw() function is intended to draw a shape, and the getTypeName() function returns a string description of the shape.

Let's create a *shapes[] array, which contains pointers of the base type CShape, and specifies the values of a pointer for the different classes.

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- an array of pointers of objects of CShape type
   CShape *shapes[];
//--- resizing of an array 
   ArrayResize(shapes,5);
//--- filling of a pointers array
   shapes[0]=new CShape;
   shapes[1]=new CLine;
   shapes[2]=new CTriangle;
   shapes[3]=new CRectangle;
   shapes[4]=new CCircle;
//--- printing the type of each array element
   for(int i=0;i<5;i++)
     {
      Print(i,shapes[i].getTypeName());
     }
//--- deleting all objects in the array
   for(int i=0;i<5;i++) delete(shapes[i]);
  }

Inside of the for()  cycle we call the getTypeName () method for each element of the *shapes[]  array. The first time you may be surprised the fact, that the getTypeName() function of a base class calls for the each object in the list, despite the fact that the each derived class has its own implementation of the getTypeName() function.

2010.03.18 14:06:18 DemoPolymorphism (EURUSD, H1) 4 Shape
2010.03.18 14:06:18 DemoPolymorphism (EURUSD, H1) 3 Shape
2010.03.18 14:06:18 DemoPolymorphism (EURUSD, H1) 2 Shape
2010.03.18 14:06:18 DemoPolymorphism (EURUSD, H1) 1 Shape
2010.03.18 14:06:18 DemoPolymorphism (EURUSD, H1) 0 Shape

The explanation of this fact is the following: the *shapes []  array is declared as an array of pointers of CShape type, and therefore the each array object calls the getTypeName() method of a base class, even if a descendant has a different implementation. To call the getTypeName() function corresponding to the actual object type (descendant) at the moment of the program execution, it's necessary to declare this function in a base class as a virtual function.

Let's add the virtual keyword to the getTypeName() function in the declaration of a parent CShape class.

class CShape
  (
private:
   int m_type;
public:
                     CShape () (m_type = 0;)
   void Draw ();
   virtual string getTypeName () (return ("Shape");)
  )

and launch the script again. Now the results are consistent with those expected:

2010.03.18 15:01:11 DemoPolymorphism (EURUSD, H1) 4 Circle
2010.03.18 15:01:11 DemoPolymorphism (EURUSD, H1) 3 Rectangle
2010.03.18 15:01:11 DemoPolymorphism (EURUSD, H1) 2 Triangle
2010.03.18 15:01:11 DemoPolymorphism (EURUSD, H1) 1 Line
2010.03.18 15:01:11 DemoPolymorphism (EURUSD, H1) 0 Shape

So, the declaration of a virtual function in a base class allowed to call the same function of a descendant during the execution of program. Now we can implement the fully-featured  Draw() function for the each of derived classes.

An example of its work can be found in the attached  DrawManyObjects.mq5 script, which shows a random shapes on the chart.

Conclusion

So, it's time to sum up. In MQL5, the objects creation and destroying is performed automatically, so you should use the pointers only if they are really needed, and if you understand how to work with them.

However, if you cannot do it without the use of pointers, be sure to check the pointer correctness before its use, using the CheckPointer() - it has been added special for these cases.

One last thing: in MQL5 the pointers aren't actual memory pointers, as they used in C++, so you should not pass them to DLL as input parameters.

Translated from Russian by MetaQuotes Ltd.
Original article: https://www.mql5.com/ru/articles/36

Last comments | Go to discussion (2)
alwaysmlie4u
alwaysmlie4u | 21 Sep 2018 at 03:06
The tutorial made it clear for me to understand polymorphism. Thanks
Bro840
Bro840 | 26 Dec 2018 at 20:38
MetaQuotes Software Corp.:

New article Using the Object Pointers in MQL5 is published:

Author: MetaQuotes

I cant see the tutorial....

Creating Tick Indicators in MQL5 Creating Tick Indicators in MQL5
In this article, we will consider the creation of two indicators: the tick indicator, which plots the tick chart of the price and tick candle indicator, which plot candles with the specified number of ticks. Each of the indicators writes the incoming prices into a file, and uses the saved data after the restart of the indicator (these data also can be used by the other programs)
MQL5: Analysis and Processing of Commodity Futures Trading Commission (CFTC) Reports in MetaTrader 5 MQL5: Analysis and Processing of Commodity Futures Trading Commission (CFTC) Reports in MetaTrader 5
In this article, we will develop a tool for CFTC report analysis. We will solve the following problem: to develop an indicator, that allows using the CFTC report data directly from the data files provided by Commission without an intermediate processing and conversion. Further, it can be used for the different purposes: to plot the data as an indicator, to proceed with the data in the other indicators, in the scripts for the automated analysis, in the Expert Advisors for the use in the trading strategies.
Creating a "Snake" Game in MQL5 Creating a "Snake" Game in MQL5
This article describes an example of "Snake" game programming. In MQL5, the game programming became possible primarily due to event handling features. The object-oriented programming greatly simplifies this process. In this article, you will learn the event processing features, the examples of use of the Standard MQL5 Library classes and details of periodic function calls.
Introduction to MQL5: How to write simple Expert Advisor and Custom Indicator Introduction to MQL5: How to write simple Expert Advisor and Custom Indicator
MetaQuotes Programming Language 5 (MQL5), included in MetaTrader 5 Client Terminal, has many new possibilities and higher performance, compared to MQL4. This article will help you to get acquainted with this new programming language. The simple examples of how to write an Expert Advisor and Custom Indicator are presented in this article. We will also consider some details of MQL5 language, that are necessary to understand these examples.