Русский Español Português
preview
From Basic to Intermediate: Classes (II)

From Basic to Intermediate: Classes (II)

MetaTrader 5Examples |
203 0
CODE X
CODE X

Introduction

In the previous article From Basic to Intermediate: Classes (I), we began exploring object-oriented programming. However, in that article, we only discussed class constructors. Sometimes we need to implement another special member function specific to classes: the destructor.

To fully understand how destructors work, you can draw a parallel between object-oriented programming—in which classes are created and used—and event-driven programming in MetaTrader 5. "Wow! What kind of strange comparison are you about to make?" Relax, dear reader. You will understand everything soon. I assure you: this will make it much easier for you to understand why destructors exist and how they should be implemented when necessary.

It is time to set aside anything that might distract you and focus on what we will be discussing in this article. All right, let's move on to the next topic.


Classes (II)

One of the most difficult concepts to understand in object-oriented programming is the destructor. In many cases, the practical purpose of destructors is not always obvious. Furthermore, since you, as a programmer, cannot explicitly call a destructor, it becomes even harder to understand why it exists at all. This certainly does not make it any easier for a beginner to grasp the concept of a destructor.

Old-school programmers like me, who have literally watched the evolution of programming over the years, also had a hard time understanding some of the new concepts and mechanisms that were emerging. Now imagine a programmer who is faced with all these already implemented concepts and has to understand them. What confusion! First and foremost, because many of these concepts are usually explained very poorly, turning what is initially simple into a hydra-like monster: the more heads you cut off in an attempt to finish it off, the more complicated the situation becomes. A destructor is precisely one such concept. In this article, you will see that although it may seem complicated, it is actually very simple. Once you correctly understand how it works, it will be much easier for you to determine when and how to implement it in your classes.

All right, to start with, let's put object-oriented programming aside for a moment and move on to something simpler and more practical: event-driven programming. This is precisely the paradigm we use when developing indicators and Expert Advisors for MetaTrader 5. Okay, but what is the connection between event-driven programming and object-oriented programming? To be honest, dear reader, they do not have much in common. However, since we use MQL5—a language designed to allow programmers to control the operation of MetaTrader 5—it is very easy to establish a connection between these two paradigms. This comparison will allow us to demonstrate how a destructor works in practice.

To start, we will create a very simple indicator, the code for which is shown below:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. #property description "Demo"
04. //+------------------------------------------------------------------+
05. int OnInit()
06. {
07.    return INIT_SUCCEEDED;
08. };
09. //+------------------------------------------------------------------+
10. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
11. {
12.    return rates_total;
13. };
14. //+------------------------------------------------------------------+
15. void OnDeinit(const int reason)
16. {
17. };
18. //+------------------------------------------------------------------+

Code 01

As we have already seen in the first articles about indicators in this series, both indicators and Expert Advisors operate based on events that, in most cases, are generated and triggered by MetaTrader 5. There are also situations where the code itself can initiate events, but that is not important right now. It is important to understand that these events originate from MetaTrader 5.

For more information, see the previous articles. In particular, From Basic to Intermediate: Events (I) will help you grasp some of the concepts necessary for understanding this article.

We can think of Code 01 as if it were a class. “How come? I do not understand what you mean.” Don't worry, you will understand everything in a moment. Remember, in the previous article we talked about two special class member functions? The constructor is responsible for initializing the class, and the destructor is responsible for destroying what the class has created. So, let's take another look at Code 01. Since this is an indicator, when MetaTrader 5 places it on the chart, it will first call and execute the code of the OnInit function. When we remove this indicator from the chart, MetaTrader 5 will call and execute the OnDeinit function, if it has been implemented. This way, we will be able to remove any chart element we want deleted when the indicator is removed.

Based on this simple idea and the similarity between object-oriented programming and the way indicator code works, we can implement something in Code 01 and begin to understand how a destructor actually works.

We will add an object to the chart, and when the indicator is removed, that object will be deleted as well. This is a very simple task that has already been explained in other articles in this series.

We will use the article From Basic to Intermediate: Objects (I) as the basis for what we will be doing. In it, I showed how to add and remove objects from the chart. By modifying Code 01 in accordance with what was explained in that article, we will get the code shown below:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. #property description "Demo"
04. //+------------------------------------------------------------------+
05. #define def_NameChannel    "Demo"
06. //+------------------------------------------------------------------+
07. int OnInit()
08. {
09.    ObjectCreate(0, def_NameChannel, OBJ_REGRESSION, 0, 0, 0);
10. 
11.    return INIT_SUCCEEDED;
12. };
13. //+------------------------------------------------------------------+
14. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
15. {
16.    return rates_total;
17. };
18. //+------------------------------------------------------------------+
19. void OnDeinit(const int reason)
20. {
21.    ObjectDelete(0, def_NameChannel);
22.    ChartRedraw();
23. };
24. //+------------------------------------------------------------------+

Code 02

The purpose of Code 02 is to create an OBJ_REGRESSION object and display it on the chart. As soon as the indicator is removed, the object will also be removed. However, when you run the code, you will notice that no object appears on the chart, even though one is actually created on line 09. How can we solve this? It is very simple, dear reader; all you need to do is change the code as shown below:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. #property description "Demo"
04. //+------------------------------------------------------------------+
05. #define def_NameChannel    "Demo"
06. //+------------------------------------------------------------------+
07. int OnInit()
08. {
09.     datetime    dt0 = TimeCurrent(),
10.                 dt1[20];
11. 
12.     CopyTime(NULL, NULL, dt0, dt1.Size(), dt1);
13.     ObjectCreate(0, def_NameChannel, OBJ_REGRESSION, 0, dt1[0], 0, dt0, 0);
14. 
15.     return INIT_SUCCEEDED;
16. };
17. //+------------------------------------------------------------------+
18. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
19. {
20.     return rates_total;
21. };
22. //+------------------------------------------------------------------+
23. void OnDeinit(const int reason)
24. {
25.     ObjectDelete(0, def_NameChannel);
26.     ChartRedraw();
27. };
28. //+------------------------------------------------------------------+

Code 03

The only required change is to obtain the date/time values we will use to create and position the regression object. This is done on lines 9 and 12. The result is shown below:

Figure 01

Now, take a look at the following detail. When we add this indicator to the chart, the object defined on line 13 is created and positioned. When the indicator is removed, the same object is removed from the chart thanks to line 25. That is, the OnInit event handler serves as the constructor, while the OnDeinit event handler serves as the destructor. "Well, but what does this have to do with object-oriented programming? I still do not understand what you are getting at."

So, dear reader, now you will understand this, because we have reached the most interesting part: converting code 03 into a program that uses object-oriented programming. Please pay close attention so you can understand how we will do this. Since code 03 is an indicator, and using object-oriented programming in it would require two statements that we have not covered yet, we will change our approach and convert code 03 into a script. The result is shown below:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #define def_NameChannel    "Demo"
05. //+------------------------------------------------------------------+
06. void OnStart(void)
07. {
08.     datetime    dt0 = TimeCurrent(),
09.                 dt1[20];
10. 
11.     CopyTime(NULL, NULL, dt0, dt1.Size(), dt1);
12.     ObjectCreate(0, def_NameChannel, OBJ_REGRESSION, 0, dt1[0], 0, dt0, 0);
13.     ChartRedraw();
14. 
15.     Sleep(2000);
16.    
17.     ObjectDelete(0, def_NameChannel);
18.     ChartRedraw();
19. }
20. //+------------------------------------------------------------------+

Code 04

Please note that we are now using a script instead of an indicator. However, that does not change the essence of what we are doing. We are simply using an approach that will make it easier to explain and clearly demonstrate how the constructor and destructor of the class we will create later work. To prevent the object from disappearing immediately after it is created, we use line 15 to insert a short pause between its placement and removal. When executed, the code will behave as shown in the following animation:

Animation 01

Great, the script is working correctly. And now comes the most interesting part. All we need to do is change code 04 as follows:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #define def_NameChannel    "Demo"
05. //+------------------------------------------------------------------+
06. class C_Regression
07. {
08.     private :
09. //+----------------+
10.     public  :
11. //+----------------+
12.         C_Regression()
13.         {
14.             datetime    dt0 = TimeCurrent(),
15.                         dt1[20];
16. 
17.             CopyTime(NULL, NULL, dt0, dt1.Size(), dt1);
18.             ObjectCreate(0, def_NameChannel, OBJ_REGRESSION, 0, dt1[0], 0, dt0, 0);
19.             ChartRedraw();
20.         }
21. //+----------------+
22. };
23. //+------------------------------------------------------------------+
24. void OnStart(void)
25. {
26.     C_Regression channel;
27.     
28.     Sleep(2000);
29.    
30.     ObjectDelete(0, def_NameChannel);
31.     ChartRedraw();
32. }
33. //+------------------------------------------------------------------+

Code 05

Now, dear reader, please pay very close attention. Code 05 will produce the same result as we saw in Animation 01. Nevertheless, this is where we begin to see how to implement this behavior using object-oriented programming. Since the part related to the constructor was already explained in the previous article, we can focus on the destructor. And this is exactly where many beginners get completely confused because they do not understand how it works. This is primarily because many authors do not explain things the way I am trying to explain them here.

To add a destructor to code 05 and bring it fully into line with the principles of object-oriented programming, simply modify it as shown below:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #define def_NameChannel    "Demo"
05. //+------------------------------------------------------------------+
06. class C_Regression
07. {
08.     private :
09. //+----------------+
10.     public  :
11. //+----------------+
12.         C_Regression()
13.         {
14.             datetime    dt0 = TimeCurrent(),
15.                         dt1[20];
16. 
17.             CopyTime(NULL, NULL, dt0, dt1.Size(), dt1);
18.             ObjectCreate(0, def_NameChannel, OBJ_REGRESSION, 0, dt1[0], 0, dt0, 0);
19.             ChartRedraw();
20.         }
21. //+----------------+
22.         ~C_Regression()
23.         {
24.             ObjectDelete(0, def_NameChannel);
25.             ChartRedraw();
26.         }
27. //+----------------+
28. };
29. //+------------------------------------------------------------------+
30. void OnStart(void)
31. {
32.     C_Regression channel;
33.     
34.     Sleep(2000);
35. }
36. //+------------------------------------------------------------------+

Code 06

Now, dear reader, run code 06 in the MetaTrader 5 terminal and be amazed by the result. This way, you can make sure the result matches what is shown in Animation 01. Why? Keep in mind that MetaTrader 5 will only execute the code contained in the OnStart procedure. However, if we take a closer look at this procedure, we will see that it contains only two lines. Nevertheless, the code retains its behavior: it creates an object, places it on the chart, lets some time pass, and then removes it. So, the question arises once again: How did this happen? The answer is that the destructor is called.

"How is that possible? I cannot see any calls whatsoever, except for two lines in the OnStart procedure. The only difference I noticed in Code 06 is that you created another special member function inside the class with the same name, but with a tilde character at the beginning. Upon closer inspection, I notice that it contains the code that was in lines 30 and 31 of Code 05. Nothing else has been added. Nevertheless, you claim—and I can verify this by running the code—that the object is deleted. Now I do not understand anything at all. To me, that makes absolutely no sense. I know: this can only be the work of the DEVIL. Because GOD would not have made something so complicated."

Indeed, dear reader, there is something intriguing about destructors. To understand them properly, we need to learn about one more concept. This concept was explained in the first articles of this series, when we discussed variables. Read this carefully, and you will understand why Code 06 works, as well as how to declare and use a destructor.

In the article “From Basic to Intermediate: Variables (I)”, we discussed variable lifetime and variable scope. If you have any doubts about this, please refer to that article for more detailed information. Understanding both concepts will help you understand when the compiler calls a destructor and will also allow you to use object-oriented programming more effectively.

All right, let's take it one step at a time. First, you need to declare the destructor as shown in line 22 of code 06. In other words, you should add the tilde character (~) before the class name. This way, the compiler will understand that the special member function you are declaring is the destructor of the class itself. Since destructors and constructors NEVER RETURN ANY VALUE, you cannot use them for this purpose. You have to trust that your code will do everything in the best possible way.

Second point: unlike constructors, which can accept initialization arguments, as we saw in the previous article, destructors NEVER accept arguments, UNDER ANY CIRCUMSTANCES or FOR ANY REASON. Attempting to do this will result in an error that will prevent the code from being compiled and, consequently, the executable file from being created.

Third, destructors are always called implicitly, except when we use two operators, which we will discuss a little later. In other words, theoretically, YOU HAVE NO CONTROL over when and where the destructor will be called. The compiler determines this based on the variable lifetime. Let me repeat: in theory, that is exactly how it is. In practice, there are ways to control when and where a destructor will be called. For now, we will focus on the part that is easiest to understand.

Good, but now the question arises: what is variable lifetime? Well, dear reader, we discussed this in the first article of this series. Nevertheless, we can briefly review this here.

A variable comes into existence when it is declared and ceases to exist at the end of the block in which it was declared.

Okay, but that did not help me at all, because I still do not understand anything. In that case, I suggest you go back to the first articles in this series and study them carefully. A clear understanding of these concepts will allow you to use MQL5 as effectively as possible. Without these, forget it: you will not be able to understand the explanation.

Let's continue. When, on line 32, we declare the variable `channel`, whose type is the `C_Regression` class, the default constructor of that class is called. This was discussed in the previous article. However, upon completion of the code block beginning on line 31—that is, when execution proceeds to line 35—the variables declared within it are destroyed. In this case, the only variable in the block is `channel`. Since the compiler knows that `channel` is a class instance, it will look for a destructor in `C_Regression`. If a destructor is not defined, the compiler will generate one so that the object can be destroyed correctly. Keep the following in mind: the compiler DOES NOT KNOW HOW TO DESTROY AN OBJECT. It will simply generate an implicit destructor in accordance with the language's rules. Thus, you will be able to compile the code and create an executable file.

However, since we defined and implemented a destructor on line 22 of our C_Regression class, the compiler will generate a call to execute this code when the lifetime of the object associated with the variable `channel` ends. For this reason, even though it is not explicitly stated in the code, the OBJ_REGRESSION object is removed from the chart.

"How interesting! Now I am really starting to understand how code 06 works and how the destructor is called. However, a question just came to mind. I have been reading these articles and have learned a lot of interesting things presented in a very accessible way. However, what has been shown here appears to apply only to this specific case. Couldn't this be done some other way?" What do you mean, dear reader? Please try to be a little more specific so I can help you.

"I want to understand the following: in Code 06, we use a script to demonstrate what we saw earlier in the indicator created in Code 03. So far, everything is clear. In the indicator, when we asked MetaTrader 5 to remove it, the OnDeinit function was called. In Code 06, this would be equivalent to calling the destructor on line 22, as explained earlier. The same thing happens with the constructor. In Code 03, this task was performed by the OnInit function on line 7. In Code 06, this task is performed by the constructor on line 12, which is called when line 32 is executed. I have the following question: can we use the same class from Code 06 in Code 03? And if so, how should we do it?"

That is an excellent question, dear reader. The answer is YES. We can use the same class, as implemented in Code 06, in Code 03 without any problems. To help you clearly understand how to do this, we will move the class to a header file. This way, we will be able to use it both in a script and in any other code—whether it is an indicator, an Expert Advisor, or even a service. However, when it comes to services, we will need to take a few additional steps, which we will discuss later.

With that in mind, we create the header file shown below:

01. //+------------------------------------------------------------------+
02. class C_Regression
03. {
04.     private :
05. //+----------------+
06.     public  :
07. //+----------------+
08.         C_Regression()
09.         {
10.             datetime    dt0 = TimeCurrent(),
11.                         dt1[20];
12. 
13.             CopyTime(NULL, NULL, dt0, dt1.Size(), dt1);
14.             ObjectCreate(0, def_NameChannel, OBJ_REGRESSION, 0, dt1[0], 0, dt0, 0);
15.             ChartRedraw();
16.         }
17. //+----------------+
18.         ~C_Regression()
19.         {
20.             ObjectDelete(0, def_NameChannel);
21.             ChartRedraw();
22.         }
23. //+----------------+
24. };
25. //+------------------------------------------------------------------+

Code 07

Please note that the class code has remained unchanged. To use it in a script similar to Code 06, we will use a somewhat different approach. The new code is shown below:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #define def_NameChannel    "Demo"
05. //+------------------------------------------------------------------+
06. #include <Tutorial\File 01.mqh>
07. //+------------------------------------------------------------------+
08. void OnStart(void)
09. {
10.     C_Regression channel;
11.     
12.     Sleep(2000);
13. }
14. //+------------------------------------------------------------------+

Code 08

If you do not understand Code 08, I recommend reading the article “From Basic to Intermediate: The Include Directive”, which explains how this directive works and what precautions you need to take to ensure the code works correctly. You also need to understand how definitions work. To do this, you can read the article “From Basic to Intermediate: Definitions (I)”, which explains everything you need to know to fully understand Code 08.

So, we now have the header file shown in Code 07, which can be used in other types of MQL5 code. Let's take a look at how to use this same class, but now in code equivalent to Code 03. To do this, we need to create something similar to what is shown below:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. #property description "Demo"
04. //+------------------------------------------------------------------+
05. #define def_NameChannel    "Demo"
06. //+------------------------------------------------------------------+
07. #include <Tutorial\File 01.mqh>
08. //+------------------------------------------------------------------+
09. int OnInit()
10. {
11.     return INIT_SUCCEEDED;
12. };
13. //+------------------------------------------------------------------+
14. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
15. {
16.     return rates_total;
17. };
18. //+------------------------------------------------------------------+
19. void OnDeinit(const int reason)
20. {
21. };
22. //+------------------------------------------------------------------+

Code 09

To use the class correctly in Code 09, we need to revisit the topic of variables. Once again: if you do not understand the simplest concepts, you will not be able to understand the more complex ones. So, if you have any doubts, go back to the previous articles. Our problem here is the variable lifetime. Sometimes this concept complicates things a bit.

This issue did not occur in Code 03, since we did not need to declare any variables. Everything was done locally and in complete isolation. However, in this new code, we will not be able to proceed in the same way. If we try to do this, the local variable will be destroyed immediately after the code block ends. So, how can we solve this problem? The solution is to use a global variable. Therefore, it will not be destroyed until the program has finished running. This is where things get much more interesting and exciting—but also significantly more dangerous for those who are not paying close attention to what they are implementing or who try to skip steps in the learning process. The code below produces the same result as before.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. #property description "Demo"
04. //+------------------------------------------------------------------+
05. #define def_NameChannel    "Demo"
06. //+------------------------------------------------------------------+
07. #include <Tutorial\File 01.mqh>
08. //+------------------------------------------------------------------+
09. C_Regression gl_Channel;
10. //+------------------------------------------------------------------+
11. int OnInit()
12. {
13.     return INIT_SUCCEEDED;
14. };
15. //+------------------------------------------------------------------+
16. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
17. {
18.     return rates_total;
19. };
20. //+------------------------------------------------------------------+
21. void OnDeinit(const int reason)
22. {
23. };
24. //+------------------------------------------------------------------+

Code 10

Code 10 looks quite surprising if you analyze it closely. At the same time, we did not create anything explicitly. All we need to do is declare, on line 09, a variable of type C_Regression, which is defined in the file included on line 07. You might be thinking, "Wow, this code doesn't actually do anything, since no operations are performed inside the OnInit function. The same thing happens with other event handlers, as you can verify by examining OnCalculate and OnDeinit. So, this code is completely useless. And that is all."

Hmm. I think you have not fully understood how the compiler manages the way classes work. That is why you claim that Code 10 is completely useless. However, unlike Code 09, which really does nothing, the same cannot be said of Code 10. It actually performs a single operation: it places an object defined within the C_Regression class on the chart. "But why is this happening if, apparently, there is no code snippet inside the functions and procedures that MetaTrader 5 will execute? If this really works, I just can't figure out why. Could you explain this to me in a way that I can understand, too?"

So, dear reader, you must remember that by declaring a variable, we perform an operation. However, when working with classes—unlike with other data types and structures—a slightly more complex operation is performed. As I have already explained, when the compiler encounters a variable declaration of a class type, it looks for a suitable constructor. If a class does not declare any constructors, the compiler creates one so that the object can be initialized correctly. If a suitable constructor is defined in your code, the compiler generates a call to execute the exact code implemented within it.

Therefore, when line 09 is executed, the class constructor will be called. Since this constructor is located on line 8 of code 07, its entire contents will be executed, and the object we have been working with since the beginning of this article will be created. This object will remain on the chart until the indicator is permanently removed; in this case, this is code 10. When this happens, the global variable declared on line 9 of code 10 will be destroyed. It is at this very moment that the destructor will be called. In other words, all the code implemented in the destructor on line 18 of code 07 will be executed.

As I said at the beginning, in object-oriented programming, things are not always what they seem. That is why you should study and practice before you assume you have already mastered something you do not actually understand yet.

"All right, dear author. I agree with you on this point. However, before we finish, I would like to ask you this. If code 10 works the way you just explained, then before we wrap up, I would like to ask this: is there any way to control when the class code will be executed? I want to avoid odd code where simply declaring a variable of a class type already triggers a constructor call. So, can we control this behavior?" Yes, dear reader. However, to avoid making this article even more complicated, we will not discuss that for now.


Concluding Thoughts

This article may well leave more readers than any other wondering what to do next. Although I have tried to explain this topic as simply and clearly as possible, it is practically impossible to fully understand the material just by reading the article. You should study what we have discussed here and put it into practice to truly understand how these mechanisms work and why they behave the way they do.

I know this topic seems pretty confusing at first. That is why I have spent a lot of time studying C++ and trying to understand it. Although some people believe that this can be learned in a few days, I regret to say that in practice, this is not the case. It takes months, or even years, to master C++ before you can say, "Yes, I'm a C++ programmer." However, MQL5 is not C++. In fact, MQL5 is much simpler than C++. That does not mean the expertise I have gained over the years of programming has not been useful to me. Quite the opposite. Most of what I explain and demonstrate in this article is based on my own experience and the challenges I faced while learning object-oriented programming.

Therefore, dear reader, make sure you fully grasp the ideas I am sharing, and start practicing and studying what is shown in this short series of articles. Starting with the next article, things will start to get a little more complicated if you have not fully understood what we have covered and explained here. See you in the next article, where I will explain how to better control the use of classes to avoid what happens in Code 10.

MQ5 file Description
Indicator\Code 01 Demo file
Indicator\Code 02 Demo file
Script\Code 01 Demo file
Script\Code 02 Demo file
Script\Code 03 Demo file
Script\Code 04 Demo file

Translated from Portuguese by MetaQuotes Ltd.
Original article: https://www.mql5.com/pt/articles/16764

Attached files |
Anexo.zip (3.45 KB)
Eco-inspired Evolutionary Algorithm (ECO) Eco-inspired Evolutionary Algorithm (ECO)
The article discusses the ECO optimization algorithm, which is based on ecological concepts: populations are grouped into habitats based on territorial proximity, exchange genetic material within habitats, and migrate between them. Despite its wide range of operators and elegant biological metaphor, the algorithm produced a certain result discussed below.
Neural Networks in Trading: Generalizing Time Series Without Data-Specific Dependence (Conclusion) Neural Networks in Trading: Generalizing Time Series Without Data-Specific Dependence (Conclusion)
The article will show you how Mamba4Cast turns theory into a working trading algorithm and lays the groundwork for your own experiments. Do not miss this opportunity to gain a full range of knowledge and inspiration for developing your own strategy.
Building Your Personal Expert Advisor (Part 5): Risk Management IV—Basket Risk and Strategy-Specific Sizing Building Your Personal Expert Advisor (Part 5): Risk Management IV—Basket Risk and Strategy-Specific Sizing
Part 5 moves risk control from single trades to a basket-level framework. The EA aggregates its own positions, computes volume‑weighted entry, floating P/L including swap, and used margin, then enforces limits on combined loss, margin, position count, and time underwater, while logging maximum adverse excursion. A companion mean‑reversion EA demonstrates target‑based sizing and caps on implied risk that remains hidden when trades are evaluated in isolation.
Automating Chart Patterns in MQL5 (Part 2): The Double Top and Double Bottom Automating Chart Patterns in MQL5 (Part 2): The Double Top and Double Bottom
We build a robust MQL5 detector for double tops and double bottoms that first confirms the H4 trend, then validates six conditions (point equality, neckline placement, ordering, width, height, and ATR‑based tolerances). The neckline break is timed on the chart's timeframe, and a three-state machine ensures each pattern trades once. The measured‑move target translates structure into clear exits.