Popular Posts

Editor'S Choice - 2020

MQL4: Correcting errors and warnings during compilation in MetaEditor

Developing MQL4 trading experts is not an easy task. Firstly, the algorithmization of any complex trading system is already a problem, since you need to take into account a lot of details, starting with the features of the TS and ending with the specifics of the MetaTrader 4 environment. Secondly, even the presence of a detailed algorithm does not eliminate the difficulties that arise when transferring the developed algorithm to the MQL4 programming language.

The compiler provides some assistance in writing the correct experts. After starting the compilation, MetaEditor will report all syntax errors in your code. But, unfortunately, in addition to syntax errors, your adviser may also contain logical errors that the compiler cannot catch. Therefore, we will have to do this ourselves. How to do this is in our material today.

The most common compilation errors

If there are errors in the code, the program cannot be compiled. For full control of all errors, it is recommended to use strict compilation mode, which is set by the directive:

#property strict

This mode greatly simplifies the search for errors. Now let's move on to the most common compilation errors.

Identifier matches reserved word

If the name of the variable or function matches one of the reserved words:

int char; // wrong int char1; // correct int char () // wrong {return (0); }

then the compiler displays error messages:

To fix this error, you need to fix the name of the variable or function. I recommend sticking with the following naming system:

All functions must indicate an action. That is, it must be a verb. For example, OpenLongPosition () or ModifyStopLoss (). After all, functions always do something, right?

In addition, it is advisable to call functions in the so-called CamelCase style. And the variables are in cebab_case style. This is a common practice.

Speaking of variable names. Variables are nouns. For example, my_stop_loss, day_of_week, current_month. It’s not so scary to name a variable by a long name; What is a dow, Dow Jones index? No, it turns out to be the day of the week. Of course, today you already understand what this variable is. But when you open the advisor code a month later, everything will not be so obvious. And this time lost on decoding messages from the past - do you need it?

Special characters in variable and function names

Move on. If the names of variables or functions contain special characters ($, @, period):

int $ var1; // wrong int @ var2; // wrong int var.3; // wrong void f @ () // wrong {return; }

then the compiler displays error messages:

To correct this error, you again need to adjust the names of variables or functions, well, or immediately call them humanly. Ideally, the code should be written so that even a person who does not know programming just read it and understand what is going on there.

Errors using the switch statement

The old version of the compiler allowed using any values ​​in the expressions and constants of the switch statement:

void start () {double n = 3.14; switch (n) {case 3.14: Print ("Pi"); break; case 2.7: Print ("E"); break; }}

In the new compiler, the expressions and constants of the switch statement must be integers, so when using such constructs, errors occur:

Therefore, when you parse classics code, such as WallStreet, Ilan, and other incorruptibles (which is very useful for self-development), you can come across this error. It is treated very simply, for example, when using such a line here:

switch (MathMod (day_48, 10))

This is how you can easily solve the problem:

switch ((int) MathMod (day_48, 10))

Function Return Values

All functions except void must return a value of the declared type. For example:

int function () {}

In strict compilation mode (strict), an error occurs:

In compilation mode, the compiler displays a warning by default:

If the return value of the function does not match the declaration:

int init () {return; }

Then, in strict compilation mode, an error occurs:

In compilation mode, the compiler displays a warning by default:

To fix such errors in the function code, you just need to add a return statement return with a return value of the corresponding type.

Arrays in function arguments

Arrays in function arguments are passed only by reference. Previously, this was not so, so in old advisers you can find this error. Here is an example:

double ArrayAverage (double a) {return (0); }

Given code in strict compilation mode (strict) will result in an error:

In compilation mode, the compiler displays a warning by default:

To fix such errors, you must explicitly indicate the transfer of the array by reference, adding the & prefix to the array name:

double ArrayAverage (double & a) {return (0); }

By the way, constant arrays (Time, Open, High, Low, Close, Volume) cannot be passed by reference. For example, a call:

ArrayAverage (Open);

regardless of compilation mode leads to an error:

To eliminate such errors, you need to copy the necessary data from the constant array:

// --- array for storing open price values ​​double OpenPrices; // --- copy the opening price values ​​into the OpenPrices ArrayCopy array (OpenPrices, Open, 0,0, WHOLE_ARRAY); // --- call the function ArrayAverage (OpenPrices);

One of the most common mistakes is the loss of an indicator by an adviser. In such cases, usually the expert users on the forums angrily write: "The adviser does not work!" or "I put the adviser on the chart and nothing happens!". The solution to this issue is actually very simple. As always, just look at the "Log" tab of the terminal and find there an entry like:

2018.07.08 09: 15: 44.957 2016.01.04 00:51 cannot open file 'C: Users1AppDataRoamingMetaQuotesTerminal MQL4indicatorsKELTNER_F12.ex4' 2

This tells us that they forgot to put the indicator in the folder, or it is named differently. If the indicator is missing, you need to add it to the folder with indicators. If it is, it is worth checking its name in the code of the adviser - most likely it is called differently there.

Compiler warnings

Compiler warnings are for informational purposes and are not error messages, however, they indicate possible sources of errors and it is better to correct them. Clean code should not contain warnings.

Intersections of global and local variable names

If at the global and local levels there are variables with the same name:

int i; // global variable void OnStart () {int i = 0, j = 0; // local variables for (i = 0; i <5; i ++) {j + = i; } PrintFormat ("i =% d, j =% d", i, j); }

then the compiler displays a warning and indicates the line number on which the global variable is declared:

To correct such warnings, you need to adjust the names of global variables.

Type mismatch

In the following example:

#property strict void OnStart () {double a = 7; float b = a; int c = b; string str = c; Print (c); }

in strict compilation mode with type mismatch, the compiler displays warnings:

In this example, the compiler warns of a possible loss of precision when assigning various data types and implicit conversion of type int to string.

To fix, you need to use explicit type conversion:

#property strict void OnStart () {double a = 7; float b = (float) a; int c = (int) b; string str = (string) c; Print (c); }

Unused variables

The presence of variables that are not used in the program code (extra entities) is not a good form.

void OnStart () {int i, j = 10, k, l, m, n2 = 1; for (i = 0; i <5; i ++) {j + = i;}}

Messages about such variables are displayed regardless of the compilation mode:

To fix it, you just need to remove unused variables from the program code.

Diagnostics of compilation errors

Often, after writing a program, compilation problems arise due to errors in the code. These may be the most varied mistakes, but in any case, there is a need to quickly detect a code section where an error is made.

Often, people take a lot of time and a lot of nerves in search of some extra bracket. However, there is a way to quickly detect errors, which is based on the use of commenting.

Writing a large enough code without a single mistake is very nice. But, unfortunately, this does not happen often. I do not consider errors here that lead to incorrect code execution. Here we will talk about errors that make compilation impossible.

Common mistakes are inserting an extra bracket in a difficult condition, lack of a bracket, not setting a colon, a comma when declaring variables, a typo in the variable name, and so on. Often when compiling, you can immediately see in which line a similar error was made. But there are times when finding such an error is not so simple. Neither the compiler nor the keen eye can help us immediately find the error. In such cases, as a rule, novice programmers begin to "go around" all the code, trying to visually identify the error. And again and again, while the nerves withstand.

However, MQL, like other programming languages, offers an excellent tool - commenting. Using it, you can disable some parts of the code. Usually, comments are used to insert some kind of comments, or to disable unused sections of code. Commenting can also be successfully applied when searching for errors.

The search for errors usually comes down to determining the code section where the error is made, and then, in this section, the error is visually located. I think it’s unlikely that anyone will doubt that it’s easier and faster to examine 5-10 lines of code more quickly than 100-500, or even several thousand.

When using commenting, the task is extremely simple. First you need to comment out the various sections of the code (sometimes almost the entire code), thereby “disabling” it. Then, in turn, the commentary is removed from these sections of the code. After the next withdrawal of commenting, an attempt is made to compile. If the compilation is successful, the error is not in this section of code. Then the next section of code opens and so on. When there is a problem part of the code, an error is visually searched, then it is eliminated. Again, an attempt is made to compile. If everything went well, the error is resolved.

It is important to correctly identify the sections of code that you need to comment on. If this condition (or other logical construction), then it should be fully commented. If you comment on the section of code where the variables are declared, it is important that the section where these variables are accessed is not opened. In other words, commenting should be applied according to programming logic. Failure to comply with this approach leads to new, misleading, compilation errors.

Here is a great example of an error when it is not clear where to look for it and commenting on the code can help us.

Runtime errors

Errors that occur during the execution of program code are commonly called runtime errors. Such errors usually depend on the state of the program and are associated with incorrect values ​​of variables.

For example, if a variable is used as an index of array elements, then its negative values ​​will inevitably lead to an outflow of the array.

Array out of range

This error often occurs in indicators when accessing indicator buffers. The IndicatorCounted () function returns the number of bars that have not changed since the last indicator call. The values ​​of indicators on previously calculated bars do not need to be recalculated, therefore, to speed up the calculations, it is sufficient to process only the last few bars.

Most indicators that use this method of optimization of calculations have the following form:

// + ----------------------------------------------- ------------------- + // | Custom indicator iteration function | // + ----------------------------------------------- ------------------- + int start () {// --- sometimes at least N bars are required for the calculation (for example, 100) // if there is no such on the chart the number of bars (for example, on the MN timeframe) if (Bars <100) {return (-1); // stop the calculation and exit ahead of schedule} // --- the number of bars that have not changed since the last indicator call int counted_bars = IndicatorCounted (); // --- in case of an error, exit if (counted_bars0 // --- during repeated calls, increase the limit by 1 to // --- guaranteed to update the indicator values ​​for the last bar limit ++;} // --- the main calculation cycle for (int i = limit; i> 0; i--) {// using the values ​​of bars going deeper into the history by 5 and 10 Buff1i = 0.5 * (Openi + 5 + Closei + 10)}}

The incorrect case handling is often encountered counted_bars == 0 (the initial position of limit must be reduced by a value equal to 1 + the maximum index relative to the loop variable).

It should also be remembered that at the time the start () function is executed, we can access the elements of the indicator buffer arrays from 0 to Bars () - 1. If there is a need to work with arrays that are not indicator buffers, then their size should be increased using the ArrayResize () function in accordance with the current size of indicator buffers. The maximum index of an element for addressing can also be obtained by calling ArraySize () with one of the indicator buffers as an argument.

Division by zero (Zero divide)

The “Zero divide” error occurs if the divider is equal to zero during the division operation:

void OnStart () {int a = 0, b = 0, c; c = a / b; Print ("c =", c); }

When this script is executed, the “Experts” tab displays an error message and the program terminates:

Typically, such an error occurs in cases where the value of the divider is determined by the values ​​of some external data. For example, if trading parameters are analyzed, then the value of the margin involved will be 0 if there are no open orders. Another example: if the analyzed data is read from a file, then if it is absent, correct operation cannot be guaranteed. For this reason, it is advisable to try to take into account such cases and correctly handle them.

The easiest way is to check the divisor before the division operation and display a message about the incorrect parameter value:

void OnStart () {int a = 0, b = 0, c; if (b! = 0) {c = a / b; Print (c); } else {Print ("Error: b = 0"); return }}

As a result, a critical error does not occur, but a message is displayed about the incorrect value of the parameter and the operation ends:

Using 0 instead of NULL for the current character

In the old version of the compiler, it was allowed to use 0 (zero) as an argument in functions requiring a financial instrument.

For example, the value of the Moving Average technical indicator for the current symbol could be requested as follows:

AlligatorJawsBufferi = iMA (0,0,13,8, MODE_SMMA, PRICE_MEDIAN, i); // wrong

In the new compiler, to indicate the current character, you must explicitly specify NULL:

AlligatorJawsBufferi = iMA (NULL, 0.13.8, MODE_SMMA, PRICE_MEDIAN, i); // right

In addition, the current symbol and chart period can be specified using the Symbol () and Period () functions.

AlligatorJawsBufferi = iMA (Symbol (), Period (), 13.8, MODE_SMMA, PRICE_MEDIAN, i); // right

Even better, if you use the predefined variables _Symbol and _Period - they are processed faster:

AlligatorJawsBufferi = iMA (_Symbol, _Period, 13.8, MODE_SMMA, PRICE_MEDIAN, i); // right

Unicode strings and their use in DLL

Strings are a sequence of Unicode characters. Keep this fact in mind and use the appropriate Windows features. For example, when using the library functions wininet.dll instead of InternetOpenA () and InternetOpenUrlA (), you should call InternetOpenW () and InternetOpenUrlW (). When passing strings to a DLL, use the MqlString structure:

#pragma pack (push, 1) struct MqlString {int size; // 32-bit integer, contains the size of the buffer allocated for the string LPWSTR buffer; // 32-bit address of the buffer containing the string int reserved; // 32-bit integer, reserved, do not use}; #pragma pack (pop, 1)

File sharing

When opening files, you must explicitly specify the FILE_SHARE_WRITE and FILE_SHARE_READ flags for sharing.

If they are absent, the file will be opened in exclusive mode, which will not allow anyone else to open it until it is closed by the monopolist.

For example, when working with offline charts, you must explicitly specify the shared flags:

// 1-st change - add share flags ExtHandle = FileOpenHistory (c_symbol + i_period + ". Hst", FILE_BIN | FILE_WRITE | FILE_SHARE_WRITE | FILE_SHARE_READ);

Datetime conversion feature

Keep in mind that converting a datetime type to a string depends on the compilation mode:

datetime date = D'2014.03.05 15:46:58 '; string str = "mydate =" + date; // --- str = "mydate = 1394034418" - without the #property strict directive // ​​--- str = "mydate = 2014.03.05 15:46:58" - with the #property strict directive

For example, an attempt to work with files whose name contains a colon will result in an error.

Runtime Error Handling

Since no trading expert can do without using the built-in user-defined functions, first of all we will try to simplify our life when analyzing the errors returned by these functions.

Some libraries are available in the set “out of the box” to simplify the writing of advisers, including those for working with errors. They are stored in the MQL4 / Include folder:

We will need two libraries:

  • stderror.mqh - contains constants for the number of each error;
  • stdlib.mqh - contains several auxiliary functions, including the function of returning the error description as a string:
string ErrorDescription (int error_code)

Therefore, we will connect both of these libraries to our project:

#include #include 

The error descriptions themselves are in the MQL4 / Library / stdlib.mql4 file and they are in English. Therefore, if you are against foreign languages, you can always rewrite the descriptions in your native language.

Another built-in function we need is GetLastError (). It is she who returns the error codes in the form of an integer (int), which we will then process. Error codes and their descriptions in Russian can be found in the mql4 manual from MetaQuotes. From there, you can take information to translate the stdlib.mql4 file into Russian.

Now that we have connected the necessary libraries, we will consider the results of the functions directly related to trading operations, since ignoring malfunctions in these functions can lead to critical consequences for the bot.

Unfortunately, using MQL4, you cannot write a generalized library to handle all possible error situations. In each case, you will have to handle the errors separately. But not everything is so bad - many errors do not need to be processed, it is enough to eliminate them at the stage of development and testing of an expert, although for this you need to know in time about their presence.

For example, consider two errors typical for MQL4 experts:

  1. Error 130 - ERR_INVALID_STOPS

One of the cases when the first error occurs is the expert’s attempt to place a pending order too close to the market. Its presence can seriously impair expert performance in some cases. For example, let’s say an expert, having opened a profitable position, makes profit every 150 points. If the next such attempt causes an error of 130, and the price irretrievably returns to the previous stop level, the expert may deprive you of a legitimate profit. Despite the possibility of such consequences, this error can be eliminated fundamentally by finalizing the expert code so that it takes into account the minimum allowable distance between the price and stops.

The second error related to the busyness of the trading context of the terminal cannot be completely eliminated. When several experts work in the same terminal, it is always possible that one of the experts will try to open a position while the other is still doing the same. Therefore, such an error should always be handled.

Thus, we should always be aware if any of the built-in functions used returns an error while the EA is working. This can be achieved using the following simple helper function:

void logError (string functionName, string msg, int errorCode = -1) {Print ("ERROR: in" + functionName + "()"); Print ("ERROR:" + msg); int err = GetLastError (); if (errorCode! = -1) {err = errorCode; } if (err! = ERR_NO_ERROR) {Print ("ERROR: code =" + err + "-" + ErrorDescription (err)); }}

We will use it as follows:

void openLongTrade () {int ticket = OrderSend (Symbol (), OP_BUY, 1.0, Ask + 5, 5, 0, 0); if (ticket == -1) {logError ("openLongTrade", "could not open order"); }}

Of course, this is a simplified example. For writing more competent functions of opening, closing and modifying orders, see this lesson.

The first parameter to the logError () function is the name of the function in which the error was detected, in our example, in the openLongTrade () function. If our expert calls the OrderSend () function in several places, this will allow us to determine exactly in which of them the error occurred. The second parameter passes the description of the error so that you can understand exactly where the error was detected inside the openLongTrade () function. This can be either a short description of the error or a more detailed description of the values ​​of all parameters passed to the built-in function.

I prefer the latter option, since if an error occurs, you can immediately get all the information necessary for analysis. For example, suppose that before calling OrderSend (), the current price had to deviate greatly from the last known price. As a result, an error will occur during the execution of this example, and the following lines will appear in the expert log:

ERROR: in openLongTrade () ERROR: could not open order ERROR: code = 138 - requote

That is, you will immediately see:

  • in which function the error occurred;
  • what it refers to (in this case, an attempt to open a position);
  • which error occurred (error code and its description).

Now consider the third, optional, parameter to the logError () function. It is necessary in those cases when we want to process a specific type of error, and we will report on the rest in the protocol of the expert’s work, as before:

void updateStopLoss (double newStopLoss) {bool modified = OrderModify (OrderTicket (), OrderOpenPrice (), newStopLoss, OrderTakeProfit (), OrderExpiration ()); if (! modified) {int errorCode = GetLastError (); if (errorCode! = ERR_NO_RESULT) {logError ("updateStopLoss", "failed to modify order", errorCode); }}}

This is where the built-in OrderModify () function is called in the updateStopLoss () function. This function is slightly different in terms of error handling from OrderSend (). If none of the parameters of the order to be changed differs from its current parameters, then the function will return an error ERR_NO_RESULT. If in our expert such a situation is permissible, then we should specifically ignore this error. To do this, we analyze the value returned by GetLastError (). If an error occurs with the code ERR_NO_RESULT, then we do not output anything to the protocol.

However, if another error occurred, it is necessary to fully report on it, as we did before. That is why we save the result of the GetLastError () function in an intermediate variable and pass it the third parameter to the logError () function. The fact is that the built-in GetLastError () function automatically resets the code of the last error after its call. If we did not pass the error code explicitly to logError (), then an error with code 0 and a description of “no error” would be reflected in the protocol.

Similar actions must be performed while processing other errors, for example, requotes. The main idea is to handle only errors that need to be processed, and pass the rest to the logError () function. Then we will always be in the know if an unexpected error occurred during the expert’s work. After analyzing the logs, we can decide whether this error requires separate processing or whether it can be eliminated by finalizing the expert code. This approach often significantly simplifies life and reduces the time it takes to deal with errors.

Diagnostics of logical errors

Logical errors in the expert code can cause many problems. The lack of the possibility of step-by-step debugging of experts makes the fight against such errors not a very enjoyable task. The main tool for diagnosing this at the moment is the built-in Print () function. Using it, you can print the current values ​​of important variables, as well as log the expert’s work directly in the terminal during testing. When debugging an expert during testing with visualization, the built-in Comment () function can also help, which displays messages on a chart. As a rule, making sure that the expert does not work as intended, you have to add temporary calls to the Print () function and record the internal state of the expert in the alleged places where the error occurred.

However, to detect complex error situations, sometimes you have to add dozens of such calls to the Print () function, and after you find and fix the problem, you have to delete or comment on them so that the expert code is not cluttered and its testing is not slowed down. The situation worsens if the Print () function is already used in the expert code to periodically log various states. Then the removal of temporary calls to Print () cannot be performed by simply searching for the phrase 'Print' in the expert code. You have to think about it so as not to remove useful calls to this function.

For example, when logging the errors of the functions OrderSend (), OrderModify () and OrderClose (), it is useful to print the current value of the Bid and Ask variables into the protocol. This makes it easier to recognize the causes of errors such as ERR_INVALID_STOPS and ERR_OFF_QUOTES.

To highlight such diagnostic findings in the protocol, I recommend using the following auxiliary function:

void logInfo (string msg) {Print ("INFO:" + msg); }

This is desirable for several reasons. Firstly, now such calls will not come across when searching for 'Print' in the expert code, because we will search logInfo. Secondly, this function has another useful feature, which we will talk about a little later.

Adding and removing temporary diagnostic calls to the Print () function takes us valuable time. Therefore, I propose to consider another approach that is effective in detecting logical errors in the code and allows us to save our time a little. Consider the following simple function:

void openLongTrade (double stopLoss) {int ticket = OrderSend (Symbol (), OP_BUY, 1.0, Ask, 5, stopLoss, 0); if (ticket == -1) {logError ("openLongTrade", "could not open order"); }}

In this case, since we are opening a long position, it is quite obvious that during normal operation of the expert, the value of the stopLoss parameter will never be greater than or equal to the current Bid price. That is, when the openLongTrade () function is called, the stopLoss <Bid condition is always satisfied. Since we know about this even at the stage of writing the function in question, we can immediately use it as follows:

void openLongTrade (double stopLoss) {assert ("openLongTrade", stopLoss <Bid, "stopLoss <Bid"); int ticket = OrderSend (Symbol (), OP_BUY, 1.0, Ask, 5, stopLoss, 0); if (ticket == -1) {logError ("openLongTrade", "could not open order"); }}

That is, we log our statement in the code using the new helper function assert (). The function itself looks pretty simple:

void assert (string functionName, bool assertion, string description = "") {if (! assertion) {Print ("ASSERT: in" + functionName + "() -" + description); }}

The first parameter of the function is its name, in which our condition is checked (by analogy with the logError () function). The second parameter passes the result of checking this condition. And the third parameter is its description. As a result, if the expected condition is not met, the following information will be displayed in the protocol:

  • the name of the function in which the condition was violated;
  • description of the violated condition.

As a description, you can pass, for example, the condition itself, or you can display a more detailed description containing the values ​​of the controlled variables at the time of checking the condition, if this helps to understand the causes of the error.

Of course, the considered example is maximally simplified. But, I hope, the main idea reflects quite well. In the process of building up the expert’s functionality, we are aware of how it should work and which states and input parameters of the functions are valid and which are not. Fixing this in the expert code using the assert () function, we obtain valuable information about the place in which the logic of the expert’s work is violated. Moreover, we partially relieve ourselves of the need to add and remove temporary calls to the Print () function, since the assert () function issues diagnostic messages to the protocol only when inconsistencies are detected under the expected conditions.

Another useful trick is to use this function before each division operation. The fact is that sometimes as a result of one or another logical error, sometimes division by zero occurs. The expert’s work in this case is terminated, and only one line appears in the protocol with a sad diagnosis: 'zero divide'. Finding out exactly where this error occurred if the division operation is used repeatedly in the code is quite difficult. The assert () function will help here. We insert the corresponding checks before each division operation:

assert ("buildChannel", distance> 0, "distance> 0"); double slope = delta / distance;

And now, in the case of division by zero, it will be enough just to look in the logs to find out in which exact place the error occurred.

State handling

While the expert is working on your account, some situations may arise that are not errors - the so-called expert states. Such states are not errors, but still they should be logged. The special functions of the mql4 language help in this.

The IsExpertEnabled () function returns information about the ability to run experts. The function will return true if experts are allowed to run in the client terminal, otherwise returns false. If false returns, it will be useful to notify the user with a request to enable the appropriate setting. Example:

void OnStart () {if (! IsExpertEnabled () {// advisers are not allowed to trade Alert ("Attention! Please press the" Expert Advisors "button in MT4");} // working algorithm of the adviser return;}

If the expert uses external libraries, the IsLibrariesAllowed () function is useful. It returns true if the expert can call the library function, otherwise returns false.

If the library is in the form of a dll file, the IsDllsAllowed () function is useful. It will also be useful to check whether it is generally possible to trade with the help of experts using the IsTradeAllowed () function.

If you want to find out if the account is demo or real, you can use the IsDemo () function.

All of the above checks should be done in the OnInit () function.

Of course, it is worth checking periodically the connection with the server. The IsConnected () function will help.

The following three functions will help determine which mode the EA is in. If IsOptimisation () returns true, optimization is performed, if IsTesting (), then testing, IsVisualMode () - testing in visualization mode. For each of these options, the adviser can have its own logic. For example, for the visualization mode, you can display something on the chart (and not display in other modes for the sake of saving resources). In test mode, you can display debugging information, in optimization mode, lighten the code as much as possible in order to save time.

And the last function is IsTradeContextBusy (). It will return true if the thread for performing trading operations is busy. This can be useful when an expert performs trading operations. You can use the Sleep function to wait for a moment and try again.

Another useful feature is UninitializeReason ()

int deinit () {switch (UninitializeReason ()) {case REASON_CHARTCLOSE: case REASON_REMOVE: CleanUp (); break; // clean and free resources. case REASON_RECOMPILE: case REASON_CHARTCHANGE: case REASON_PARAMETERS: case REASON_ACCOUNT: StoreData (); break; // preparation for restart. } // ...}

You can also log the reason for the adviser to exit.

Codes of the most common errors and their probable solution

Error numberValueProblemDecision
4, 146Trading server busyThe adviser gave too many orders at the same time or without waiting for a response from the server, during the operation - the adviser tries to send a new orderRebooting the terminal or optimizing the advisor code using error handling functions
8, 141Too frequent requestsPrevious error reasons in a very frequent requestSimilar solution
129Wrong priceThe price at which you are trying to open a position (BUY or SELL) is incorrectBUY must be opened by Ask and closed by BID;
SELL needs to be opened by BID and closed by ASK
130, 145Wrong feetStop loss, take profit or the opening level of a pending or limiter are incorrect.
The stops are too close to the price.
Your account is opened in the ECN (ETSN) or NDD (NDD) group, which prevents you from immediately placing stops
Check the values ​​of your stop losses, take profits, check the minimum stop level for your instrument with a broker, when setting stops - observe the minimum distance level. A well-written adviser should have functions for working on ECN and NDD accounts - this happens by modifying the order after it is opened
131Wrong volumeWrong lot when opening a deal, or less than the minimum (more than the maximum). Bit depth of a lot may also differ from a broker bitCheck the correct opening of the lot, study the specification of the contract and read the terms of trade in your DC, check the minimum and maximum lot in your DC and on your account
132The market is closedThe market is closed on weekendsTry to contact the market after the weekend
133No tradeNo trading at this timeIt is forbidden to trade on this currency pair - at a particular point in time or in general. Often brokers have a break of a few minutes at midnight
134Not enough money to complete the operationThe lot you are trying to open is too large, it does not have enough marginCheck the level of available funds and calculate the funds that you need to open a lot, monitor the level of your available funds
135-138Price has changedRequote, too fast market (news), Broker or DC does not allow you to put a position at the declared priceDo not trade at such moments, increase the level of slippage, but remember that this entails the opening of positions not at the price you stated. Provide an error handling function and the number of attempts to open positions in the EA
147Using the expiration date of the order is prohibited by the brokerYour advisor or you are trying to set the expiration date of a pending orderIn the Expert Advisor, in the OrderSend function, set the expiration parameter to 0 (zero). Do not set an expiration date
148The number of open and pending orders has reached the limit set by the brokerThe maximum number of open orders and positions has reached the limit set by the brokerDelete or close part of the positions. Stop the process of opening new positions
4012, 4013Remainder of division by zeroYou are trying to divide the number by 0 (zero)Check the advisor code for an error, or check all values ​​from MarketInfo functions at the time of returning 0, sometimes when MarketInfo (Symbol (), MODE_SPREAD) not a spread is returned, but 0 (for brokers with a floating spread)
4017DLL calls not allowedDLL calling forbidden in your terminalAllow DLL call through Menu - Service - Settings - Advisor - Allow DLL call
4018, 4019Unable to load libraryThe library is damaged or its call fails, maybe it is missing at allCheck DLL
4020Calls to external library functions not allowedCalling functions from external experts is prohibited in your terminalAllow calling functions via Menu - Service - Settings - Advisor - Allow calling external experts
4103Unable to open fileThis file does not exist or is locked by another process.Check for the specified file. Check if the file is locked by the anti-virus system, whether the write-read mode of the file is allowed
4106Unknown characterNo symbol in the market overviewIn the market overview - right-click - show all symbols. Check the name of the symbol in the adviser and its presence in the market overview. Some advisors use clear names without suffixes, and brokers intentionally set suffixes, for example EURUSDx where x is the suffix
4108Invalid ticket numberThe order ticket that the expert selects does not exist. An expert is trying to choose a ticket, but this order was closed by another adviser or by hands. When trying to carry out an order over an order, the ticket was executed and closed by a brokerIf this error appears very often, 100-1000 times per minute, check the functions of your adviser. Disable other advisers or configure them so that they do not conflict, do not close the order with your hands when the expert performs the operation. Sometimes this happens when several advisers use the same MagicNumber.
4109Trade not allowedAdvisor is forbidden to trade, on the chart a sad smile or a crossTurn on the checkbox "Allow Advisor to Trade" in the deposit when installing the advisor, or in the menu - service - settings - advisers
4110, 4111Long / short positions not allowedIn the advisor settings, in the General tab, the type of positions is not allowedIn the General tab, when installing the adviser, there is a choice of positions allowed to open


The considered auxiliary functions and simple tricks can significantly simplify and speed up the process of detecting and fixing errors in the code of trading experts written in the MQL4 programming language. Proper writing of code and functions for logging and tracking the work of the adviser significantly speeds up the process of its development.

Watch the video: Mql4 Lesson 29 Including and Importing Files (February 2020).

Leave Your Comment