WWW mql5 Com en Articles 645
WWW mql5 Com en Articles 645
16 687 3
Anatoli Kazharski
Introduction
In this article, the Expert Advisor will be enhanced with indicators whose values will be used to check
position opening conditions. To spice it up, we will create a drop-down list in the external parameters to be
able to select one out of three trading indicators.
Please be reminded, just in case: we continue to modify the Expert Advisor we have been working on
throughout the preceding articles of the MQL5 Cookbook series. The last version of the Expert Advisor can
be downloaded from the article entitled "MQL5 Cookbook: The History of Deals And Function Library for
Getting Position Properties".
In addition, this article will feature a function that we will create to check whether trading operations can
or cannot be performed. The position opening function will be modified so as to enable the Expert Advisor
to determine the trade mode (Instant Execution and Market Execution).
Since the code of the Expert Advisor, following all the enhancements and improvements made in the
previous articles, already exceeds 1,500 lines, it will be getting less and less convenient with every new
feature added. So, the logical solution is to divide it into several categories as separate library files. Now
that the objectives have been set, let's start.
We place the source code of the Expert Advisor (*.mq5) from the previous article into a separate folder,
TestIndicatorConditions, in which we need to create the Include sub-folder. This is the folder where we
will be creating include files (*.mqh). They can be generated using the MQL5 Wizard (Ctrl+N) or created
manually in the required directory as standard text files (*.txt) and further renamed to *.mqh.
Below are the names of and comments to all the include files created:
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
To include these libraries to the main file, we use the #include directive. Since the main file of the Expert
Advisor and the include file folder (Include) are located in the same folder, the code for including files will
be as follows:
Then, we will be able to open and modify them and move a part of the source code from the main file of
the Expert Advisor.
To correctly navigate through the code, references to the adjacent header files, as well as to the main file
of the Expert Advisor will be added to each header file. For example, for our library of trading functions,
TradeFunctions.mqh, this will look like this:
For files at the same nesting level, it is sufficient to simply specify the name. In order to go one level up,
you need to put two dots before the back slash in the path.
Let's add enumeration for indicators in the Enums.mqh file. For illustrative purposes, in this Expert Advisor
we will use two standard indicators (Moving Average and Commodity Channel Index) and one custom
indicator (MultiRange_PCH). The enumeration will be as follows:
//--- Indicators
enum ENUM_INDICATORS
{
MA = 0, // Moving Average
CCI = 1, // CCI
PCH = 2 // Price Channel
};
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
input bool Reverse=true; // Position reversal
sinput bool ShowInfoPanel=true; // Display of the info panel
As mentioned above, you will be able to select one out of the three indicators in the drop-down list of the
Indicator parameter.
There is only one parameter applicable to all indicators where the indicator period can be set -
IndicatorPeriod. The NumberOfBars parameter from the previous version of the Expert Advisor has been
renamed to IndicatorSegments and now denotes the number of bars during which a given indicator must be
going up/down to satisfy the position opening condition.
Further, we have added another external parameter, VolumeIncreaseStep, that can be used to set the step
for volume increase in points.
Since the position opening condition will now be checked using indicator values, the value to be assigned
will always be greater by two. In other words, if the IndicatorSegments external variable is assigned the
value of 1, the AllowedNumberOfSegments variable will be assigned the value of 3, since in order to satisfy
the condition (e.g. for a BUY), the indicator value on the completed bar must be greater than that on the
previous bar. For this purpose, we need to get the last three indicator values.
//+------------------------------------------------------------------+
//| Adjusting input parameters |
//+------------------------------------------------------------------+
void CorrectInputParameters()
{
//--- Adjust the number of bars for the position opening condition
if(AllowedNumberOfSegments<=0)
{
if(IndicatorSegments<=1)
AllowedNumberOfSegments=3; // At least three bars are req
if(IndicatorSegments>=5)
AllowedNumberOfSegments=5; // but no more than 7
else
AllowedNumberOfSegments=IndicatorSegments+1; // and always greater by two
}
}
Before we start dealing with the indicators, let's create a function that will check whether trading is
allowed - CheckTradingPermission(). If trading is not allowed for any of the reasons listed in the function,
zero value will be returned. This will mean that the next try will have to be made on the next bar.
//+------------------------------------------------------------------+
//| Checking if trading is allowed |
//+------------------------------------------------------------------+
bool CheckTradingPermission()
{
//--- For real-time mode
if(IsRealtime())
{
//--- Checking server connection
if(!TerminalInfoInteger(TERMINAL_CONNECTED))
return(1);
//--- Permission to trade at the running program level
if(!MQL5InfoInteger(MQL5_TRADE_ALLOWED))
return(2);
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
//--- Permission to trade at the terminal level
if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
return(3);
//--- Permission to trade for the current account
if(!AccountInfoInteger(ACCOUNT_TRADE_ALLOWED))
return(4);
//--- Permission to trade automatically for the current account
if(!AccountInfoInteger(ACCOUNT_TRADE_EXPERT))
return(5);
}
//---
return(0);
}
Let's now get down to the main point of the article. To get access to values of the indicator, we need to first
get its handle. This is done using special functions whose names are made of the short name of the indicator
and the 'i' symbol preceding it.
For example, the Moving Average indicator has the corresponding function iMA(). All standard indicator
handles in the MetaTrader 5 terminal can be obtained using these functions. The full list is available in the
MQL5 Reference section called Technical Indicators. If you need to get a handle of a custom indicator, use
the iCustom() function.
We will implement the GetIndicatorHandle() function where depending on the indicator selected in the
Indicator parameter the handle value of the corresponding indicator will be assigned to the
indicator_handle global variable. The function code can be found in our library of trading signal functions
(the \Include\TradeSignals.mqh file), while the variable with the indicator handle is located in the main file
of the Expert Advisor.
//+------------------------------------------------------------------+
//| Getting the indicator handle |
//+------------------------------------------------------------------+
void GetIndicatorHandle()
{
//--- If the Moving Average indicator is selected
if(Indicator==MA)
indicator_handle=iMA(_Symbol,Period(),IndicatorPeriod,0,MODE_SMA,PRICE_CLOSE);
//--- If the CCI indicator is selected
if(Indicator==CCI)
indicator_handle=iCCI(_Symbol,Period(),IndicatorPeriod,PRICE_CLOSE);
//--- If the MultiRange_PCH indicator is selected
if(Indicator==PCH)
indicator_handle=iCustom(_Symbol,Period(),"MultiRange_PCH",IndicatorPeriod);
//--- If the indicator handle could not be obtained
if(indicator_handle==INVALID_HANDLE)
Print("Failed to get the indicator handle!");
}
Further, we create the GetDataIndicators() function where using the obtained indicator handles, we can get
their values. This is done using the CopyBuffer() function in the way similar to getting bar values using the
CopyTime(), CopyClose(), CopyOpen(), CopyHigh() and CopyLow() functions considered in the article called
"MQL5 Cookbook: Analyzing Position Properties in the MetaTrader 5 Strategy Tester".
Since the indicator can have several buffers (rows of values), the buffer index is passed to the CopyBuffer()
function as the second parameter. Buffer indices for standard indicators can be found in MQL5 Reference.
For custom indicators, buffer indices can be found in the code, provided the source code is available. If
there is no code, you will need to find the index by way of experiment, by observing how conditions are
satisfied in the visualization mode of the Strategy Tester.
Prior to that, we need to create dynamic arrays for indicator buffer values in the main file of the Expert
Advisor:
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
//--- Arrays for indicator values
double indicator_buffer1[];
double indicator_buffer2[];
//+------------------------------------------------------------------+
//| Getting indicator values |
//+------------------------------------------------------------------+
bool GetIndicatorsData()
{
//--- If the indicator handle has been obtained
if(indicator_handle!=INVALID_HANDLE)
{
//--- For the Moving Average or CCI indicator
if(Indicator==MA || Indicator==CCI)
{
//--- Reverse the indexing order (... 3 2 1 0)
ArraySetAsSeries(indicator_buffer1,true);
//--- Get indicator values
if(CopyBuffer(indicator_handle,0,0,AllowedNumberOfSegments,indicator_buffer1
{
Print("Failed to copy the values ("+
_Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer
IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError
return(false);
}
}
//--- For the MultiRange_PCH indicator
if(Indicator==PCH)
{
//--- Reverse the indexing order (... 3 2 1 0)
ArraySetAsSeries(indicator_buffer1,true);
ArraySetAsSeries(indicator_buffer2,true);
//--- Get indicator values
if(CopyBuffer(indicator_handle,0,0,AllowedNumberOfSegments,indicator_buffer1
CopyBuffer(indicator_handle,1,0,AllowedNumberOfSegments,indicator_buffer2
{
Print("Failed to copy the values ("+
_Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer
IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError
return(false);
}
}
//---
return(true);
}
//--- If the indicator handle has not been obtained, retry
else
GetIndicatorHandle();
//---
return(false);
}
The GetTradingSignal() function has substantially changed. The conditions are different in the absence of
the position and where the position exists. For the Moving Average and CCI indicators, the conditions are
the same. For MultiRange_PCH, they are arranged in a separate block. To make the code more readable and
to avoid repetitions, we create an auxiliary function, GetSignal(), that returns a signal for position opening
or reversal, provided that such position exists and the relevant action is allowed by the external parameter.
Below is the code of the GetSignal() function:
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
//+------------------------------------------------------------------+
//| Checking the condition and returning a signal |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE GetSignal()
{
//--- Check conditions for the Moving Average and CCI indicators
if(Indicator==MA || Indicator==CCI)
{
//--- A Sell signal
if(AllowedNumberOfSegments==3 &&
indicator_buffer1[1]<indicator_buffer1[2])
return(ORDER_TYPE_SELL);
//---
if(AllowedNumberOfSegments==4 &&
indicator_buffer1[1]<indicator_buffer1[2] &&
indicator_buffer1[2]<indicator_buffer1[3])
return(ORDER_TYPE_SELL);
//---
if(AllowedNumberOfSegments==5 &&
indicator_buffer1[1]<indicator_buffer1[2] &&
indicator_buffer1[2]<indicator_buffer1[3] &&
indicator_buffer1[3]<indicator_buffer1[4])
return(ORDER_TYPE_SELL);
//---
if(AllowedNumberOfSegments==6 &&
indicator_buffer1[1]<indicator_buffer1[2] &&
indicator_buffer1[2]<indicator_buffer1[3] &&
indicator_buffer1[3]<indicator_buffer1[4] &&
indicator_buffer1[4]<indicator_buffer1[5])
return(ORDER_TYPE_SELL);
//---
if(AllowedNumberOfSegments>=7 &&
indicator_buffer1[1]<indicator_buffer1[2] &&
indicator_buffer1[2]<indicator_buffer1[3] &&
indicator_buffer1[3]<indicator_buffer1[4] &&
indicator_buffer1[4]<indicator_buffer1[5] &&
indicator_buffer1[5]<indicator_buffer1[6])
return(ORDER_TYPE_SELL);
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
indicator_buffer1[2]>indicator_buffer1[3] &&
indicator_buffer1[3]>indicator_buffer1[4] &&
indicator_buffer1[4]>indicator_buffer1[5] &&
indicator_buffer1[5]>indicator_buffer1[6])
return(ORDER_TYPE_BUY);
}
//--- Block that checks conditions for the MultiRange_PCH indicator
if(Indicator==PCH)
{
//--- A Sell signal
if(close_price[1]<indicator_buffer2[1] &&
open_price[1]>indicator_buffer2[1])
return(ORDER_TYPE_SELL);
//--- A Buy signal
if(close_price[1]>indicator_buffer1[1] &&
open_price[1]<indicator_buffer1[1])
return(ORDER_TYPE_BUY);
}
//--- No signal
return(WRONG_VALUE);
}
//+------------------------------------------------------------------+
//| Determining trading signals |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE GetTradingSignal()
{
//--- If there is no position
if(!pos.exists)
{
//--- A Sell signal
if(GetSignal()==ORDER_TYPE_SELL)
return(ORDER_TYPE_SELL);
//--- A Buy signal
if(GetSignal()==ORDER_TYPE_BUY)
return(ORDER_TYPE_BUY);
}
//--- If the position exists
if(pos.exists)
{
//--- Get the position type
GetPositionProperties(P_TYPE);
//--- Get the last deal price
GetPositionProperties(P_PRICE_LAST_DEAL);
//--- Block that checks conditions for the Moving Average and CCI indicators
if(Indicator==MA || Indicator==CCI)
{
//--- A Sell signal
if(pos.type==POSITION_TYPE_BUY &&
GetSignal()==ORDER_TYPE_SELL)
return(ORDER_TYPE_SELL);
//---
if(pos.type==POSITION_TYPE_SELL &&
GetSignal()==ORDER_TYPE_SELL &&
close_price[1]<pos.last_deal_price-CorrectValueBySymbolDigits(VolumeIncre
return(ORDER_TYPE_SELL);
//--- A Buy signal
if(pos.type==POSITION_TYPE_SELL &&
GetSignal()==ORDER_TYPE_BUY)
return(ORDER_TYPE_BUY);
//---
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
if(pos.type==POSITION_TYPE_BUY &&
GetSignal()==ORDER_TYPE_BUY &&
close_price[1]>pos.last_deal_price+CorrectValueBySymbolDigits(VolumeIncre
return(ORDER_TYPE_BUY);
}
//--- Block that checks conditions for the MultiRange_PCH indicator
if(Indicator==PCH)
{
//--- A Sell signal
if(pos.type==POSITION_TYPE_BUY &&
close_price[1]<indicator_buffer2[1] &&
open_price[1]>indicator_buffer2[1])
return(ORDER_TYPE_SELL);
//---
if(pos.type==POSITION_TYPE_SELL &&
close_price[1]<pos.last_deal_price-CorrectValueBySymbolDigits(VolumeIncre
return(ORDER_TYPE_SELL);
//--- A Buy signal
if(pos.type==POSITION_TYPE_SELL &&
close_price[1]>indicator_buffer1[1] &&
open_price[1]<indicator_buffer1[1])
return(ORDER_TYPE_BUY);
//---
if(pos.type==POSITION_TYPE_BUY &&
close_price[1]>pos.last_deal_price+CorrectValueBySymbolDigits(VolumeIncre
return(ORDER_TYPE_BUY);
}
}
//--- No signal
return(WRONG_VALUE);
}
Now, we only need to see into the Instant Execution and Market Execution modes that are part of symbol
properties and to modify the code of the OpenPosition() position opening function accordingly. The modes
whose names are self-explanatory can also be found in MQL5 Reference:
Instant Execution
Market Execution
Please be reminded that when dealing with the Market Execution mode, you cannot open a position with
the set Stop Loss and Take Profit levels: you need to first open a position and then modify it, by setting the
levels.
Starting with build 803, Stop Loss and Take Profit can be set when opening a position for the Market
Execution and Exchange Execution modes.
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
double offset; // Offset from the maximum possible price for
double up_level; // Upper Stop level price
double down_level; // Lower Stop level price
ENUM_SYMBOL_TRADE_EXECUTION execution_mode; // Execution mode
};
//+------------------------------------------------------------------+
//| Opening a position |
//+------------------------------------------------------------------+
void OpenPosition(double lot,
ENUM_ORDER_TYPE order_type,
double price,
double sl,
double tp,
string comment)
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
{
//--- Set the magic number in the trading structure
trade.SetExpertMagicNumber(MagicNumber);
//--- Set the slippage in points
trade.SetDeviationInPoints(CorrectValueBySymbolDigits(Deviation));
//--- The Instant Execution mode
// A position can be opened with the Stop Loss and Take Profit levels set
if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_INSTANT)
{
//--- If the position failed to open, print the relevant message
if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment))
Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(G
}
//--- The Market Execution mode
// First open a position and only then set the Stop Loss and Take Profit levels
// *** Starting with build 803, Stop Loss and Take Profit can be set upon position
if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_MARKET)
{
//--- If there is no position, first open a position and then set Stop Loss and
if(!pos.exists)
{
//--- If the position failed to open, print the relevant message
if(!trade.PositionOpen(_Symbol,order_type,lot,price,0,0,comment))
Print("Error opening the position: ",GetLastError()," - ",ErrorDescription
//--- Get the flag of presence/absence of the position
pos.exists=PositionSelect(_Symbol);
//--- If the position exists
if(pos.exists)
{
//--- Set Stop Loss and Take Profit
if(!trade.PositionModify(_Symbol,sl,tp))
Print("Error modifying the position: ",GetLastError()," - ",ErrorDescr
}
}
//--- If the position exists, increase its volume and leave the Stop Loss and T
else
{
//--- If the position failed to open, print the relevant message
if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment))
Print("Error opening the position: ",GetLastError()," - ",ErrorDescription
}
}
}
We still have to add the final, very important touch to the event handling functions:
OnInit
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- Adjust the input parameters
CorrectInputParameters();
//--- Get indicator handles
GetIndicatorHandle();
//--- Initialize the new bar
CheckNewBar();
//--- Get the properties
GetPositionProperties(P_ALL);
//--- Set the info panel
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
SetInfoPanel();
//---
return(0);
}
OnDeinit
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- Print the deinitialization reason to the journal
Print(GetDeinitReasonText(reason));
//--- When deleting from the chart
if(reason==REASON_REMOVE)
{
//--- Delete all objects relating to the info panel from the chart
DeleteInfoPanel();
//--- Delete the indicator handle
IndicatorRelease(indicator_handle);
}
}
OnTick
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- If the bar is not new, exit
if(!CheckNewBar())
{
if(IsVisualMode() || IsRealtime())
{
//--- Get the properties and update the values on the panel
GetPositionProperties(P_ALL);
//--- Set/update the info panel
SetInfoPanel();
}
return;
}
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
Now that all functions are ready, we can optimize the parameters. Keep in mind that you need to compile
the code from the main program file.
Further, we set the parameters of the Expert Advisor for optimization (see also the attached *.set file with
settings):
The optimization took about 40 minutes on a dual-core processor. The optimization chart allows you to
partly assess the quality of a trading system based on the results in the profit zone:
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
Fig. 3. Optimization chart.
Conclusion
Attached to the article is the downloadable archive with the source codes of the Expert Advisor. Once it is
extracted, you need to place the \TestIndicatorConditions file folder into <Metatrader 5
terminal>\MQL5\Experts. To ensure the correct operation of the Expert Advisor, the MultiRange_PCH
indicator should be downloaded and placed into <Metatrader 5 terminal>\MQL5\Indicators.
Translated from Russian by MetaQuotes Ltd.
Original article: https://www.mql5.com/ru/articles/645
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
testindicatorconditions.set (0.89 KB)
multirange_pch.mq5 (6.31 KB)
Warning: All rights to these materials are reserved by MetaQuotes Ltd. Copying or reprinting of these materials in whole or in part is
but I have difficulties to dowload the Zip file that seems to be corrupted
Sorry
I dont know why but when I try to test the EA with strategy tester, the TP and SL never
appear. They are not set when I do not use the trailing stop.
When using the TrailingStop parameter, the SL appears, but it seems to be a modification and
not an initial setting in the position. (using the trailing stop allow to set a SL whent the
trailing stop is used)
In the same time, when debugging allowing autotrading (on a demo account) , the SL and TP
are immediately set (when the position is first set on TradingBlock(); and it is not necessary
to wait to ModifyTrailingStop() function to see the SL and TP)
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
In these condition, it is difficult to evaluate how the EA works when SL and TP are set.
M.
MQL5 Cookbook: Developing a Framework for a Trading System Based on the Triple
Screen Strategy
In this article, we will develop a framework for a trading system based on the Triple Screen strategy
in MQL5. The Expert Advisor will not be developed from scratch. Instead, we will simply modify the
program from the previous article "MQL5 Cookbook: Using Indicators to Set Trading Conditions in
Expert Advisors" which already substantially serves our purpose. So the article will also demonstrate
how you can easily modify patterns of ready-made programs.
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF